From fcdc8e35ef7b8cd465e8e45805cab14aa1a782bf Mon Sep 17 00:00:00 2001 From: michidabedi Date: Wed, 16 Sep 2026 18:49:28 +0200 Subject: [PATCH] Add Electron desktop edition with redesigned Liquid Glass UI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert Windows Memory Cleaner into an Electron desktop app while keeping all native logic intact. Architecture: - engine/ : headless C# engine (net10-windows) that performs the kernel-level memory optimizations (ported 1:1 from ComputerService), reports RAM stats/OS capabilities, lists processes, and persists settings to the SAME HKLM\SOFTWARE\WinMemoryCleaner registry keys (data preserved). Speaks newline-delimited JSON over stdio; runs elevated. - main/ : Electron main process — frameless window, tray, global optimize hotkey, auto-optimization scheduler (interval + low-memory threshold), notifications, run-on-startup, engine spawn + protocol bridge. - preload/ : minimal contextBridge API (contextIsolation on, nodeIntegration off). - renderer/: redesigned "Liquid Glass" UI (aurora background, glass panels, radial gauges, live sparkline, dark/light themes). The original WPF app under src/ is untouched. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01NgB5SQs1gWMRze8Xo1ioo5 --- electron/.gitignore | 11 + electron/README.md | 87 + electron/build/icon.ico | Bin 0 -> 35856 bytes electron/engine/MemoryInfo.cs | 118 + electron/engine/Native.cs | 182 + electron/engine/Optimizer.cs | 415 ++ electron/engine/Program.cs | 320 + electron/engine/SettingsStore.cs | 167 + .../engine/WinMemoryCleaner.Engine.csproj | 19 + electron/engine/app.manifest | 22 + electron/main/engine.js | 167 + electron/main/main.js | 342 ++ electron/package-lock.json | 5288 +++++++++++++++++ electron/package.json | 39 + electron/preload/preload.js | 44 + electron/renderer/index.html | 306 + electron/renderer/js/app.js | 504 ++ electron/renderer/styles/app.css | 376 ++ 18 files changed, 8407 insertions(+) create mode 100644 electron/.gitignore create mode 100644 electron/README.md create mode 100644 electron/build/icon.ico create mode 100644 electron/engine/MemoryInfo.cs create mode 100644 electron/engine/Native.cs create mode 100644 electron/engine/Optimizer.cs create mode 100644 electron/engine/Program.cs create mode 100644 electron/engine/SettingsStore.cs create mode 100644 electron/engine/WinMemoryCleaner.Engine.csproj create mode 100644 electron/engine/app.manifest create mode 100644 electron/main/engine.js create mode 100644 electron/main/main.js create mode 100644 electron/package-lock.json create mode 100644 electron/package.json create mode 100644 electron/preload/preload.js create mode 100644 electron/renderer/index.html create mode 100644 electron/renderer/js/app.js create mode 100644 electron/renderer/styles/app.css diff --git a/electron/.gitignore b/electron/.gitignore new file mode 100644 index 00000000..044f5c12 --- /dev/null +++ b/electron/.gitignore @@ -0,0 +1,11 @@ +# Node / Electron +node_modules/ +dist/ +out/ + +# .NET engine build output +engine/bin/ +engine/obj/ + +# Screenshots / scratch +build/screenshot-*.png diff --git a/electron/README.md b/electron/README.md new file mode 100644 index 00000000..222645c6 --- /dev/null +++ b/electron/README.md @@ -0,0 +1,87 @@ +# Windows Memory Cleaner — Electron edition + +A modern **Electron** desktop front-end for [WinMemoryCleaner](https://github.com/IgorMundstein/WinMemoryCleaner), +with a redesigned "Liquid Glass" interface. All the original kernel-level memory work is +**preserved unchanged** — it runs in a native C# helper process that Electron drives over a +JSON protocol. + +## Why this architecture + +WinMemoryCleaner's core is not web code: it calls Windows kernel APIs via P/Invoke +(`EmptyWorkingSet`, `NtSetSystemInformation`, `SetSystemFileCacheSize`, `DeviceIoControl`, …), +which Node.js/Chromium cannot do. So the app is split cleanly: + +``` +┌─────────────────────────────┐ newline-delimited JSON over stdio ┌──────────────────────────┐ +│ Electron (renderer + main) │ ───────────────────────────────────▶ │ wmc-engine.exe (C#) │ +│ UI · tray · hotkey · sched │ ◀─────────────────────────────────── │ P/Invoke · admin │ +└─────────────────────────────┘ requests / events └───────────┬──────────────┘ + │ + Windows kernel APIs +``` + +| Layer | Path | Responsibility | +|-------|------|----------------| +| **Engine** | `engine/` | Memory stats, OS capability detection, the 8 optimization routines (ported 1:1 from `ComputerService`), process list, and settings persistence to the **original** `HKLM\SOFTWARE\WinMemoryCleaner` registry keys. | +| **Main** | `main/main.js`, `main/engine.js` | Window lifecycle, tray, global optimize hotkey, auto-optimization scheduler (interval + low-memory threshold), notifications, run-on-startup, engine spawn + protocol. | +| **Preload** | `preload/preload.js` | The only bridge to the renderer — a minimal `window.wmc` API via `contextBridge`. `contextIsolation` on, `nodeIntegration` off. | +| **Renderer** | `renderer/` | The redesigned UI (vanilla HTML/CSS/JS, no bundler). | + +### Data compatibility +The engine reads and writes the **same registry location** the original app uses, so any +existing configuration (memory areas, language, auto-optimization, exclusions) carries over +untouched. + +## Requirements +- Windows 10/11 +- [.NET SDK 8+](https://dotnet.microsoft.com/) (built and tested with SDK 10) +- [Node.js 18+](https://nodejs.org/) + +## Develop / run + +```sh +cd electron +npm install +npm run build:engine # compiles wmc-engine (dotnet) +npm start # launches Electron +``` + +The engine binary is manifested `requireAdministrator`, so **full optimization requires the +app to run elevated** (right-click → Run as administrator, or launch from an elevated shell). +For convenience during development, if the app is not elevated the bridge automatically falls +back to launching the engine via `dotnet ` (which bypasses the manifest). In that mode the +UI, live memory and settings all work; the privileged optimizations simply report a per-area +error instead of succeeding — exactly like the original app when not elevated. + +Force the dotnet fallback explicitly: + +```sh +WMC_ENGINE_VIA_DOTNET=1 npm start +``` + +## Package + +```sh +npm run build:engine +npm run dist # electron-builder → NSIS installer, requestedExecutionLevel=requireAdministrator +``` + +`electron-builder` bundles the compiled engine from `engine/bin/Release/net10.0-windows` +into the installer's `resources/engine` folder. + +## JSON protocol (engine) + +Requests are newline-delimited JSON on stdin; responses/events on stdout. + +| Command | Args | Result | +|---------|------|--------| +| `ping` | – | `{ pong, version, elevated }` | +| `getState` | – | `{ memory, os, settings, elevated }` | +| `getMemory` | – | `{ physical, virtual }` (bytes + percentages) | +| `getProcesses` | – | `string[]` of process names | +| `getSettings` / `saveSettings` | (settings) | reads/writes the original registry keys | +| `setPriority` | `{ priority: "low"\|"normal" }` | sets the engine process priority | +| `optimize` | `{ areas:int, processExclusion:[], reason }` | streams `optimizeStart`/`progress` events, returns `{ before, after, released, results[] }` | + +## License +GPL-3.0, same as the original project. diff --git a/electron/build/icon.ico b/electron/build/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..56bcad93a2aa10e9ac9ef374aaa65ba0cfd2fa62 GIT binary patch literal 35856 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 TW=Oq4@Xsy-Q~g{$+PVJ^!027K literal 0 HcmV?d00001 diff --git a/electron/engine/MemoryInfo.cs b/electron/engine/MemoryInfo.cs new file mode 100644 index 00000000..5c271c86 --- /dev/null +++ b/electron/engine/MemoryInfo.cs @@ -0,0 +1,118 @@ +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; + +namespace WinMemoryCleaner.Engine +{ + /// + /// Memory areas (bit flags). Values match the original Enums.Memory.Areas exactly, + /// so persisted settings remain compatible. + /// + [Flags] + internal enum MemoryAreas + { + None = 0, + CombinedPageList = 1, + ModifiedFileCache = 2, + ModifiedPageList = 4, + RegistryCache = 8, + StandbyList = 16, + StandbyListLowPriority = 32, + SystemFileCache = 64, + WorkingSet = 128 + } + + internal enum OptimizationReason + { + LowMemory, + Manual, + Schedule + } + + /// + /// Operating-system capability detection, ported from the original ComputerService/OperatingSystem. + /// + [SupportedOSPlatform("windows")] + internal sealed class OsInfo + { + public bool Is64Bit { get; } + public bool IsWindowsXpOrGreater { get; } + public bool IsWindowsVistaOrGreater { get; } + public bool IsWindows7OrGreater { get; } + public bool IsWindows8OrGreater { get; } + public bool IsWindows81OrGreater { get; } + + public bool HasWorkingSet => IsWindowsXpOrGreater; + public bool HasSystemFileCache => IsWindowsXpOrGreater; + public bool HasModifiedFileCache => IsWindowsXpOrGreater; + public bool HasModifiedPageList => IsWindowsVistaOrGreater; + public bool HasStandbyList => IsWindowsVistaOrGreater; + public bool HasCombinedPageList => IsWindows8OrGreater; + public bool HasRegistryHive => IsWindows81OrGreater; + + public OsInfo() + { + var v = Environment.OSVersion.Version; + Is64Bit = Environment.Is64BitOperatingSystem; + IsWindowsXpOrGreater = v.Major >= 5.1; + IsWindowsVistaOrGreater = v.Major >= 6; + IsWindows7OrGreater = (v.Major > 6) || (v.Major == 6 && v.Minor >= 1); + IsWindows8OrGreater = v.Major >= 6.2; + IsWindows81OrGreater = v.Major >= 6.3; + } + + /// Which areas the OS supports, as a bit mask. + public MemoryAreas SupportedAreas + { + get + { + var a = MemoryAreas.None; + if (HasWorkingSet) a |= MemoryAreas.WorkingSet; + if (HasSystemFileCache) a |= MemoryAreas.SystemFileCache; + if (HasModifiedFileCache) a |= MemoryAreas.ModifiedFileCache; + if (HasModifiedPageList) a |= MemoryAreas.ModifiedPageList; + if (HasStandbyList) a |= MemoryAreas.StandbyList | MemoryAreas.StandbyListLowPriority; + if (HasCombinedPageList) a |= MemoryAreas.CombinedPageList; + if (HasRegistryHive) a |= MemoryAreas.RegistryCache; + return a; + } + } + } + + /// Point-in-time RAM snapshot from GlobalMemoryStatusEx. + [SupportedOSPlatform("windows")] + internal readonly struct MemorySnapshot + { + public long PhysicalTotal { get; } + public long PhysicalFree { get; } + public long PhysicalUsed { get; } + public int PhysicalUsedPercent { get; } + + public long VirtualTotal { get; } + public long VirtualFree { get; } + public long VirtualUsed { get; } + public int VirtualUsedPercent { get; } + + private MemorySnapshot(Structs.Windows.MemoryStatusEx m) + { + PhysicalTotal = m.TotalPhys; + PhysicalFree = m.AvailPhys; + PhysicalUsed = m.TotalPhys >= m.AvailPhys ? m.TotalPhys - m.AvailPhys : 0; + PhysicalUsedPercent = m.MemoryLoad; + + VirtualTotal = m.TotalPageFile; + VirtualFree = m.AvailPageFile; + VirtualUsed = m.TotalPageFile >= m.AvailPageFile ? m.TotalPageFile - m.AvailPageFile : 0; + VirtualUsedPercent = m.TotalPageFile > 0 ? (int)(VirtualUsed * 100 / m.TotalPageFile) : 0; + } + + public static MemorySnapshot Read() + { + var m = new Structs.Windows.MemoryStatusEx(); + if (!NativeMethods.GlobalMemoryStatusEx(m)) + throw new Win32Exception(Marshal.GetLastWin32Error()); + return new MemorySnapshot(m); + } + } +} diff --git a/electron/engine/Native.cs b/electron/engine/Native.cs new file mode 100644 index 00000000..0334daad --- /dev/null +++ b/electron/engine/Native.cs @@ -0,0 +1,182 @@ +using Microsoft.Win32.SafeHandles; +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; +using System.Security; + +namespace WinMemoryCleaner.Engine +{ + /// + /// Windows API. Ported verbatim (signatures unchanged) from the original + /// WinMemoryCleaner Interop/NativeMethods.cs so the optimization behavior is identical. + /// + [SupportedOSPlatform("windows")] + internal static class NativeMethods + { + [DllImport("advapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool AdjustTokenPrivileges(IntPtr tokenHandle, [MarshalAs(UnmanagedType.Bool)] bool disableAllPrivileges, ref Structs.Windows.TokenPrivileges newState, int bufferLength, IntPtr previousState, IntPtr returnLength); + + [SuppressUnmanagedCodeSecurity] + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] + internal static extern SafeFileHandle CreateFile([MarshalAs(UnmanagedType.LPWStr)] string lpFileName, FileAccess dwDesiredAccess, FileShare dwShareMode, IntPtr lpSecurityAttributes, FileMode dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile); + + [SuppressUnmanagedCodeSecurity] + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool DeviceIoControl(SafeFileHandle hDevice, int dwIoControlCode, IntPtr lpInBuffer, int nInBufferSize, IntPtr lpOutBuffer, int nOutBufferSize, out int lpBytesReturned, IntPtr lpOverlapped); + + [SuppressUnmanagedCodeSecurity] + [DllImport("psapi.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool EmptyWorkingSet(IntPtr hProcess); + + [SuppressUnmanagedCodeSecurity] + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool FlushFileBuffers(SafeFileHandle hFile); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool GlobalMemoryStatusEx([In, Out] Structs.Windows.MemoryStatusEx lpBuffer); + + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, ref long lpLuid); + + [SuppressUnmanagedCodeSecurity] + [DllImport("ntdll.dll", SetLastError = true)] + internal static extern int NtSetSystemInformation(int SystemInformationClass, IntPtr SystemInformation, uint SystemInformationLength); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool SetSystemFileCacheSize(IntPtr minimumFileCacheSize, IntPtr maximumFileCacheSize, int flags); + } + + /// + /// Structs. Ported verbatim from the original Core/Structs.cs. + /// + internal static class Structs + { + internal static class Windows + { + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct MemoryCombineInformationEx + { + public IntPtr Handle; + public IntPtr PagesCombined; + public long Flags; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + public class MemoryStatusEx + { + public readonly int Length; + public int MemoryLoad; + public long TotalPhys; + public long AvailPhys; + public long TotalPageFile; + public long AvailPageFile; + public long TotalVirtual; + public long AvailVirtual; + public long AvailExtendedVirtual; + + public MemoryStatusEx() + { + Length = Marshal.SizeOf(typeof(MemoryStatusEx)); + } + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct SystemFileCacheInformation32 + { + public int CurrentSize; + public int PeakSize; + public int PageFaultCount; + public int MinimumWorkingSet; + public int MaximumWorkingSet; + public int CurrentSizeIncludingTransitionInPages; + public int PeakSizeIncludingTransitionInPages; + public int TransitionRePurposeCount; + public int Flags; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct SystemFileCacheInformation64 + { + public long CurrentSize; + public long PeakSize; + public long PageFaultCount; + public long MinimumWorkingSet; + public long MaximumWorkingSet; + public long CurrentSizeIncludingTransitionInPages; + public long PeakSizeIncludingTransitionInPages; + public long TransitionRePurposeCount; + public long Flags; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct TokenPrivileges + { + public int Count; + public long Luid; + public int Attr; + } + } + } + + /// + /// Windows-specific constants. Ported verbatim from the original Core/Constants.cs (Windows section). + /// + internal static class Constants + { + internal static class Windows + { + internal static class Drive + { + public const int FsctlDiscardVolumeCache = 589828; // FSCTL_DISCARD_VOLUME_CACHE + public const int IoControlResetWriteOrder = 589832; // FSCTL_RESET_WRITE_ORDER + } + + internal static class File + { + public const int FlagsNoBuffering = 536870912; // FILE_FLAG_NO_BUFFERING + } + + internal static class Privilege + { + public const string SeDebugName = "SeDebugPrivilege"; + public const string SeIncreaseQuotaName = "SeIncreaseQuotaPrivilege"; + public const string SeProfSingleProcessName = "SeProfileSingleProcessPrivilege"; + } + + internal static class PrivilegeAttribute + { + public const int Enabled = 2; + } + + internal static class SystemErrorCode + { + public const int ErrorAccessDenied = 5; + public const int ErrorSuccess = 0; + } + + internal static class SystemInformationClass + { + public const int SystemCombinePhysicalMemoryInformation = 130; + public const int SystemFileCacheInformation = 21; + public const int SystemMemoryListInformation = 80; + public const int SystemRegistryReconciliationInformation = 155; + } + + internal static class SystemMemoryListCommand + { + public const int MemoryEmptyWorkingSets = 2; + public const int MemoryFlushModifiedList = 3; + public const int MemoryPurgeLowPriorityStandbyList = 5; + public const int MemoryPurgeStandbyList = 4; + } + } + } +} diff --git a/electron/engine/Optimizer.cs b/electron/engine/Optimizer.cs new file mode 100644 index 00000000..18d3f0da --- /dev/null +++ b/electron/engine/Optimizer.cs @@ -0,0 +1,415 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; +using System.Security.Principal; +using System.Text; + +namespace WinMemoryCleaner.Engine +{ + /// Result of an optimization run for a single memory area. + internal sealed class AreaResult + { + public string Name { get; set; } + public double DurationSeconds { get; set; } + public string Error { get; set; } + public bool Success => string.IsNullOrEmpty(Error); + } + + /// + /// Faithful port of the memory-optimization logic from the original + /// Service/ComputerService.cs. The native call sequences are unchanged; only the + /// presentation (progress reporting, logging) is decoupled from WPF. + /// + [SupportedOSPlatform("windows")] + internal sealed class Optimizer + { + private readonly OsInfo _os; + private readonly IReadOnlyCollection _processExclusionList; + + /// Raised as each area begins: (stepIndex, areaName). + public event Action OnProgress; + + public Optimizer(OsInfo os, IEnumerable processExclusionList) + { + _os = os; + _processExclusionList = new HashSet( + processExclusionList ?? Enumerable.Empty(), + StringComparer.OrdinalIgnoreCase); + } + + public IReadOnlyList Optimize(MemoryAreas areas) + { + var results = new List(); + if (areas == MemoryAreas.None) + return results; + + var step = 0; + var sw = new Stopwatch(); + + void Run(string name, Action action) + { + OnProgress?.Invoke(++step, name); + sw.Restart(); + var result = new AreaResult { Name = name }; + try + { + action(); + } + catch (Exception e) + { + result.Error = GetMessage(e); + } + finally + { + result.DurationSeconds = sw.Elapsed.TotalSeconds; + results.Add(result); + } + } + + // Order preserved from the original ComputerService.Optimize. + if ((areas & MemoryAreas.WorkingSet) != 0) + Run("Working Set", OptimizeWorkingSet); + + if ((areas & MemoryAreas.SystemFileCache) != 0) + Run("System File Cache", OptimizeSystemFileCache); + + if ((areas & MemoryAreas.ModifiedPageList) != 0) + Run("Modified Page List", OptimizeModifiedPageList); + + if ((areas & (MemoryAreas.StandbyList | MemoryAreas.StandbyListLowPriority)) != 0) + { + var lowPriority = (areas & MemoryAreas.StandbyListLowPriority) != 0; + Run(lowPriority ? "Standby List (low priority)" : "Standby List", + () => OptimizeStandbyList(lowPriority)); + } + + if ((areas & MemoryAreas.CombinedPageList) != 0) + Run("Combined Page List", OptimizeCombinedPageList); + + if ((areas & MemoryAreas.RegistryCache) != 0) + Run("Registry Cache", OptimizeRegistryCache); + + if ((areas & MemoryAreas.ModifiedFileCache) != 0) + Run("Modified File Cache", OptimizeModifiedFileCache); + + // Garbage Collector step (mirrors App.ReleaseMemory in the original). + OnProgress?.Invoke(++step, "Garbage Collector"); + try + { + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.Collect(); + } + catch { /* ignored */ } + + return results; + } + + #region Privilege / volume helpers (ported verbatim) + + private static Microsoft.Win32.SafeHandles.SafeFileHandle OpenVolumeHandle(string driveLetter) + { + if (string.IsNullOrWhiteSpace(driveLetter)) + return null; + + return NativeMethods.CreateFile( + @"\\.\" + driveLetter.TrimEnd(':', '\\') + ":", + FileAccess.ReadWrite, + FileShare.Read | FileShare.Write, + IntPtr.Zero, + FileMode.Open, + (int)FileAttributes.Normal | Constants.Windows.File.FlagsNoBuffering, + IntPtr.Zero); + } + + private static bool SetIncreasePrivilege(string privilegeName) + { + var result = false; + + using (var current = WindowsIdentity.GetCurrent(TokenAccessLevels.Query | TokenAccessLevels.AdjustPrivileges)) + { + Structs.Windows.TokenPrivileges newState; + newState.Count = 1; + newState.Luid = 0L; + newState.Attr = Constants.Windows.PrivilegeAttribute.Enabled; + + if (NativeMethods.LookupPrivilegeValue(null, privilegeName, ref newState.Luid)) + result = NativeMethods.AdjustTokenPrivileges(current.Token, false, ref newState, 0, IntPtr.Zero, IntPtr.Zero); + } + + return result; + } + + #endregion + + #region Area routines (ported verbatim from ComputerService) + + private void OptimizeCombinedPageList() + { + if (!_os.HasCombinedPageList) + throw new Exception("Combined Page List optimization is not supported on this operating system."); + + if (!SetIncreasePrivilege(Constants.Windows.Privilege.SeProfSingleProcessName)) + throw new Exception("Administrator privilege required: " + Constants.Windows.Privilege.SeProfSingleProcessName); + + var handle = GCHandle.Alloc(0); + try + { + var info = new Structs.Windows.MemoryCombineInformationEx(); + handle = GCHandle.Alloc(info, GCHandleType.Pinned); + + if (NativeMethods.NtSetSystemInformation( + Constants.Windows.SystemInformationClass.SystemCombinePhysicalMemoryInformation, + handle.AddrOfPinnedObject(), + (uint)Marshal.SizeOf(info)) != Constants.Windows.SystemErrorCode.ErrorSuccess) + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + finally + { + FreeHandle(ref handle); + } + } + + private void OptimizeModifiedFileCache() + { + if (!_os.HasModifiedFileCache) + throw new Exception("Modified File Cache optimization is not supported on this operating system."); + + foreach (var drive in DriveInfo.GetDrives()) + { + if (drive == null || drive.DriveType != DriveType.Fixed || string.IsNullOrWhiteSpace(drive.Name)) + continue; + + using (var handle = OpenVolumeHandle(drive.Name)) + { + if (handle == null || handle.IsInvalid) + continue; + + int bytesReturned; + + if (_os.IsWindows7OrGreater) + { + try + { + var buffer = Marshal.AllocHGlobal(1); + try + { + if (!NativeMethods.DeviceIoControl(handle, Constants.Windows.Drive.IoControlResetWriteOrder, + buffer, 1, IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero)) + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + finally + { + Marshal.FreeHGlobal(buffer); + } + } + catch { /* ignored */ } + + if (_os.IsWindows8OrGreater) + { + try + { + if (!NativeMethods.DeviceIoControl(handle, Constants.Windows.Drive.FsctlDiscardVolumeCache, + IntPtr.Zero, 0, IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero)) + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + catch { /* ignored */ } + } + } + + if (!NativeMethods.FlushFileBuffers(handle)) + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + } + } + + private void OptimizeModifiedPageList() + { + if (!_os.HasModifiedPageList) + throw new Exception("Modified Page List optimization is not supported on this operating system."); + + if (!SetIncreasePrivilege(Constants.Windows.Privilege.SeProfSingleProcessName)) + throw new Exception("Administrator privilege required: " + Constants.Windows.Privilege.SeProfSingleProcessName); + + var handle = GCHandle.Alloc(Constants.Windows.SystemMemoryListCommand.MemoryFlushModifiedList, GCHandleType.Pinned); + try + { + if (NativeMethods.NtSetSystemInformation( + Constants.Windows.SystemInformationClass.SystemMemoryListInformation, + handle.AddrOfPinnedObject(), + (uint)Marshal.SizeOf(Constants.Windows.SystemMemoryListCommand.MemoryFlushModifiedList)) != Constants.Windows.SystemErrorCode.ErrorSuccess) + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + finally + { + FreeHandle(ref handle); + } + } + + private void OptimizeRegistryCache() + { + if (!_os.HasRegistryHive) + throw new Exception("Registry Cache optimization is not supported on this operating system."); + + if (NativeMethods.NtSetSystemInformation( + Constants.Windows.SystemInformationClass.SystemRegistryReconciliationInformation, + IntPtr.Zero, 0) != Constants.Windows.SystemErrorCode.ErrorSuccess) + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + + private void OptimizeStandbyList(bool lowPriority = false) + { + if (!_os.HasStandbyList) + throw new Exception("Standby List optimization is not supported on this operating system."); + + if (!SetIncreasePrivilege(Constants.Windows.Privilege.SeProfSingleProcessName)) + throw new Exception("Administrator privilege required: " + Constants.Windows.Privilege.SeProfSingleProcessName); + + object command = lowPriority + ? Constants.Windows.SystemMemoryListCommand.MemoryPurgeLowPriorityStandbyList + : Constants.Windows.SystemMemoryListCommand.MemoryPurgeStandbyList; + + var handle = GCHandle.Alloc(command, GCHandleType.Pinned); + try + { + if (NativeMethods.NtSetSystemInformation( + Constants.Windows.SystemInformationClass.SystemMemoryListInformation, + handle.AddrOfPinnedObject(), + (uint)Marshal.SizeOf(command)) != Constants.Windows.SystemErrorCode.ErrorSuccess) + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + finally + { + FreeHandle(ref handle); + } + } + + private void OptimizeSystemFileCache() + { + if (!_os.HasSystemFileCache) + throw new Exception("System File Cache optimization is not supported on this operating system."); + + if (!SetIncreasePrivilege(Constants.Windows.Privilege.SeIncreaseQuotaName)) + throw new Exception("Administrator privilege required: " + Constants.Windows.Privilege.SeIncreaseQuotaName); + + var handle = GCHandle.Alloc(0); + try + { + object info; + if (_os.Is64Bit) + info = new Structs.Windows.SystemFileCacheInformation64 { MinimumWorkingSet = -1L, MaximumWorkingSet = -1L }; + else + info = new Structs.Windows.SystemFileCacheInformation32 { MinimumWorkingSet = int.MaxValue, MaximumWorkingSet = int.MaxValue }; + + handle = GCHandle.Alloc(info, GCHandleType.Pinned); + + if (NativeMethods.NtSetSystemInformation( + Constants.Windows.SystemInformationClass.SystemFileCacheInformation, + handle.AddrOfPinnedObject(), + (uint)Marshal.SizeOf(info)) != Constants.Windows.SystemErrorCode.ErrorSuccess) + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + finally + { + FreeHandle(ref handle); + } + + var fileCacheSize = IntPtr.Subtract(IntPtr.Zero, 1); // Flush + if (!NativeMethods.SetSystemFileCacheSize(fileCacheSize, fileCacheSize, 0)) + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + + private void OptimizeWorkingSet() + { + if (!_os.HasWorkingSet) + throw new Exception("Working Set optimization is not supported on this operating system."); + + var errors = new StringBuilder(); + + if (_processExclusionList.Count > 0) + { + if (!SetIncreasePrivilege(Constants.Windows.Privilege.SeDebugName)) + throw new Exception("Administrator privilege required: " + Constants.Windows.Privilege.SeDebugName); + + var processes = Process.GetProcesses() + .Where(p => p != null && !_processExclusionList.Contains(p.ProcessName)); + + foreach (var process in processes) + { + using (process) + { + try + { + if (!NativeMethods.EmptyWorkingSet(process.Handle)) + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + catch (InvalidOperationException) { /* ignored */ } + catch (Win32Exception e) + { + if (e.NativeErrorCode != Constants.Windows.SystemErrorCode.ErrorAccessDenied) + errors.Append(process.ProcessName + ": " + GetMessage(e) + " | "); + } + } + } + + if (errors.Length > 3) + errors.Remove(errors.Length - 3, 3); + } + else + { + if (!SetIncreasePrivilege(Constants.Windows.Privilege.SeProfSingleProcessName)) + throw new Exception("Administrator privilege required: " + Constants.Windows.Privilege.SeProfSingleProcessName); + + var handle = GCHandle.Alloc(Constants.Windows.SystemMemoryListCommand.MemoryEmptyWorkingSets, GCHandleType.Pinned); + try + { + if (NativeMethods.NtSetSystemInformation( + Constants.Windows.SystemInformationClass.SystemMemoryListInformation, + handle.AddrOfPinnedObject(), + (uint)Marshal.SizeOf(Constants.Windows.SystemMemoryListCommand.MemoryEmptyWorkingSets)) != Constants.Windows.SystemErrorCode.ErrorSuccess) + { + var e = new Win32Exception(Marshal.GetLastWin32Error()); + if (errors.Length > 0) errors.Append(" | "); + errors.Append(GetMessage(e)); + } + } + finally + { + FreeHandle(ref handle); + } + } + + if (errors.Length > 0) + throw new Exception(errors.ToString()); + } + + #endregion + + private static void FreeHandle(ref GCHandle handle) + { + try + { + if (handle.IsAllocated) + handle.Free(); + } + catch (InvalidOperationException) { /* ignored */ } + } + + internal static string GetMessage(Exception e) + { + var message = e?.Message ?? string.Empty; + var inner = e?.InnerException; + while (inner != null) + { + message += " " + inner.Message; + inner = inner.InnerException; + } + return message.Trim(); + } + } +} diff --git a/electron/engine/Program.cs b/electron/engine/Program.cs new file mode 100644 index 00000000..5e0223ae --- /dev/null +++ b/electron/engine/Program.cs @@ -0,0 +1,320 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.Versioning; +using System.Security.Principal; +using System.Text; +using System.Text.Json; +using System.Text.Json.Nodes; +using System.Threading; +using System.Threading.Tasks; + +namespace WinMemoryCleaner.Engine +{ + /// + /// Headless memory-cleaning engine. Speaks a newline-delimited JSON protocol over + /// stdin/stdout so the Electron front-end (or any host) can drive it. + /// + /// Request : {"id":1,"cmd":"optimize","args":{...}}\n + /// Response: {"id":1,"ok":true,"result":{...}}\n + /// Event : {"type":"event","id":1,"event":"progress","data":{...}}\n + /// + [SupportedOSPlatform("windows")] + internal static class Program + { + private const string Version = "1.0.0"; + + private static readonly object _stdoutLock = new(); + private static readonly SemaphoreSlim _optimizeGate = new(1, 1); + private static readonly OsInfo _os = new(); + + private static int Main(string[] args) + { + // Force invariant, UTF-8, no buffering surprises. + var stdout = new StreamWriter(Console.OpenStandardOutput(), new UTF8Encoding(false)) { AutoFlush = true }; + Console.SetOut(stdout); + + // Announce readiness so the host knows the pipe is live. + Emit(new JsonObject + { + ["type"] = "ready", + ["version"] = Version, + ["elevated"] = IsElevated(), + ["pid"] = Environment.ProcessId + }); + + using var stdin = new StreamReader(Console.OpenStandardInput(), Encoding.UTF8); + var inFlight = new List(); + string line; + while ((line = stdin.ReadLine()) != null) + { + if (string.IsNullOrWhiteSpace(line)) + continue; + + // Dispatch each request independently so cheap reads aren't blocked by a long optimize. + var captured = line; + lock (inFlight) + { + inFlight.RemoveAll(t => t.IsCompleted); + inFlight.Add(Task.Run(() => Dispatch(captured))); + } + } + + // stdin closed: drain outstanding requests before exiting so no response is lost. + Task[] pending; + lock (inFlight) { pending = inFlight.ToArray(); } + try { Task.WaitAll(pending, TimeSpan.FromSeconds(30)); } catch { /* ignored */ } + + return 0; + } + + private static void Dispatch(string line) + { + JsonNode request; + try + { + request = JsonNode.Parse(line); + } + catch (Exception e) + { + Emit(new JsonObject { ["ok"] = false, ["error"] = "Invalid JSON: " + e.Message }); + return; + } + + var id = request?["id"]?.GetValue() ?? 0; + var cmd = request?["cmd"]?.ToString(); + var argsNode = request?["args"] as JsonObject ?? new JsonObject(); + + try + { + JsonNode result = cmd switch + { + "ping" => Ping(), + "getState" => GetState(), + "getMemory" => MemoryToJson(MemorySnapshot.Read()), + "getProcesses" => GetProcesses(), + "getSettings" => SettingsStore.Read(), + "saveSettings" => SaveSettings(argsNode), + "setPriority" => SetPriority(argsNode), + "optimize" => Optimize(id, argsNode), + _ => throw new Exception("Unknown command: " + cmd) + }; + + Respond(id, result); + } + catch (Exception e) + { + Emit(new JsonObject { ["id"] = id, ["ok"] = false, ["error"] = Optimizer.GetMessage(e) }); + } + } + + #region Commands + + private static JsonObject Ping() => new() + { + ["pong"] = true, + ["version"] = Version, + ["elevated"] = IsElevated() + }; + + private static JsonObject GetState() => new() + { + ["memory"] = MemoryToJson(MemorySnapshot.Read()), + ["os"] = OsToJson(), + ["settings"] = SettingsStore.Read(), + ["elevated"] = IsElevated() + }; + + private static JsonObject SaveSettings(JsonObject args) + { + SettingsStore.Write(args); + return new JsonObject { ["saved"] = true }; + } + + private static JsonObject SetPriority(JsonObject args) + { + var priority = args["priority"]?.ToString()?.ToLowerInvariant(); + try + { + using var self = Process.GetCurrentProcess(); + self.PriorityClass = priority == "normal" + ? ProcessPriorityClass.Normal + : ProcessPriorityClass.Idle; // "low" + } + catch { /* best effort */ } + return new JsonObject { ["priority"] = priority }; + } + + private static JsonArray GetProcesses() + { + var names = Process.GetProcesses() + .Where(p => p != null) + .Select(p => + { + try { return p.ProcessName; } catch { return null; } + finally { try { p.Dispose(); } catch { } } + }) + .Where(n => !string.IsNullOrWhiteSpace(n) && + !n.Equals("wmc-engine", StringComparison.OrdinalIgnoreCase)) + .Select(n => n.ToLowerInvariant().Replace(".exe", string.Empty)) + .Distinct(StringComparer.OrdinalIgnoreCase) + .OrderBy(n => n, StringComparer.OrdinalIgnoreCase); + + var array = new JsonArray(); + foreach (var n in names) array.Add(n); + return array; + } + + private static JsonObject Optimize(int id, JsonObject args) + { + var areas = (MemoryAreas)(args["areas"]?.GetValue() ?? 0); + // Never attempt an area the OS doesn't support. + areas &= _os.SupportedAreas; + + var exclusions = (args["processExclusion"] as JsonArray)? + .Select(n => n?.ToString()) + .Where(n => !string.IsNullOrWhiteSpace(n)) + .ToList() ?? new List(); + + var reason = args["reason"]?.ToString() ?? "Manual"; + + // Only one optimization at a time. + _optimizeGate.Wait(); + try + { + var before = MemorySnapshot.Read(); + + var totalSteps = CountBits((int)areas) + 1; // +1 for the GC step + Emit(new JsonObject + { + ["type"] = "event", + ["id"] = id, + ["event"] = "optimizeStart", + ["data"] = new JsonObject { ["total"] = totalSteps, ["reason"] = reason } + }); + + var optimizer = new Optimizer(_os, exclusions); + optimizer.OnProgress += (step, name) => Emit(new JsonObject + { + ["type"] = "event", + ["id"] = id, + ["event"] = "progress", + ["data"] = new JsonObject + { + ["step"] = step, + ["total"] = totalSteps, + ["percent"] = (int)(step * 100.0 / totalSteps), + ["name"] = name + } + }); + + var results = optimizer.Optimize(areas); + var after = MemorySnapshot.Read(); + + var resultArray = new JsonArray(); + foreach (var r in results) + { + resultArray.Add(new JsonObject + { + ["name"] = r.Name, + ["durationSeconds"] = Math.Round(r.DurationSeconds, 2), + ["success"] = r.Success, + ["error"] = r.Error + }); + } + + return new JsonObject + { + ["reason"] = reason, + ["areas"] = (int)areas, + ["before"] = MemoryToJson(before), + ["after"] = MemoryToJson(after), + ["released"] = new JsonObject + { + ["physical"] = Math.Max(0, after.PhysicalFree - before.PhysicalFree), + ["virtual"] = Math.Max(0, after.VirtualFree - before.VirtualFree) + }, + ["results"] = resultArray + }; + } + finally + { + _optimizeGate.Release(); + } + } + + #endregion + + #region JSON helpers + + private static JsonObject MemoryToJson(MemorySnapshot m) => new() + { + ["physical"] = new JsonObject + { + ["total"] = m.PhysicalTotal, + ["free"] = m.PhysicalFree, + ["used"] = m.PhysicalUsed, + ["usedPercent"] = m.PhysicalUsedPercent, + ["freePercent"] = 100 - m.PhysicalUsedPercent + }, + ["virtual"] = new JsonObject + { + ["total"] = m.VirtualTotal, + ["free"] = m.VirtualFree, + ["used"] = m.VirtualUsed, + ["usedPercent"] = m.VirtualUsedPercent, + ["freePercent"] = 100 - m.VirtualUsedPercent + } + }; + + private static JsonObject OsToJson() => new() + { + ["is64Bit"] = _os.Is64Bit, + ["supportedAreas"] = (int)_os.SupportedAreas, + ["areas"] = new JsonObject + { + ["WorkingSet"] = _os.HasWorkingSet, + ["SystemFileCache"] = _os.HasSystemFileCache, + ["ModifiedFileCache"] = _os.HasModifiedFileCache, + ["ModifiedPageList"] = _os.HasModifiedPageList, + ["StandbyList"] = _os.HasStandbyList, + ["StandbyListLowPriority"] = _os.HasStandbyList, + ["CombinedPageList"] = _os.HasCombinedPageList, + ["RegistryCache"] = _os.HasRegistryHive + } + }; + + private static void Respond(int id, JsonNode result) + => Emit(new JsonObject { ["id"] = id, ["ok"] = true, ["result"] = result }); + + private static void Emit(JsonObject payload) + { + var json = payload.ToJsonString(new JsonSerializerOptions { WriteIndented = false }); + lock (_stdoutLock) + { + Console.Out.WriteLine(json); + } + } + + #endregion + + private static bool IsElevated() + { + try + { + using var identity = WindowsIdentity.GetCurrent(); + return new WindowsPrincipal(identity).IsInRole(WindowsBuiltInRole.Administrator); + } + catch { return false; } + } + + private static int CountBits(int value) + { + var count = 0; + while (value != 0) { count += value & 1; value >>= 1; } + return count; + } + } +} diff --git a/electron/engine/SettingsStore.cs b/electron/engine/SettingsStore.cs new file mode 100644 index 00000000..b4bc3b82 --- /dev/null +++ b/electron/engine/SettingsStore.cs @@ -0,0 +1,167 @@ +using Microsoft.Win32; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Runtime.Versioning; +using System.Text.Json; +using System.Text.Json.Nodes; + +namespace WinMemoryCleaner.Engine +{ + /// + /// Reads and writes settings to the SAME registry location used by the original + /// WinMemoryCleaner (HKLM\SOFTWARE\WinMemoryCleaner). This preserves any configuration + /// a user already had before migrating to the Electron edition. + /// + /// Value names match the original Core/Settings.cs where they overlap; a few new keys + /// (Theme) are added alongside them for the redesigned UI. + /// + [SupportedOSPlatform("windows")] + internal static class SettingsStore + { + private const string SettingsKey = @"SOFTWARE\WinMemoryCleaner"; + private const string ExclusionKey = @"SOFTWARE\WinMemoryCleaner\ProcessExclusionList"; + + // Defaults mirror the original Settings.Load(). + private static readonly Dictionary Defaults = new() + { + ["AlwaysOnTop"] = false, + ["AutoOptimizationInterval"] = 0, + ["AutoOptimizationMemoryUsage"] = 0, + ["AutoUpdate"] = true, + ["CloseAfterOptimization"] = false, + ["CloseToTheNotificationArea"] = false, + ["CompactMode"] = false, + ["CreateStartMenuShortcut"] = true, + ["FontSize"] = 14.0, + ["Language"] = "en", + // CombinedPageList|ModifiedFileCache|ModifiedPageList|RegistryCache|StandbyList|SystemFileCache|WorkingSet + ["MemoryAreas"] = (int)(MemoryAreas.CombinedPageList | MemoryAreas.ModifiedFileCache | + MemoryAreas.ModifiedPageList | MemoryAreas.RegistryCache | + MemoryAreas.StandbyList | MemoryAreas.SystemFileCache | MemoryAreas.WorkingSet), + ["RunOnPriority"] = 0, // Low + ["RunOnStartup"] = false, + ["ShowOptimizationNotifications"] = true, + ["ShowVirtualMemory"] = false, + ["StartMinimized"] = false, + ["UseHotkey"] = false, + ["HotkeyModifiers"] = "Control+Shift", + ["HotkeyKey"] = "M", + ["Theme"] = "dark" + }; + + private static readonly HashSet BoolKeys = new(StringComparer.Ordinal) + { + "AlwaysOnTop", "AutoUpdate", "CloseAfterOptimization", "CloseToTheNotificationArea", + "CompactMode", "CreateStartMenuShortcut", "RunOnStartup", "ShowOptimizationNotifications", + "ShowVirtualMemory", "StartMinimized", "UseHotkey" + }; + + private static readonly HashSet IntKeys = new(StringComparer.Ordinal) + { + "AutoOptimizationInterval", "AutoOptimizationMemoryUsage", "MemoryAreas", "RunOnPriority" + }; + + private static readonly HashSet DoubleKeys = new(StringComparer.Ordinal) { "FontSize" }; + + public static JsonObject Read() + { + var result = new JsonObject(); + using (var key = Registry.LocalMachine.OpenSubKey(SettingsKey)) + { + foreach (var kv in Defaults) + { + var raw = key?.GetValue(kv.Key); + result[kv.Key] = ToNode(kv.Key, raw, kv.Value); + } + } + result["ProcessExclusionList"] = ReadExclusionList(); + return result; + } + + private static JsonArray ReadExclusionList() + { + var array = new JsonArray(); + using (var key = Registry.LocalMachine.OpenSubKey(ExclusionKey)) + { + if (key != null) + foreach (var name in key.GetValueNames().OrderBy(n => n)) + array.Add(name); + } + return array; + } + + private static JsonNode ToNode(string name, object raw, object fallback) + { + try + { + if (BoolKeys.Contains(name)) + return JsonValue.Create(raw == null ? (bool)fallback : Convert.ToInt32(raw, CultureInfo.InvariantCulture) != 0); + if (IntKeys.Contains(name)) + return JsonValue.Create(raw == null ? (int)fallback : Convert.ToInt32(raw, CultureInfo.InvariantCulture)); + if (DoubleKeys.Contains(name)) + return JsonValue.Create(raw == null ? (double)fallback : Convert.ToDouble(raw, CultureInfo.InvariantCulture)); + return JsonValue.Create(raw?.ToString() ?? (string)fallback); + } + catch + { + return JsonValue.Create(fallback?.ToString()); + } + } + + public static void Write(JsonObject settings) + { + using (var key = Registry.LocalMachine.CreateSubKey(SettingsKey)) + { + if (key == null) return; + + foreach (var kv in Defaults) + { + if (!settings.TryGetPropertyValue(kv.Key, out var node) || node == null) + continue; + + if (BoolKeys.Contains(kv.Key)) + key.SetValue(kv.Key, node.GetValue() ? 1 : 0, RegistryValueKind.DWord); + else if (IntKeys.Contains(kv.Key)) + key.SetValue(kv.Key, node.GetValue(), RegistryValueKind.DWord); + else if (DoubleKeys.Contains(kv.Key)) + key.SetValue(kv.Key, node.GetValue().ToString(CultureInfo.InvariantCulture), RegistryValueKind.String); + else + key.SetValue(kv.Key, node.ToString(), RegistryValueKind.String); + } + } + + if (settings.TryGetPropertyValue("ProcessExclusionList", out var listNode) && listNode is JsonArray list) + WriteExclusionList(list); + } + + private static void WriteExclusionList(JsonArray list) + { + Registry.LocalMachine.DeleteSubKey(ExclusionKey, false); + if (list.Count == 0) return; + + using (var key = Registry.LocalMachine.CreateSubKey(ExclusionKey)) + { + if (key == null) return; + foreach (var item in list) + { + var name = item?.ToString(); + if (!string.IsNullOrWhiteSpace(name)) + key.SetValue(name.Replace(".exe", string.Empty).Trim().ToLowerInvariant(), string.Empty, RegistryValueKind.String); + } + } + } + + public static List ReadExclusionNames() + { + var list = new List(); + using (var key = Registry.LocalMachine.OpenSubKey(ExclusionKey)) + { + if (key != null) + list.AddRange(key.GetValueNames()); + } + return list; + } + } +} diff --git a/electron/engine/WinMemoryCleaner.Engine.csproj b/electron/engine/WinMemoryCleaner.Engine.csproj new file mode 100644 index 00000000..82a83d4c --- /dev/null +++ b/electron/engine/WinMemoryCleaner.Engine.csproj @@ -0,0 +1,19 @@ + + + + Exe + net10.0-windows + disable + disable + wmc-engine + WinMemoryCleaner.Engine + true + x64 + x64 + true + en + + app.manifest + + + diff --git a/electron/engine/app.manifest b/electron/engine/app.manifest new file mode 100644 index 00000000..1935b87d --- /dev/null +++ b/electron/engine/app.manifest @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/electron/main/engine.js b/electron/main/engine.js new file mode 100644 index 00000000..386c6f61 --- /dev/null +++ b/electron/main/engine.js @@ -0,0 +1,167 @@ +'use strict'; + +const { spawn } = require('child_process'); +const readline = require('readline'); +const path = require('path'); +const fs = require('fs'); +const { EventEmitter } = require('events'); + +/** + * Bridge to the native C# engine (wmc-engine). + * + * Communicates over newline-delimited JSON on stdin/stdout: + * - request/response are correlated by an incrementing numeric id + * - unsolicited "event" messages (progress, ready) are re-emitted on this EventEmitter + * + * The engine binary is manifested `requireAdministrator`. It therefore only launches + * when the Electron process is itself elevated. For non-elevated development the bridge + * falls back to `dotnet `, which bypasses the exe manifest so the UI, live memory + * and settings all work (privileged optimizations will simply report per-area errors). + */ +class Engine extends EventEmitter { + constructor() { + super(); + this.proc = null; + this.rl = null; + this._nextId = 1; + this._pending = new Map(); + this.ready = false; + this.elevated = false; + this._readyResolvers = []; + } + + _resolveEnginePaths() { + // Packaged: resources/engine/wmc-engine.exe + const packaged = path.join(process.resourcesPath || '', 'engine', 'wmc-engine.exe'); + // Dev build output + const devDir = path.join(__dirname, '..', 'engine', 'bin', 'Release', 'net10.0-windows'); + const devExe = path.join(devDir, 'wmc-engine.exe'); + const devDll = path.join(devDir, 'wmc-engine.dll'); + return { packaged, devExe, devDll }; + } + + _candidates() { + const { packaged, devExe, devDll } = this._resolveEnginePaths(); + const viaDotnet = process.env.WMC_ENGINE_VIA_DOTNET === '1'; + const list = []; + + if (fs.existsSync(packaged)) list.push({ command: packaged, args: [] }); + if (!viaDotnet && fs.existsSync(devExe)) list.push({ command: devExe, args: [] }); + // dotnet fallback bypasses the exe's requireAdministrator manifest (dev, non-elevated). + if (fs.existsSync(devDll)) list.push({ command: 'dotnet', args: [devDll] }); + if (viaDotnet && fs.existsSync(devExe)) list.push({ command: devExe, args: [] }); + + if (!list.length) throw new Error('wmc-engine not found. Run "npm run build:engine" first.'); + return list; + } + + start() { + this._launchQueue = this._candidates(); + this._spawnNext(); + return this; + } + + _spawnNext() { + const next = this._launchQueue.shift(); + if (!next) { + this.emit('engine-error', new Error('Failed to launch wmc-engine (elevation may be required).')); + return; + } + + let spawnFailed = false; + this.proc = spawn(next.command, next.args, { + stdio: ['pipe', 'pipe', 'pipe'], + windowsHide: true + }); + + this.proc.on('error', (err) => { + // Elevation failure or missing binary: try the next candidate (e.g. dotnet DLL). + spawnFailed = true; + if (this._launchQueue.length) this._spawnNext(); + else this.emit('engine-error', err); + }); + + this.proc.on('exit', (code) => { + if (spawnFailed) return; + this.ready = false; + this.emit('engine-exit', code); + }); + + this.proc.stderr.on('data', (d) => this.emit('engine-stderr', d.toString())); + + this.rl = readline.createInterface({ input: this.proc.stdout }); + this.rl.on('line', (line) => this._onLine(line)); + } + + _onLine(line) { + line = line.trim(); + if (!line) return; + + let msg; + try { + msg = JSON.parse(line); + } catch { + return; // ignore non-JSON noise + } + + if (msg.type === 'ready') { + this.ready = true; + this.elevated = !!msg.elevated; + this.emit('ready', msg); + this._readyResolvers.splice(0).forEach((r) => r(msg)); + return; + } + + if (msg.type === 'event') { + this.emit('event', msg); + this.emit(`event:${msg.event}`, msg); + return; + } + + // Response to a request + if (typeof msg.id === 'number' && this._pending.has(msg.id)) { + const { resolve, reject } = this._pending.get(msg.id); + this._pending.delete(msg.id); + if (msg.ok) resolve(msg.result); + else reject(new Error(msg.error || 'Engine error')); + } + } + + whenReady() { + if (this.ready) return Promise.resolve({ elevated: this.elevated }); + return new Promise((resolve) => this._readyResolvers.push(resolve)); + } + + request(cmd, args = {}) { + if (!this.proc || !this.proc.stdin.writable) { + return Promise.reject(new Error('Engine is not running')); + } + const id = this._nextId++; + const payload = JSON.stringify({ id, cmd, args }) + '\n'; + return new Promise((resolve, reject) => { + this._pending.set(id, { resolve, reject }); + this.proc.stdin.write(payload, (err) => { + if (err) { + this._pending.delete(id); + reject(err); + } + }); + // Safety timeout (optimize can be slow, so keep it generous) + setTimeout(() => { + if (this._pending.has(id)) { + this._pending.delete(id); + reject(new Error(`Engine request "${cmd}" timed out`)); + } + }, 120000); + }); + } + + stop() { + try { this.rl && this.rl.close(); } catch {} + try { this.proc && this.proc.stdin.end(); } catch {} + try { this.proc && this.proc.kill(); } catch {} + this.proc = null; + } +} + +module.exports = { Engine }; diff --git a/electron/main/main.js b/electron/main/main.js new file mode 100644 index 00000000..e6aa2454 --- /dev/null +++ b/electron/main/main.js @@ -0,0 +1,342 @@ +'use strict'; + +const { app, BrowserWindow, ipcMain, Tray, Menu, globalShortcut, Notification, shell, nativeImage } = require('electron'); +const path = require('path'); +const { Engine } = require('./engine'); + +const ICON_PATH = path.join(__dirname, '..', 'build', 'icon.ico'); + +// Single instance — focus the existing window instead of opening a second one. +// If we don't get the lock, quit immediately and never create a window (otherwise a +// second instance can leave a stray hidden window behind). +const gotLock = app.requestSingleInstanceLock(); + +let mainWindow = null; +let tray = null; +let engine = null; +let settings = {}; +let latestMemory = null; +let isQuitting = false; + +// Auto-optimization bookkeeping (mirrors MainViewModel.MonitorApp). +let lastAutoByInterval = Date.now(); +let lastAutoByMemory = Date.now(); +const AUTO_MEMORY_MIN_INTERVAL_MS = 5 * 60 * 1000; // Constants.App.AutoOptimizationMemoryUsageInterval + +/* ------------------------------------------------------------------ Window */ + +function createWindow() { + mainWindow = new BrowserWindow({ + width: 1120, + height: 760, + minWidth: 880, + minHeight: 600, + show: false, + frame: false, + titleBarStyle: 'hidden', + backgroundColor: '#0b0f1a', + icon: ICON_PATH, + webPreferences: { + preload: path.join(__dirname, '..', 'preload', 'preload.js'), + contextIsolation: true, + nodeIntegration: false, + sandbox: false + } + }); + + mainWindow.loadFile(path.join(__dirname, '..', 'renderer', 'index.html')); + + const reveal = () => { + if (mainWindow && !mainWindow.isDestroyed() && !mainWindow.isVisible() && !settings.StartMinimized) { + mainWindow.show(); + mainWindow.focus(); + } + applyAlwaysOnTop(); + }; + mainWindow.once('ready-to-show', reveal); + // Fallback: if ready-to-show is missed for any reason, don't leave a hidden window behind. + mainWindow.webContents.once('did-finish-load', reveal); + setTimeout(reveal, 3000); + + // Close-to-tray behavior. + mainWindow.on('close', (e) => { + if (!isQuitting && settings.CloseToTheNotificationArea) { + e.preventDefault(); + mainWindow.hide(); + } + }); + + mainWindow.on('closed', () => { mainWindow = null; }); + + mainWindow.on('maximize', () => sendToRenderer('window:state', { maximized: true })); + mainWindow.on('unmaximize', () => sendToRenderer('window:state', { maximized: false })); +} + +function sendToRenderer(channel, payload) { + if (mainWindow && !mainWindow.isDestroyed()) { + mainWindow.webContents.send(channel, payload); + } +} + +function applyAlwaysOnTop() { + if (mainWindow) mainWindow.setAlwaysOnTop(!!settings.AlwaysOnTop); +} + +/* ------------------------------------------------------------------ Engine */ + +async function startEngine() { + engine = new Engine(); + + engine.on('event', (msg) => sendToRenderer('engine:event', msg)); + engine.on('engine-exit', (code) => sendToRenderer('engine:status', { running: false, code })); + engine.on('engine-error', (err) => sendToRenderer('engine:status', { running: false, error: String(err) })); + + engine.start(); + const info = await engine.whenReady(); + sendToRenderer('engine:status', { running: true, elevated: info.elevated }); + + // Load persisted settings and apply side effects. + settings = await engine.request('getSettings'); + applyPriority(); + registerHotkey(); + applyLoginItem(); + + startPolling(); +} + +function applyPriority() { + const priority = settings.RunOnPriority === 0 ? 'low' : 'normal'; + engine.request('setPriority', { priority }).catch(() => {}); +} + +function applyLoginItem() { + try { + app.setLoginItemSettings({ openAtLogin: !!settings.RunOnStartup, path: process.execPath }); + } catch { /* ignored */ } +} + +/* -------------------------------------------------------------- Monitoring */ + +function startPolling() { + const poll = async () => { + if (!engine || !engine.ready) return; + try { + latestMemory = await engine.request('getMemory'); + sendToRenderer('memory:update', latestMemory); + updateTrayTooltip(); + evaluateAutoOptimization(); + } catch { /* transient */ } + }; + poll(); + setInterval(poll, 2000); // matches the original 5s? Original polls every 5s; 2s feels more alive. +} + +function evaluateAutoOptimization() { + if (!latestMemory) return; + const now = Date.now(); + + // Interval-based (hours) + const intervalHours = settings.AutoOptimizationInterval || 0; + if (intervalHours > 0 && (now - lastAutoByInterval) / 3600000 >= intervalHours) { + lastAutoByInterval = now; + runOptimize('Schedule'); + return; + } + + // Low-memory threshold (% free) + const threshold = settings.AutoOptimizationMemoryUsage || 0; + if (threshold > 0 && + latestMemory.physical.freePercent < threshold && + (now - lastAutoByMemory) >= AUTO_MEMORY_MIN_INTERVAL_MS) { + lastAutoByMemory = now; + runOptimize('LowMemory'); + } +} + +/* -------------------------------------------------------------- Optimize */ + +let optimizing = false; + +async function runOptimize(reason) { + if (optimizing || !engine || !engine.ready) return null; + optimizing = true; + sendToRenderer('optimize:state', { running: true, reason }); + try { + const result = await engine.request('optimize', { + areas: settings.MemoryAreas || 0, + processExclusion: settings.ProcessExclusionList || [], + reason + }); + + if (settings.ShowOptimizationNotifications) notifyOptimized(result, reason); + sendToRenderer('optimize:result', result); + return result; + } catch (err) { + sendToRenderer('optimize:error', { message: String(err.message || err) }); + return null; + } finally { + optimizing = false; + sendToRenderer('optimize:state', { running: false }); + if (reason === 'Manual' && settings.CloseAfterOptimization) { + isQuitting = true; + app.quit(); + } + } +} + +function formatBytes(bytes) { + if (!bytes || bytes < 0) bytes = 0; + const units = ['B', 'KB', 'MB', 'GB', 'TB']; + let i = 0, v = bytes; + while (v >= 1024 && i < units.length - 1) { v /= 1024; i++; } + return `${v.toFixed(1)} ${units[i]}`; +} + +function notifyOptimized(result, reason) { + if (!Notification.isSupported()) return; + const phys = formatBytes(result.released.physical); + const body = settings.ShowVirtualMemory + ? `Reason: ${reason}\nPhysical: ${phys}\nVirtual: ${formatBytes(result.released.virtual)}` + : `Reason: ${reason}\nPhysical freed: ${phys}`; + new Notification({ title: 'Memory optimized', body, icon: ICON_PATH, silent: true }).show(); +} + +/* ------------------------------------------------------------------- Tray */ + +function createTray() { + let image = nativeImage.createFromPath(ICON_PATH); + if (!image.isEmpty()) image = image.resize({ width: 16, height: 16 }); + tray = new Tray(image.isEmpty() ? ICON_PATH : image); + tray.setToolTip('Windows Memory Cleaner'); + rebuildTrayMenu(); + + tray.on('double-click', showWindow); + tray.on('middle-click', () => { + if (settings.TrayIconOptimizeOnMiddleMouseClick) runOptimize('Manual'); + }); +} + +function rebuildTrayMenu() { + if (!tray) return; + const menu = Menu.buildFromTemplate([ + { label: 'Optimize now', click: () => runOptimize('Manual') }, + { type: 'separator' }, + { label: 'Show', click: showWindow }, + { label: 'Hide', click: () => mainWindow && mainWindow.hide() }, + { type: 'separator' }, + { label: 'GitHub', click: () => shell.openExternal('https://github.com/IgorMundstein/WinMemoryCleaner') }, + { label: 'Exit', click: () => { isQuitting = true; app.quit(); } } + ]); + tray.setContextMenu(menu); +} + +function updateTrayTooltip() { + if (tray && latestMemory) { + tray.setToolTip(`Windows Memory Cleaner — RAM ${latestMemory.physical.usedPercent}% used`); + } +} + +function showWindow() { + if (!mainWindow) createWindow(); + else { mainWindow.show(); mainWindow.focus(); } +} + +/* --------------------------------------------------------------- Hotkey */ + +function accelerator() { + const mods = (settings.HotkeyModifiers || 'Control+Shift').split('+').map((m) => m.trim()).filter(Boolean); + const key = settings.HotkeyKey || 'M'; + return [...mods, key].join('+'); +} + +function registerHotkey() { + globalShortcut.unregisterAll(); + if (!settings.UseHotkey) return true; + try { + return globalShortcut.register(accelerator(), () => runOptimize('Manual')); + } catch { + return false; + } +} + +/* --------------------------------------------------------------- IPC */ + +function registerIpc() { + ipcMain.handle('engine:getState', async () => { + const state = await engine.request('getState'); + settings = state.settings; + return state; + }); + ipcMain.handle('engine:getMemory', () => latestMemory || engine.request('getMemory')); + ipcMain.handle('engine:getProcesses', () => engine.request('getProcesses')); + ipcMain.handle('engine:getSettings', async () => { + settings = await engine.request('getSettings'); + return settings; + }); + + ipcMain.handle('engine:saveSettings', async (_e, next) => { + settings = { ...settings, ...next }; + await engine.request('saveSettings', settings); + // Apply side effects + applyPriority(); + applyAlwaysOnTop(); + applyLoginItem(); + const hotkeyOk = registerHotkey(); + rebuildTrayMenu(); + return { ok: true, hotkeyOk }; + }); + + ipcMain.handle('engine:optimize', (_e, reason) => runOptimize(reason || 'Manual')); + + // Window controls + ipcMain.handle('window:minimize', () => mainWindow && mainWindow.minimize()); + ipcMain.handle('window:toggleMaximize', () => { + if (!mainWindow) return false; + if (mainWindow.isMaximized()) mainWindow.unmaximize(); + else mainWindow.maximize(); + return mainWindow.isMaximized(); + }); + ipcMain.handle('window:close', () => mainWindow && mainWindow.close()); + ipcMain.handle('window:isMaximized', () => !!(mainWindow && mainWindow.isMaximized())); + + ipcMain.handle('app:info', () => ({ + version: app.getVersion(), + electron: process.versions.electron, + chrome: process.versions.chrome, + node: process.versions.node, + elevated: engine ? engine.elevated : false + })); + + ipcMain.handle('shell:openExternal', (_e, url) => shell.openExternal(url)); +} + +/* --------------------------------------------------------------- Lifecycle */ + +if (!gotLock) { + app.quit(); +} else { + app.on('second-instance', showWindow); + + app.whenReady().then(async () => { + createWindow(); + createTray(); + registerIpc(); + try { + await startEngine(); + } catch (err) { + sendToRenderer('engine:status', { running: false, error: String(err) }); + } + }); +} + +app.on('window-all-closed', () => { + // Keep running in tray on Windows unless explicitly quitting. + if (process.platform !== 'darwin' && isQuitting) app.quit(); +}); + +app.on('before-quit', () => { isQuitting = true; }); + +app.on('will-quit', () => { + globalShortcut.unregisterAll(); + if (engine) engine.stop(); +}); diff --git a/electron/package-lock.json b/electron/package-lock.json new file mode 100644 index 00000000..efd62971 --- /dev/null +++ b/electron/package-lock.json @@ -0,0 +1,5288 @@ +{ + "name": "win-memory-cleaner-desktop", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "win-memory-cleaner-desktop", + "version": "1.0.0", + "license": "GPL-3.0", + "devDependencies": { + "electron": "^33.2.0", + "electron-builder": "^25.1.8" + } + }, + "node_modules/@develar/schema-utils": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz", + "integrity": "sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.0", + "ajv-keywords": "^3.4.1" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/@electron/asar": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@electron/asar/-/asar-3.4.1.tgz", + "integrity": "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^5.0.0", + "glob": "^7.1.6", + "minimatch": "^3.0.4" + }, + "bin": { + "asar": "bin/asar.js" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/@electron/asar/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@electron/asar/node_modules/brace-expansion": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@electron/asar/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@electron/get": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.3.tgz", + "integrity": "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "env-paths": "^2.2.0", + "fs-extra": "^8.1.0", + "got": "^11.8.5", + "progress": "^2.0.3", + "semver": "^6.2.0", + "sumchecker": "^3.0.1" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "global-agent": "^3.0.0" + } + }, + "node_modules/@electron/notarize": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-2.5.0.tgz", + "integrity": "sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^9.0.1", + "promise-retry": "^2.0.1" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/notarize/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@electron/notarize/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/notarize/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/osx-sign": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@electron/osx-sign/-/osx-sign-1.3.1.tgz", + "integrity": "sha512-BAfviURMHpmb1Yb50YbCxnOY0wfwaLXH5KJ4+80zS0gUkzDX3ec23naTlEqKsN+PwYn+a1cCzM7BJ4Wcd3sGzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "compare-version": "^0.1.2", + "debug": "^4.3.4", + "fs-extra": "^10.0.0", + "isbinaryfile": "^4.0.8", + "minimist": "^1.2.6", + "plist": "^3.0.5" + }, + "bin": { + "electron-osx-flat": "bin/electron-osx-flat.js", + "electron-osx-sign": "bin/electron-osx-sign.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@electron/osx-sign/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@electron/osx-sign/node_modules/isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/@electron/osx-sign/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/osx-sign/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/rebuild": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-3.6.1.tgz", + "integrity": "sha512-f6596ZHpEq/YskUd8emYvOUne89ij8mQgjYFA5ru25QwbrRO+t1SImofdDv7kKOuWCmVOuU5tvfkbgGxIl3E/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@malept/cross-spawn-promise": "^2.0.0", + "chalk": "^4.0.0", + "debug": "^4.1.1", + "detect-libc": "^2.0.1", + "fs-extra": "^10.0.0", + "got": "^11.7.0", + "node-abi": "^3.45.0", + "node-api-version": "^0.2.0", + "node-gyp": "^9.0.0", + "ora": "^5.1.0", + "read-binary-file-arch": "^1.0.6", + "semver": "^7.3.5", + "tar": "^6.0.5", + "yargs": "^17.0.1" + }, + "bin": { + "electron-rebuild": "lib/cli.js" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/@electron/rebuild/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@electron/rebuild/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/rebuild/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@electron/rebuild/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/universal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@electron/universal/-/universal-2.0.1.tgz", + "integrity": "sha512-fKpv9kg4SPmt+hY7SVBnIYULE9QJl8L3sCfcBsnqbJwwBwAeTLokJ9TRt9y7bK0JAzIW2y78TVVjvnQEms/yyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron/asar": "^3.2.7", + "@malept/cross-spawn-promise": "^2.0.0", + "debug": "^4.3.1", + "dir-compare": "^4.2.0", + "fs-extra": "^11.1.1", + "minimatch": "^9.0.3", + "plist": "^3.1.0" + }, + "engines": { + "node": ">=16.4" + } + }, + "node_modules/@electron/universal/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@electron/universal/node_modules/brace-expansion": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz", + "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@electron/universal/node_modules/fs-extra": { + "version": "11.4.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.4.0.tgz", + "integrity": "sha512-EQsFzMUJkCKGr1ePqlYADkIUmHW1s3ZXr5Yqy6wbGrfUCphpl2maM/kyOIRA2HpP3AaFQTZXD4ldjek+nccddA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@electron/universal/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/universal/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@electron/universal/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@malept/cross-spawn-promise": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-2.0.0.tgz", + "integrity": "sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/malept" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund" + } + ], + "license": "Apache-2.0", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/@malept/flatpak-bundler": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@malept/flatpak-bundler/-/flatpak-bundler-0.4.0.tgz", + "integrity": "sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^9.0.0", + "lodash": "^4.17.15", + "tmp-promise": "^3.0.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@malept/flatpak-bundler/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@malept/flatpak-bundler/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@malept/flatpak-bundler/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@npmcli/fs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", + "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/fs/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/move-file": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", + "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "dev": true, + "license": "MIT", + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "license": "MIT", + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@tootallnate/once": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.1.tgz", + "integrity": "sha512-HqmEUIGRJ5fSXchkVgR5F7qn48bDBzv0kWj/Kfu5e6uci4UlEeng4331LnBkWffb++Ei3FOVLxo8JJWMFBDMeQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/fs-extra": { + "version": "9.0.13", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", + "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.19.43", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz", + "integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/plist": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/plist/-/plist-3.0.5.tgz", + "integrity": "sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*", + "xmlbuilder": ">=11.0.1" + } + }, + "node_modules/@types/responselike": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", + "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/verror": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.11.tgz", + "integrity": "sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@xmldom/xmldom": { + "version": "0.9.12", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.12.tgz", + "integrity": "sha512-5AXjrcMClTryPe9LgZrygpB1lj7s0S9E0+W+AHaVKAVyHanafK86iPSvG5xHVSp/jC+VH1UXu0TAEmY279xH7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.6" + } + }, + "node_modules/7zip-bin": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-5.2.0.tgz", + "integrity": "sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==", + "dev": true, + "license": "MIT" + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true, + "license": "ISC" + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/app-builder-bin": { + "version": "5.0.0-alpha.10", + "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-5.0.0-alpha.10.tgz", + "integrity": "sha512-Ev4jj3D7Bo+O0GPD2NMvJl+PGiBAfS7pUGawntBNpCbxtpncfUixqFj9z9Jme7V7s3LBGqsWZZP54fxBX3JKJw==", + "dev": true, + "license": "MIT" + }, + "node_modules/app-builder-lib": { + "version": "25.1.8", + "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-25.1.8.tgz", + "integrity": "sha512-pCqe7dfsQFBABC1jeKZXQWhGcCPF3rPCXDdfqVKjIeWBcXzyC1iOWZdfFhGl+S9MyE/k//DFmC6FzuGAUudNDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@develar/schema-utils": "~2.6.5", + "@electron/notarize": "2.5.0", + "@electron/osx-sign": "1.3.1", + "@electron/rebuild": "3.6.1", + "@electron/universal": "2.0.1", + "@malept/flatpak-bundler": "^0.4.0", + "@types/fs-extra": "9.0.13", + "async-exit-hook": "^2.0.1", + "bluebird-lst": "^1.0.9", + "builder-util": "25.1.7", + "builder-util-runtime": "9.2.10", + "chromium-pickle-js": "^0.2.0", + "config-file-ts": "0.2.8-rc1", + "debug": "^4.3.4", + "dotenv": "^16.4.5", + "dotenv-expand": "^11.0.6", + "ejs": "^3.1.8", + "electron-publish": "25.1.7", + "form-data": "^4.0.0", + "fs-extra": "^10.1.0", + "hosted-git-info": "^4.1.0", + "is-ci": "^3.0.0", + "isbinaryfile": "^5.0.0", + "js-yaml": "^4.1.0", + "json5": "^2.2.3", + "lazy-val": "^1.0.5", + "minimatch": "^10.0.0", + "resedit": "^1.7.0", + "sanitize-filename": "^1.6.3", + "semver": "^7.3.8", + "tar": "^6.1.12", + "temp-file": "^3.4.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "dmg-builder": "25.1.8", + "electron-builder-squirrel-windows": "25.1.8" + } + }, + "node_modules/app-builder-lib/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/app-builder-lib/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/app-builder-lib/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/app-builder-lib/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aproba": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.1.0.tgz", + "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==", + "dev": true, + "license": "ISC" + }, + "node_modules/archiver": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz", + "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "archiver-utils": "^2.1.0", + "async": "^3.2.4", + "buffer-crc32": "^0.2.1", + "readable-stream": "^3.6.0", + "readdir-glob": "^1.1.2", + "tar-stream": "^2.2.0", + "zip-stream": "^4.1.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/archiver-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "glob": "^7.1.4", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^2.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/archiver-utils/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/archiver-utils/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/archiver-utils/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "deprecated": "This package is no longer supported.", + "dev": true, + "license": "ISC", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, + "node_modules/async-exit-hook": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz", + "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/bluebird-lst": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/bluebird-lst/-/bluebird-lst-1.0.9.tgz", + "integrity": "sha512-7B1Rtx82hjnSD4PGLAjVWeYH3tHAcVUmChh85a3lltKQm6FresXh9ErQo6oAv6CqxttczC3/kEg8SY5NluPuUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bluebird": "^3.5.5" + } + }, + "node_modules/boolean": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", + "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/brace-expansion": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/builder-util": { + "version": "25.1.7", + "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-25.1.7.tgz", + "integrity": "sha512-7jPjzBwEGRbwNcep0gGNpLXG9P94VA3CPAZQCzxkFXiV2GMQKlziMbY//rXPI7WKfhsvGgFXjTcXdBEwgXw9ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/debug": "^4.1.6", + "7zip-bin": "~5.2.0", + "app-builder-bin": "5.0.0-alpha.10", + "bluebird-lst": "^1.0.9", + "builder-util-runtime": "9.2.10", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.3", + "debug": "^4.3.4", + "fs-extra": "^10.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "is-ci": "^3.0.0", + "js-yaml": "^4.1.0", + "source-map-support": "^0.5.19", + "stat-mode": "^1.0.0", + "temp-file": "^3.4.0" + } + }, + "node_modules/builder-util-runtime": { + "version": "9.2.10", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.10.tgz", + "integrity": "sha512-6p/gfG1RJSQeIbz8TK5aPNkoztgY1q5TgmGFMAXcY8itsGW6Y2ld1ALsZ5UJn8rog7hKF3zHx5iQbNQ8uLcRlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "sax": "^1.2.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/builder-util/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/builder-util/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/builder-util/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/cacache": { + "version": "16.1.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", + "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/cacache/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/cacache/node_modules/brace-expansion": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz", + "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/cacache/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/cacache/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/chromium-pickle-js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz", + "integrity": "sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "license": "ISC", + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/compare-version": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz", + "integrity": "sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/compress-commons": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz", + "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^4.0.2", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/config-file-ts": { + "version": "0.2.8-rc1", + "resolved": "https://registry.npmjs.org/config-file-ts/-/config-file-ts-0.2.8-rc1.tgz", + "integrity": "sha512-GtNECbVI82bT4RiDIzBSVuTKoSHufnU7Ce7/42bkWZJZFLjmDF2WBpVsvRkhKCfKBnTBb3qZrBwPpFBU/Myvhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "^10.3.12", + "typescript": "^5.4.3" + } + }, + "node_modules/config-file-ts/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/config-file-ts/node_modules/brace-expansion": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz", + "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/config-file-ts/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/config-file-ts/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/config-file-ts/node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/crc": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", + "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "buffer": "^5.1.0" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc32-stream": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz", + "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^3.4.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/dir-compare": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-4.2.0.tgz", + "integrity": "sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimatch": "^3.0.5", + "p-limit": "^3.1.0 " + } + }, + "node_modules/dir-compare/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/dir-compare/node_modules/brace-expansion": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/dir-compare/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/dmg-builder": { + "version": "25.1.8", + "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-25.1.8.tgz", + "integrity": "sha512-NoXo6Liy2heSklTI5OIZbCgXC1RzrDQsZkeEwXhdOro3FT1VBOvbubvscdPnjVuQ4AMwwv61oaH96AbiYg9EnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "app-builder-lib": "25.1.8", + "builder-util": "25.1.7", + "builder-util-runtime": "9.2.10", + "fs-extra": "^10.1.0", + "iconv-lite": "^0.6.2", + "js-yaml": "^4.1.0" + }, + "optionalDependencies": { + "dmg-license": "^1.0.11" + } + }, + "node_modules/dmg-builder/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dmg-builder/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/dmg-builder/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/dmg-license": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/dmg-license/-/dmg-license-1.0.11.tgz", + "integrity": "sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "@types/plist": "^3.0.1", + "@types/verror": "^1.10.3", + "ajv": "^6.10.0", + "crc": "^3.8.0", + "iconv-corefoundation": "^1.1.7", + "plist": "^3.0.4", + "smart-buffer": "^4.0.2", + "verror": "^1.10.0" + }, + "bin": { + "dmg-license": "bin/dmg-license.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dotenv-expand": { + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-11.0.7.tgz", + "integrity": "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dotenv": "^16.4.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron": { + "version": "33.4.11", + "resolved": "https://registry.npmjs.org/electron/-/electron-33.4.11.tgz", + "integrity": "sha512-xmdAs5QWRkInC7TpXGNvzo/7exojubk+72jn1oJL7keNeIlw7xNglf8TGtJtkR4rWC5FJq0oXiIXPS9BcK2Irg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@electron/get": "^2.0.0", + "@types/node": "^20.9.0", + "extract-zip": "^2.0.1" + }, + "bin": { + "electron": "cli.js" + }, + "engines": { + "node": ">= 12.20.55" + } + }, + "node_modules/electron-builder": { + "version": "25.1.8", + "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-25.1.8.tgz", + "integrity": "sha512-poRgAtUHHOnlzZnc9PK4nzG53xh74wj2Jy7jkTrqZ0MWPoHGh1M2+C//hGeYdA+4K8w4yiVCNYoLXF7ySj2Wig==", + "dev": true, + "license": "MIT", + "dependencies": { + "app-builder-lib": "25.1.8", + "builder-util": "25.1.7", + "builder-util-runtime": "9.2.10", + "chalk": "^4.1.2", + "dmg-builder": "25.1.8", + "fs-extra": "^10.1.0", + "is-ci": "^3.0.0", + "lazy-val": "^1.0.5", + "simple-update-notifier": "2.0.0", + "yargs": "^17.6.2" + }, + "bin": { + "electron-builder": "cli.js", + "install-app-deps": "install-app-deps.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/electron-builder-squirrel-windows": { + "version": "25.1.8", + "resolved": "https://registry.npmjs.org/electron-builder-squirrel-windows/-/electron-builder-squirrel-windows-25.1.8.tgz", + "integrity": "sha512-2ntkJ+9+0GFP6nAISiMabKt6eqBB0kX1QqHNWFWAXgi0VULKGisM46luRFpIBiU3u/TDmhZMM8tzvo2Abn3ayg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "app-builder-lib": "25.1.8", + "archiver": "^5.3.1", + "builder-util": "25.1.7", + "fs-extra": "^10.1.0" + } + }, + "node_modules/electron-builder-squirrel-windows/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron-builder-squirrel-windows/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-builder-squirrel-windows/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/electron-builder/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron-builder/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-builder/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/electron-publish": { + "version": "25.1.7", + "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-25.1.7.tgz", + "integrity": "sha512-+jbTkR9m39eDBMP4gfbqglDd6UvBC7RLh5Y0MhFSsc6UkGHj9Vj9TWobxevHYMMqmoujL11ZLjfPpMX+Pt6YEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/fs-extra": "^9.0.11", + "builder-util": "25.1.7", + "builder-util-runtime": "9.2.10", + "chalk": "^4.1.2", + "fs-extra": "^10.1.0", + "lazy-val": "^1.0.5", + "mime": "^2.5.2" + } + }, + "node_modules/electron-publish/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron-publish/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-publish/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", + "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extsprintf": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz", + "integrity": "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "license": "MIT", + "optional": true + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/filelist": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.6.tgz", + "integrity": "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz", + "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.4", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "deprecated": "This package is no longer supported.", + "dev": true, + "license": "ISC", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/global-agent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz", + "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "es6-error": "^4.1.1", + "matcher": "^3.0.0", + "roarr": "^2.15.3", + "semver": "^7.3.2", + "serialize-error": "^7.0.1" + }, + "engines": { + "node": ">=10.0" + } + }, + "node_modules/global-agent/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/iconv-corefoundation": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", + "integrity": "sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "cli-truncate": "^2.1.0", + "node-addon-api": "^1.6.3" + }, + "engines": { + "node": "^8.11.2 || >=10" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true, + "license": "ISC" + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ip-address": { + "version": "10.7.2", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.2.tgz", + "integrity": "sha512-7H/2gFSIitxc0hG3nOI1glS8QLo/EHBFFLk8vEUjXY/xu0AdL8jZ9U1IzO2PUm0d2D/ofQcAifb0g6OBkt8U7w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/isbinaryfile": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-5.0.7.tgz", + "integrity": "sha512-gnWD14Jh3FzS3CPhF0AxNOJ8CxqeblPTADzI38r0wt8ZyQl5edpy75myt08EG2oKvpyiqSqsx+Wkz9vtkbTqYQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jake": { + "version": "10.9.4", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", + "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.6", + "filelist": "^1.0.4", + "picocolors": "^1.1.1" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/js-yaml": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/lazy-val": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz", + "integrity": "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/lazystream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/lazystream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-fetch-happen": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", + "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "dev": true, + "license": "ISC", + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/make-fetch-happen/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/make-fetch-happen/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/matcher": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", + "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "escape-string-regexp": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.7.tgz", + "integrity": "sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-abi": { + "version": "3.96.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.96.0.tgz", + "integrity": "sha512-rebQ/lz7i0EkoLzUVSrKRzA69zMkwLp95kKMWoMDkkM00Suxz0D7zEQPwRml5fQum24mj7bPvmlgLAmu2JCiYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-abi/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz", + "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/node-api-version": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-api-version/-/node-api-version-0.2.1.tgz", + "integrity": "sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + } + }, + "node_modules/node-api-version/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-gyp": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.1.tgz", + "integrity": "sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^12.13 || ^14.13 || >=16" + } + }, + "node_modules/node-gyp/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/nopt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "^1.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "deprecated": "This package is no longer supported.", + "dev": true, + "license": "ISC", + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/path-scurry/node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/pe-library": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/pe-library/-/pe-library-0.4.1.tgz", + "integrity": "sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jet2jet" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/plist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.1.tgz", + "integrity": "sha512-ZIfcLJC+7E7FBFnDxm9MPmt7D+DidyQ26lewieO75AdhA2ayMtsJSES0iWzqJQbcVRSrTufQoy0DR94xHue0oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xmldom/xmldom": "^0.9.10", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + }, + "engines": { + "node": ">=10.4.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-binary-file-arch": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/read-binary-file-arch/-/read-binary-file-arch-1.0.6.tgz", + "integrity": "sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "bin": { + "read-binary-file-arch": "cli.js" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdir-glob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "minimatch": "^5.1.0" + } + }, + "node_modules/readdir-glob/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/readdir-glob/node_modules/brace-expansion": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz", + "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/readdir-glob/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resedit": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/resedit/-/resedit-1.7.2.tgz", + "integrity": "sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pe-library": "^0.4.1" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jet2jet" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/roarr": { + "version": "2.15.4", + "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", + "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "detect-node": "^2.0.4", + "globalthis": "^1.0.1", + "json-stringify-safe": "^5.0.1", + "semver-compare": "^1.0.0", + "sprintf-js": "^1.1.2" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/sanitize-filename": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.4.tgz", + "integrity": "sha512-9ZyI08PsvdQl2r/bBIGubpVdR3RR9sY6RDiWFPreA21C/EFlQhmgo20UZlNjZMMZNubusLhAQozkA0Od5J21Eg==", + "dev": true, + "license": "WTFPL OR ISC", + "dependencies": { + "truncate-utf8-bytes": "^1.0.0" + } + }, + "node_modules/sax": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.1.tgz", + "integrity": "sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/serialize-error": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", + "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "type-fest": "^0.13.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true, + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.10", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.10.tgz", + "integrity": "sha512-e0VyvkVTwVYViNovRkZ9aodhxVlyoMn7eJhVUPxZ+eK9P/7CBkxvvsBOHqFPEH416726W8tLXXXjKwqgTErrCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ip-address": "^10.1.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/socks-proxy-agent/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/ssri": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/stat-mode": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-1.0.0.tgz", + "integrity": "sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sumchecker": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", + "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.1.0" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/temp-file": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.4.0.tgz", + "integrity": "sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-exit-hook": "^2.0.1", + "fs-extra": "^10.0.0" + } + }, + "node_modules/temp-file/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/temp-file/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/temp-file/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/tmp": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz", + "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/tmp-promise": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz", + "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tmp": "^0.2.0" + } + }, + "node_modules/truncate-utf8-bytes": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", + "integrity": "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==", + "dev": true, + "license": "WTFPL", + "dependencies": { + "utf8-byte-length": "^1.0.1" + } + }, + "node_modules/type-fest": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unique-filename": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", + "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", + "dev": true, + "license": "ISC", + "dependencies": { + "unique-slug": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/unique-slug": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", + "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/utf8-byte-length": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz", + "integrity": "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==", + "dev": true, + "license": "(WTFPL OR MIT)" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/verror": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.1.tgz", + "integrity": "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", + "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zip-stream": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", + "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "archiver-utils": "^3.0.4", + "compress-commons": "^4.1.2", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/zip-stream/node_modules/archiver-utils": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz", + "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "glob": "^7.2.3", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + } + } +} diff --git a/electron/package.json b/electron/package.json new file mode 100644 index 00000000..cd179c5a --- /dev/null +++ b/electron/package.json @@ -0,0 +1,39 @@ +{ + "name": "win-memory-cleaner-desktop", + "productName": "Windows Memory Cleaner", + "version": "3.0.8", + "description": "A modern Electron desktop front-end for Windows Memory Cleaner, driving the native C# optimization engine.", + "author": "Igor Mundstein (original) — Electron edition", + "license": "GPL-3.0", + "main": "main/main.js", + "scripts": { + "start": "electron .", + "build:engine": "dotnet build engine/WinMemoryCleaner.Engine.csproj -c Release", + "dev": "npm run build:engine && electron .", + "dist": "electron-builder" + }, + "devDependencies": { + "electron": "^33.2.0", + "electron-builder": "^25.1.8" + }, + "build": { + "appId": "com.winmemorycleaner.desktop", + "productName": "Windows Memory Cleaner", + "files": [ + "main/**/*", + "preload/**/*", + "renderer/**/*", + "build/**/*" + ], + "extraResources": [ + { + "from": "engine/bin/Release/net10.0-windows", + "to": "engine" + } + ], + "win": { + "target": "nsis", + "requestedExecutionLevel": "requireAdministrator" + } + } +} diff --git a/electron/preload/preload.js b/electron/preload/preload.js new file mode 100644 index 00000000..7dfe2a65 --- /dev/null +++ b/electron/preload/preload.js @@ -0,0 +1,44 @@ +'use strict'; + +const { contextBridge, ipcRenderer } = require('electron'); + +/** + * The only surface the renderer can touch. No Node, no direct IPC — just this + * explicit, minimal API. Event subscriptions return an unsubscribe function. + */ +const listen = (channel) => (callback) => { + const handler = (_event, payload) => callback(payload); + ipcRenderer.on(channel, handler); + return () => ipcRenderer.removeListener(channel, handler); +}; + +contextBridge.exposeInMainWorld('wmc', { + // Engine / data + getState: () => ipcRenderer.invoke('engine:getState'), + getMemory: () => ipcRenderer.invoke('engine:getMemory'), + getProcesses: () => ipcRenderer.invoke('engine:getProcesses'), + getSettings: () => ipcRenderer.invoke('engine:getSettings'), + saveSettings: (settings) => ipcRenderer.invoke('engine:saveSettings', settings), + optimize: (reason) => ipcRenderer.invoke('engine:optimize', reason), + + // App / shell + appInfo: () => ipcRenderer.invoke('app:info'), + openExternal: (url) => ipcRenderer.invoke('shell:openExternal', url), + + // Window controls + window: { + minimize: () => ipcRenderer.invoke('window:minimize'), + toggleMaximize: () => ipcRenderer.invoke('window:toggleMaximize'), + close: () => ipcRenderer.invoke('window:close'), + isMaximized: () => ipcRenderer.invoke('window:isMaximized') + }, + + // Events (main -> renderer) + onMemory: listen('memory:update'), + onEngineEvent: listen('engine:event'), + onEngineStatus: listen('engine:status'), + onOptimizeState: listen('optimize:state'), + onOptimizeResult: listen('optimize:result'), + onOptimizeError: listen('optimize:error'), + onWindowState: listen('window:state') +}); diff --git a/electron/renderer/index.html b/electron/renderer/index.html new file mode 100644 index 00000000..410c41c6 --- /dev/null +++ b/electron/renderer/index.html @@ -0,0 +1,306 @@ + + + + + + + Windows Memory Cleaner + + + + + + + +
+
+
+ + Windows Memory Cleaner + 3.0.8 +
+
+
+ + + Engine + +
+
+ + + +
+
+ +
+ + + + +
+ + +
+
+
+

Overview

+

Live memory status

+
+ +
+ +
+
+
+ + + + + + + + + + +
+ – + RAM used +
+
+
+

Physical Memory

+
+
Used–
+
Free–
+
Total–
+
+
+
+ +
+
+ + + + + + + + + + +
+ – + Committed +
+
+
+

Virtual Memory

+
+
Used–
+
Free–
+
Total–
+
+
+
+ +
+
+

RAM usage

+ – +
+ + + + + + + + + + +
+
+ +
+
+
+

Memory areas

+

Choose what gets cleaned. Unsupported areas are disabled for your Windows version.

+
+
+ + +
+
+
+
+ +
+ +
Ctrl + Shift + M
+
+
+ + +
+

Automation

Let the cleaner run itself

+ +
+
+

Optimize on a schedule

Disabled

+
+ + Off +
+
+
+ +
+
+

Optimize when free RAM drops below

Disabled

+
+ + Off +
+
+

Throttled to at most once every 5 minutes.

+
+
+ + +
+

Process exclusions

Skip these when trimming working sets

+
+
+ + + +
+
+
+
+ + +
+
+

Settings

Behavior, appearance & shortcuts

+ +
+ +
+

Behavior

+
+
+ +
+

Optimize hotkey

+
+ +
+ + + + +
+
+ +
+ +
+

Appearance

+
+
+ + +
+ +
+
+
+ + +
+

About

Windows Memory Cleaner — Electron edition

+
+ +

A modern desktop shell over the original native optimization engine. Your kernel-level + memory operations run in a hardened C# helper; this window is only the interface.

+
    + +
    +
    + +
    +
    + + +
    + + + + + + + diff --git a/electron/renderer/js/app.js b/electron/renderer/js/app.js new file mode 100644 index 00000000..f3e32d2e --- /dev/null +++ b/electron/renderer/js/app.js @@ -0,0 +1,504 @@ +'use strict'; + +/* ========================================================================== + Windows Memory Cleaner — renderer + Talks only to window.wmc (see preload). No Node here. + ========================================================================== */ + +const api = window.wmc; +const $ = (sel, root = document) => root.querySelector(sel); +const $$ = (sel, root = document) => [...root.querySelectorAll(sel)]; + +const RING_C = 540; // 2 * PI * 86, matches CSS stroke-dasharray + +// Memory-area metadata. Bit values match the engine's MemoryAreas enum exactly. +const AREAS = [ + { bit: 128, key: 'WorkingSet', name: 'Working Set', sub: "Processes' active RAM" }, + { bit: 16, key: 'StandbyList', name: 'Standby List', sub: 'Cached standby pages' }, + { bit: 32, key: 'StandbyListLowPriority', name: 'Standby (low priority)', sub: 'Low-priority cache' }, + { bit: 4, key: 'ModifiedPageList', name: 'Modified Page List', sub: 'Pending writes' }, + { bit: 64, key: 'SystemFileCache', name: 'System File Cache', sub: 'Cached file data' }, + { bit: 2, key: 'ModifiedFileCache', name: 'Modified File Cache', sub: 'Dirty file pages' }, + { bit: 1, key: 'CombinedPageList', name: 'Combined Page List', sub: 'Deduplicated pages' }, + { bit: 8, key: 'RegistryCache', name: 'Registry Cache', sub: 'Registry hive cache' } +]; + +const BEHAVIOR_TOGGLES = [ + { key: 'AlwaysOnTop', label: 'Always on top' }, + { key: 'StartMinimized', label: 'Start minimized' }, + { key: 'CloseToTheNotificationArea', label: 'Close to tray' }, + { key: 'CloseAfterOptimization', label: 'Close after optimizing' }, + { key: 'RunOnStartup', label: 'Run on Windows startup' }, + { key: 'ShowOptimizationNotifications', label: 'Optimization notifications' }, + { key: 'ShowVirtualMemory', label: 'Show virtual memory' }, + { key: 'RunOnLowPriority', label: 'Run on low priority', derived: true }, + { key: 'CompactMode', label: 'Compact mode' }, + { key: 'AutoUpdate', label: 'Check for updates' } +]; + +const LANGUAGES = [ + ['en', 'English'], ['it', 'Italiano'], ['de', 'Deutsch'], ['fr', 'Français'], + ['es', 'Español'], ['pt-BR', 'Português (BR)'], ['nl', 'Nederlands'], ['pl', 'Polski'], + ['ru', 'Русский'], ['tr', 'Türkçe'], ['zh-Hans', '简体中文'], ['zh-Hant', '繁體中文'], + ['ja', '日本語'], ['ko', '한국어'], ['ar', 'العربية'] +]; + +const HOTKEY_KEYS = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z', + 'F1','F2','F3','F4','F5','F6','F7','F8','F9','F10','F11','F12']; + +const state = { + settings: {}, + os: null, + memory: null, + optimizing: false, + history: [] +}; + +/* ------------------------------------------------ utils */ +function formatBytes(bytes) { + if (!bytes || bytes < 0) bytes = 0; + const units = ['B', 'KB', 'MB', 'GB', 'TB']; + let i = 0, v = bytes; + while (v >= 1024 && i < units.length - 1) { v /= 1024; i++; } + return `${v.toFixed(v >= 100 || i === 0 ? 0 : 1)} ${units[i]}`; +} + +function toast(title, body, isError = false) { + const host = $('#toastHost'); + const el = document.createElement('div'); + el.className = 'toast' + (isError ? ' err' : ''); + el.innerHTML = `
    ${title}
    ` + + (body ? `
    ${body}
    ` : ''); + host.appendChild(el); + setTimeout(() => { el.classList.add('out'); setTimeout(() => el.remove(), 400); }, isError ? 5200 : 4200); +} + +/* ------------------------------------------------ persistence */ +let saveTimer = null; +function saveSoon() { + clearTimeout(saveTimer); + saveTimer = setTimeout(async () => { + try { + const res = await api.saveSettings(state.settings); + if (res && res.hotkeyOk === false && state.settings.UseHotkey) { + showHotkeyWarn(true); + } + } catch (e) { toast('Could not save', String(e.message || e), true); } + }, 180); +} + +/* ------------------------------------------------ navigation */ +function initNav() { + $$('.nav-item').forEach((btn) => { + btn.addEventListener('click', () => { + $$('.nav-item').forEach((b) => b.classList.toggle('active', b === btn)); + const view = btn.dataset.view; + $$('.view').forEach((v) => v.classList.toggle('active', v.id === `view-${view}`)); + if (view === 'processes') refreshProcesses(); + }); + }); +} + +/* ------------------------------------------------ window controls */ +function initWindowControls() { + $('#btnMin').addEventListener('click', () => api.window.minimize()); + $('#btnMax').addEventListener('click', () => api.window.toggleMaximize()); + $('#btnClose').addEventListener('click', () => api.window.close()); +} + +/* ------------------------------------------------ theme */ +function applyTheme(theme) { + document.documentElement.setAttribute('data-theme', theme); + const useIcon = theme === 'dark' ? 'i-moon' : 'i-sun'; + $('#themeToggle').innerHTML = ``; + $$('#themeSeg button').forEach((b) => b.classList.toggle('active', b.dataset.themeVal === theme)); +} +function setTheme(theme) { + state.settings.Theme = theme; + applyTheme(theme); + saveSoon(); +} + +/* ------------------------------------------------ gauges */ +function setRing(arcId, pctId, cardId, pct, showNa = false) { + const arc = $(arcId), lbl = $(pctId); + if (showNa) { + arc.style.strokeDashoffset = RING_C; + lbl.textContent = '—'; lbl.classList.add('na'); + return; + } + lbl.classList.remove('na'); + const p = Math.max(0, Math.min(100, pct)); + arc.style.strokeDashoffset = RING_C * (1 - p / 100); + lbl.textContent = Math.round(p); +} + +function renderMemory(mem) { + state.memory = mem; + const phys = mem.physical, virt = mem.virtual; + + setRing('#physArc', '#physPct', '#physCard', phys.usedPercent); + $('#physUsed').textContent = formatBytes(phys.used); + $('#physFree').textContent = formatBytes(phys.free); + $('#physTotal').textContent = formatBytes(phys.total); + + setRing('#virtArc', '#virtPct', '#virtCard', virt.usedPercent); + $('#virtUsed').textContent = formatBytes(virt.used); + $('#virtFree').textContent = formatBytes(virt.free); + $('#virtTotal').textContent = formatBytes(virt.total); + + $('#dashSubtitle').textContent = `${formatBytes(phys.used)} of ${formatBytes(phys.total)} in use`; + $('#sparkNow').textContent = `${phys.usedPercent}%`; + + pushHistory(phys.usedPercent); +} + +function pushHistory(pct) { + state.history.push(pct); + if (state.history.length > 60) state.history.shift(); + const h = state.history; + if (h.length < 2) return; + const W = 300, H = 90, pad = 4; + const step = W / (h.length - 1); + const y = (v) => H - pad - (v / 100) * (H - pad * 2); + let line = `M0 ${y(h[0]).toFixed(1)}`; + h.forEach((v, i) => { if (i) line += ` L${(i * step).toFixed(1)} ${y(v).toFixed(1)}`; }); + $('#sparkLine').setAttribute('d', line); + $('#sparkArea').setAttribute('d', `${line} L${W} ${H} L0 ${H} Z`); +} + +/* ------------------------------------------------ areas */ +function renderAreas() { + const grid = $('#areasGrid'); + const supported = state.os ? state.os.supportedAreas : 0xFF; + grid.innerHTML = ''; + AREAS.forEach((a) => { + const isSupported = (supported & a.bit) !== 0; + const on = (state.settings.MemoryAreas & a.bit) !== 0; + const chip = document.createElement('button'); + chip.className = 'area-chip' + (on ? ' on' : '') + (isSupported ? '' : ' disabled'); + chip.innerHTML = + `` + + `${a.name}
    ${a.sub}
    `; + if (isSupported) chip.addEventListener('click', () => toggleArea(a)); + grid.appendChild(chip); + }); +} + +function toggleArea(a) { + let areas = state.settings.MemoryAreas || 0; + const turningOn = (areas & a.bit) === 0; + areas ^= a.bit; + // Standby list and its low-priority variant are mutually exclusive (original behavior). + if (turningOn && a.bit === 16) areas &= ~32; + if (turningOn && a.bit === 32) areas &= ~16; + state.settings.MemoryAreas = areas; + renderAreas(); + updateOptimizeEnabled(); + saveSoon(); +} + +function updateOptimizeEnabled() { + const has = (state.settings.MemoryAreas || 0) !== 0; + $('#optimizeBtn').disabled = !has || state.optimizing; +} + +/* ------------------------------------------------ optimize */ +function initOptimize() { + $('#optimizeBtn').addEventListener('click', () => { if (!state.optimizing) api.optimize('Manual'); }); + $('#selectAll').addEventListener('click', () => { + state.settings.MemoryAreas = state.os ? state.os.supportedAreas & ~32 : 0xFF & ~32; + renderAreas(); updateOptimizeEnabled(); saveSoon(); + }); + $('#selectNone').addEventListener('click', () => { + state.settings.MemoryAreas = 0; renderAreas(); updateOptimizeEnabled(); saveSoon(); + }); +} + +function setOptimizing(running) { + state.optimizing = running; + const btn = $('#optimizeBtn'); + btn.classList.toggle('running', running); + updateOptimizeEnabled(); + if (!running) { + $('#optFill').style.width = '0%'; + $('#optText').textContent = 'Optimize'; + } +} + +/* ------------------------------------------------ automation */ +function initAutomation() { + const interval = $('#autoInterval'), mem = $('#autoMem'); + + interval.addEventListener('input', () => { + const v = +interval.value; + $('#autoIntervalOut').textContent = v === 0 ? 'Off' : `${v} h`; + $('#autoIntervalDesc').textContent = v === 0 ? 'Disabled' : `Every ${v} hour${v > 1 ? 's' : ''}`; + }); + interval.addEventListener('change', () => { + state.settings.AutoOptimizationInterval = +interval.value; saveSoon(); + }); + + mem.addEventListener('input', () => { + const v = +mem.value; + $('#autoMemOut').textContent = v === 0 ? 'Off' : `${v}%`; + $('#autoMemDesc').textContent = v === 0 ? 'Disabled' : `When free RAM is below ${v}%`; + }); + mem.addEventListener('change', () => { + state.settings.AutoOptimizationMemoryUsage = +mem.value; saveSoon(); + }); +} + +function syncAutomation() { + const iv = state.settings.AutoOptimizationInterval || 0; + const mv = state.settings.AutoOptimizationMemoryUsage || 0; + $('#autoInterval').value = iv; + $('#autoMem').value = mv; + $('#autoIntervalOut').textContent = iv === 0 ? 'Off' : `${iv} h`; + $('#autoIntervalDesc').textContent = iv === 0 ? 'Disabled' : `Every ${iv} hour${iv > 1 ? 's' : ''}`; + $('#autoMemOut').textContent = mv === 0 ? 'Off' : `${mv}%`; + $('#autoMemDesc').textContent = mv === 0 ? 'Disabled' : `When free RAM is below ${mv}%`; +} + +/* ------------------------------------------------ processes */ +async function refreshProcesses() { + try { + const procs = await api.getProcesses(); + const excluded = new Set((state.settings.ProcessExclusionList || []).map((s) => s.toLowerCase())); + const sel = $('#procSelect'); + sel.innerHTML = ''; + procs.filter((p) => !excluded.has(p.toLowerCase())).forEach((p) => { + const o = document.createElement('option'); o.value = p; o.textContent = p; sel.appendChild(o); + }); + } catch (e) { /* ignore */ } + renderExclusionList(); +} + +function renderExclusionList() { + const list = $('#procList'); + const items = state.settings.ProcessExclusionList || []; + list.innerHTML = ''; + if (!items.length) { list.innerHTML = '
    No excluded processes
    '; return; } + items.forEach((name) => { + const row = document.createElement('div'); + row.className = 'proc-item'; + row.innerHTML = `${name}`; + row.querySelector('button').addEventListener('click', () => { + state.settings.ProcessExclusionList = items.filter((n) => n !== name); + saveSoon(); refreshProcesses(); + }); + list.appendChild(row); + }); +} + +function initProcesses() { + $('#procAdd').addEventListener('click', () => { + const val = $('#procSelect').value; + if (!val) return; + const list = state.settings.ProcessExclusionList || []; + if (!list.includes(val)) { list.push(val); list.sort(); state.settings.ProcessExclusionList = list; saveSoon(); refreshProcesses(); } + }); + $('#procRefresh').addEventListener('click', refreshProcesses); +} + +/* ------------------------------------------------ settings toggles */ +function getToggle(key) { + if (key === 'RunOnLowPriority') return (state.settings.RunOnPriority || 0) === 0; + return !!state.settings[key]; +} +function setToggle(key, val) { + if (key === 'RunOnLowPriority') { state.settings.RunOnPriority = val ? 0 : 1; } + else { state.settings[key] = val; } + // Live UI effects + if (key === 'ShowVirtualMemory') $('#virtCard').style.display = val ? '' : 'none'; + saveSoon(); +} + +function renderToggles() { + const grid = $('#toggleGrid'); + grid.innerHTML = ''; + BEHAVIOR_TOGGLES.forEach((t) => { + const row = document.createElement('div'); + row.className = 'toggle-row'; + row.innerHTML = `${t.label} + `; + row.querySelector('input').addEventListener('change', (e) => setToggle(t.key, e.target.checked)); + grid.appendChild(row); + }); + $('#virtCard').style.display = state.settings.ShowVirtualMemory ? '' : 'none'; +} + +/* ------------------------------------------------ hotkey */ +function showHotkeyWarn(show) { + const el = $('#hotkeyWarn'); + el.hidden = !show; + el.className = 'hint-note warn'; + el.innerHTML = show ? ` This shortcut is already in use by the system. Choose another.` : ''; +} + +function currentAccelerator() { + const mods = []; + if ($('#hkCtrl').checked) mods.push('Control'); + if ($('#hkShift').checked) mods.push('Shift'); + if ($('#hkAlt').checked) mods.push('Alt'); + return { modifiers: mods.join('+'), key: $('#hkKey').value }; +} +function updateHotkeyHint() { + const parts = []; + if ($('#hkCtrl').checked) parts.push('Ctrl'); + if ($('#hkShift').checked) parts.push('Shift'); + if ($('#hkAlt').checked) parts.push('Alt'); + parts.push($('#hkKey').value); + $('#ctaHint').textContent = state.settings.UseHotkey ? parts.join(' + ') : 'Hotkey off'; +} + +function initHotkey() { + const key = $('#hkKey'); + HOTKEY_KEYS.forEach((k) => { const o = document.createElement('option'); o.value = k; o.textContent = k; key.appendChild(o); }); + + const onChange = () => { + const { modifiers, key: k } = currentAccelerator(); + state.settings.UseHotkey = $('#useHotkey').checked; + state.settings.HotkeyModifiers = modifiers || 'Control+Shift'; + state.settings.HotkeyKey = k; + showHotkeyWarn(false); + updateHotkeyHint(); + saveSoon(); + }; + ['#useHotkey', '#hkCtrl', '#hkShift', '#hkAlt', '#hkKey'].forEach((s) => $(s).addEventListener('change', onChange)); +} + +function syncHotkey() { + const mods = (state.settings.HotkeyModifiers || 'Control+Shift').split('+'); + $('#useHotkey').checked = !!state.settings.UseHotkey; + $('#hkCtrl').checked = mods.includes('Control'); + $('#hkShift').checked = mods.includes('Shift'); + $('#hkAlt').checked = mods.includes('Alt'); + $('#hkKey').value = state.settings.HotkeyKey || 'M'; + updateHotkeyHint(); +} + +/* ------------------------------------------------ appearance */ +function initAppearance() { + $('#themeToggle').addEventListener('click', () => setTheme(state.settings.Theme === 'dark' ? 'light' : 'dark')); + $$('#themeSeg button').forEach((b) => b.addEventListener('click', () => setTheme(b.dataset.themeVal))); + + const lang = $('#langSelect'); + LANGUAGES.forEach(([code, name]) => { const o = document.createElement('option'); o.value = code; o.textContent = name; lang.appendChild(o); }); + lang.addEventListener('change', () => { state.settings.Language = lang.value; saveSoon(); }); +} + +/* ------------------------------------------------ reset & about */ +function initReset() { + $('#resetBtn').addEventListener('click', async () => { + const keepLang = state.settings.Language; + state.settings = { + AlwaysOnTop: false, AutoOptimizationInterval: 0, AutoOptimizationMemoryUsage: 0, AutoUpdate: true, + CloseAfterOptimization: false, CloseToTheNotificationArea: false, CompactMode: false, CreateStartMenuShortcut: true, + FontSize: 14, Language: keepLang, MemoryAreas: 223, RunOnPriority: 0, RunOnStartup: false, + ShowOptimizationNotifications: true, ShowVirtualMemory: false, StartMinimized: false, UseHotkey: false, + HotkeyModifiers: 'Control+Shift', HotkeyKey: 'M', Theme: 'dark', + ProcessExclusionList: [] + }; + await api.saveSettings(state.settings); + hydrateUI(); + toast('Settings reset', 'Restored to default configuration'); + }); + + $$('[data-ext]').forEach((b) => b.addEventListener('click', () => api.openExternal(b.dataset.ext))); +} + +async function loadAbout() { + try { + const info = await api.appInfo(); + $('#appVersion').textContent = info.version; + $('#aboutFacts').innerHTML = ` +
  • App version${info.version}
  • +
  • Electron${info.electron}
  • +
  • Chromium${info.chrome}
  • +
  • Node${info.node}
  • +
  • Enginenative C# (P/Invoke)
  • +
  • Privileges${info.elevated ? 'Administrator' : 'Standard user'}
  • `; + } catch { /* ignore */ } +} + +/* ------------------------------------------------ hydrate */ +function hydrateUI() { + applyTheme(state.settings.Theme || 'dark'); + renderAreas(); + renderToggles(); + syncAutomation(); + syncHotkey(); + updateOptimizeEnabled(); + const lang = $('#langSelect'); if (lang) lang.value = state.settings.Language || 'en'; + renderExclusionList(); +} + +/* ------------------------------------------------ engine events */ +function initEngineEvents() { + api.onMemory((mem) => renderMemory(mem)); + + api.onEngineStatus((s) => { + const chip = $('#engineChip'); + chip.classList.toggle('ok', !!s.running); + chip.classList.toggle('err', !s.running); + chip.lastChild.textContent = s.running ? ' Engine' : ' Engine offline'; + if (s.running && s.elevated) $('#elevChip').hidden = false; + if (s.error) toast('Engine problem', s.error, true); + }); + + api.onEngineEvent((msg) => { + if (msg.event === 'optimizeStart') { $('#optText').textContent = 'Starting…'; } + if (msg.event === 'progress') { + const d = msg.data; + $('#optFill').style.width = `${d.percent}%`; + $('#optText').textContent = `${d.name}…`; + } + }); + + api.onOptimizeState((s) => setOptimizing(s.running)); + + api.onOptimizeResult((r) => { + const failed = (r.results || []).filter((x) => !x.success); + const phys = formatBytes(r.released.physical); + const virt = formatBytes(r.released.virtual); + const body = state.settings.ShowVirtualMemory + ? `Physical freed: ${phys}\nVirtual freed: ${virt}${failed.length ? `\n${failed.length} area(s) skipped` : ''}` + : `Physical freed: ${phys}${failed.length ? `\n${failed.length} area(s) skipped` : ''}`; + toast('Memory optimized', body, false); + renderMemory({ physical: r.after.physical, virtual: r.after.virtual }); + }); + + api.onOptimizeError((e) => toast('Optimization failed', e.message, true)); +} + +/* ------------------------------------------------ boot */ +async function boot() { + initNav(); + initWindowControls(); + initOptimize(); + initAutomation(); + initProcesses(); + initHotkey(); + initAppearance(); + initReset(); + initEngineEvents(); + + try { + const st = await api.getState(); + state.settings = st.settings; + state.os = st.os; + if (st.memory) renderMemory(st.memory); + if (st.elevated) $('#elevChip').hidden = false; + $('#engineChip').classList.add('ok'); + } catch (e) { + // Engine may still be starting; fall back to settings only. + try { state.settings = await api.getSettings(); } catch { state.settings = {}; } + } + + hydrateUI(); + loadAbout(); +} + +document.addEventListener('DOMContentLoaded', boot); diff --git a/electron/renderer/styles/app.css b/electron/renderer/styles/app.css new file mode 100644 index 00000000..9fc9a391 --- /dev/null +++ b/electron/renderer/styles/app.css @@ -0,0 +1,376 @@ +/* ============================================================ + Windows Memory Cleaner — Liquid Glass design system + ============================================================ */ + +:root { + --accent-a: #a06bff; + --accent-b: #22d3ee; + --accent-grad: linear-gradient(135deg, var(--accent-a), var(--accent-b)); + --good: #34d399; + --warn: #fbbf24; + --danger: #fb7185; + + --radius: 20px; + --radius-sm: 12px; + --ease: cubic-bezier(.22, 1, .36, 1); + --titlebar-h: 44px; +} + +/* ---- Dark (default) ---- */ +:root[data-theme="dark"] { + --bg-0: #070912; + --bg-1: #0b1020; + --text: #eef2ff; + --text-dim: #9aa7c7; + --text-faint: #6b7799; + --glass-bg: rgba(255, 255, 255, .055); + --glass-bg-2: rgba(255, 255, 255, .09); + --glass-brd: rgba(255, 255, 255, .12); + --glass-hi: rgba(255, 255, 255, .35); + --shadow: 0 24px 60px -20px rgba(0, 0, 0, .7); + --ring-track: rgba(255, 255, 255, .08); + color-scheme: dark; +} + +/* ---- Light ---- */ +:root[data-theme="light"] { + --bg-0: #eef1fb; + --bg-1: #e5e9f7; + --text: #14192b; + --text-dim: #52607f; + --text-faint: #8290ad; + --glass-bg: rgba(255, 255, 255, .55); + --glass-bg-2: rgba(255, 255, 255, .72); + --glass-brd: rgba(255, 255, 255, .8); + --glass-hi: rgba(255, 255, 255, .95); + --shadow: 0 24px 55px -22px rgba(60, 70, 120, .45); + --ring-track: rgba(20, 25, 43, .09); + color-scheme: light; +} + +* { box-sizing: border-box; margin: 0; padding: 0; } + +html, body { + height: 100%; + overflow: hidden; + font-family: "Segoe UI Variable Display", "Segoe UI", Inter, system-ui, sans-serif; + color: var(--text); + background: var(--bg-0); + -webkit-font-smoothing: antialiased; + user-select: none; +} + +body { position: relative; } + +svg.ic { width: 18px; height: 18px; display: inline-block; vertical-align: middle; color: currentColor; } + +h1 { font-size: 26px; font-weight: 650; letter-spacing: -.02em; } +h3 { font-size: 15px; font-weight: 600; letter-spacing: -.01em; } +.muted { color: var(--text-dim); font-size: 13px; } + +/* ------------------------------------------------ Aurora background */ +.aurora { position: fixed; inset: 0; z-index: 0; overflow: hidden; background: + radial-gradient(120% 120% at 100% 0%, var(--bg-1), var(--bg-0) 60%); } +.aurora .blob { + position: absolute; border-radius: 50%; filter: blur(70px); opacity: .55; + mix-blend-mode: screen; animation: drift 22s var(--ease) infinite alternate; +} +:root[data-theme="light"] .aurora .blob { mix-blend-mode: normal; opacity: .5; } +.aurora .b1 { width: 46vw; height: 46vw; left: -8vw; top: -10vw; + background: radial-gradient(circle, #7c3aed, transparent 65%); } +.aurora .b2 { width: 40vw; height: 40vw; right: -6vw; top: 6vh; + background: radial-gradient(circle, #06b6d4, transparent 65%); animation-delay: -6s; } +.aurora .b3 { width: 44vw; height: 44vw; left: 30vw; bottom: -18vw; + background: radial-gradient(circle, #ec4899, transparent 65%); animation-delay: -12s; } +.aurora .grid { + position: absolute; inset: 0; opacity: .04; + background-image: linear-gradient(var(--text) 1px, transparent 1px), + linear-gradient(90deg, var(--text) 1px, transparent 1px); + background-size: 44px 44px; mask-image: radial-gradient(100% 100% at 50% 0%, #000, transparent 75%); +} +@keyframes drift { + 0% { transform: translate3d(0,0,0) scale(1); } + 100% { transform: translate3d(4vw, 4vh, 0) scale(1.15); } +} +@media (prefers-reduced-motion: reduce) { .aurora .blob { animation: none; } } + +/* ------------------------------------------------ Title bar */ +.titlebar { + position: relative; z-index: 5; height: var(--titlebar-h); + display: flex; align-items: center; gap: 12px; + padding-left: 16px; -webkit-app-region: drag; + border-bottom: 1px solid var(--glass-brd); + background: linear-gradient(180deg, var(--glass-bg), transparent); +} +.titlebar-drag { flex: 1; display: flex; align-items: center; height: 100%; min-width: 0; } +.brand { display: flex; align-items: center; gap: 10px; min-width: 0; } +.brand-mark { + width: 18px; height: 18px; border-radius: 6px; background: var(--accent-grad); + box-shadow: 0 0 18px -2px var(--accent-a); position: relative; flex: 0 0 auto; +} +.brand-mark::after { content: ""; position: absolute; inset: 4px; border-radius: 3px; + background: rgba(255,255,255,.85); mix-blend-mode: overlay; } +.brand-mark.big { width: 46px; height: 46px; border-radius: 14px; } +.brand-name { font-size: 13px; font-weight: 600; letter-spacing: .01em; white-space: nowrap; + overflow: hidden; text-overflow: ellipsis; } +.brand-ver { font-size: 10.5px; color: var(--text-faint); padding: 1px 7px; flex: 0 0 auto; + border: 1px solid var(--glass-brd); border-radius: 999px; font-variant-numeric: tabular-nums; } + +.titlebar-status { display: flex; align-items: center; gap: 8px; margin-right: 8px; + -webkit-app-region: no-drag; } +.chip { display: inline-flex; align-items: center; gap: 6px; font-size: 11px; height: 24px; + padding: 0 11px; border-radius: 999px; border: 1px solid var(--glass-brd); + background: var(--glass-bg); color: var(--text-dim); font-weight: 500; white-space: nowrap; } +.chip .ic { width: 13px; height: 13px; } +.chip.elev { color: var(--good); + border-color: color-mix(in srgb, var(--good) 45%, transparent); + background: color-mix(in srgb, var(--good) 12%, transparent); } +.chip.engine .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--text-faint); } +.chip.engine.ok { color: var(--good); + border-color: color-mix(in srgb, var(--good) 30%, transparent); } +.chip.engine.ok .dot { background: var(--good); box-shadow: 0 0 8px var(--good); + animation: pulse 2.2s var(--ease) infinite; } +.chip.engine.err { color: var(--danger); } +.chip.engine.err .dot { background: var(--danger); box-shadow: 0 0 8px var(--danger); } +@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: .35; } } + +.titlebar-controls { display: flex; height: 100%; -webkit-app-region: no-drag; } +.win-btn { width: 46px; height: var(--titlebar-h); border: 0; background: transparent; + color: var(--text-dim); cursor: pointer; display: grid; place-items: center; + transition: background .15s, color .15s; } +.win-btn:hover { background: var(--glass-bg-2); color: var(--text); } +.win-btn.danger:hover { background: #e11d48; color: #fff; } + +/* ------------------------------------------------ Shell layout */ +.shell { position: relative; z-index: 2; display: flex; height: calc(100vh - var(--titlebar-h)); } + +.sidebar { + width: 84px; display: flex; flex-direction: column; align-items: center; gap: 6px; + padding: 14px 0 16px; margin: 0 0 14px 14px; border-radius: var(--radius); + background: var(--glass-bg); border: 1px solid var(--glass-brd); + backdrop-filter: blur(24px) saturate(160%); -webkit-backdrop-filter: blur(24px) saturate(160%); + box-shadow: var(--shadow); overflow: hidden auto; scrollbar-width: none; +} +.sidebar::-webkit-scrollbar { display: none; } +.nav-spacer { flex: 1 1 auto; min-height: 12px; } +.nav-item { + width: 62px; height: 56px; flex: 0 0 auto; display: flex; flex-direction: column; align-items: center; + justify-content: center; gap: 5px; border: 0; border-radius: 14px; cursor: pointer; + background: transparent; color: var(--text-dim); font-size: 10.5px; font-weight: 500; + transition: all .2s var(--ease); position: relative; +} +.nav-item .ic { width: 21px; height: 21px; } +.nav-item:hover { color: var(--text); background: var(--glass-bg); } +.nav-item.active { color: var(--text); background: var(--glass-bg-2); + box-shadow: inset 0 1px 0 var(--glass-hi); } +.nav-item.active::before { content: ""; position: absolute; left: -8px; top: 16px; bottom: 16px; + width: 3px; border-radius: 3px; background: var(--accent-grad); box-shadow: 0 0 10px var(--accent-a); } + +.content { flex: 1; overflow-y: auto; padding: 8px 22px 26px; scrollbar-width: thin; + scrollbar-color: var(--glass-brd) transparent; } +.content::-webkit-scrollbar { width: 10px; } +.content::-webkit-scrollbar-thumb { background: var(--glass-brd); border-radius: 10px; + border: 3px solid transparent; background-clip: content-box; } + +/* ------------------------------------------------ Views */ +.view { display: none; } +/* Animate transform ONLY. Animating opacity on a subtree that uses backdrop-filter + makes the glass panels render momentarily more transparent until opacity hits 1, + which showed up as a "flash" on view switch — so we slide, we don't fade. */ +.view.active { display: block; animation: viewIn .4s var(--ease); } +@keyframes viewIn { from { transform: translateY(12px); } to { transform: none; } } +@media (prefers-reduced-motion: reduce) { .view.active { animation: none; } } + +.view-head { display: flex; align-items: flex-end; justify-content: space-between; + padding: 14px 4px 20px; } + +/* ------------------------------------------------ Glass panels */ +.glass { + background: var(--glass-bg); border: 1px solid var(--glass-brd); border-radius: var(--radius); + backdrop-filter: blur(26px) saturate(165%); -webkit-backdrop-filter: blur(26px) saturate(165%); + box-shadow: var(--shadow); position: relative; overflow: hidden; +} +.glass::before { content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; + background: linear-gradient(160deg, var(--glass-hi), transparent 42%); opacity: .18; } + +/* ------------------------------------------------ Gauges */ +.gauges { display: grid; grid-template-columns: 1fr 1fr 1.1fr; gap: 16px; margin-bottom: 16px; } +.gauge-card { padding: 22px; display: flex; align-items: center; gap: 20px; } +.ring { position: relative; width: 156px; height: 156px; flex: 0 0 auto; } +.ring-svg { width: 100%; height: 100%; } +.ring-track { fill: none; stroke: var(--ring-track); stroke-width: 14; } +.ring-fill { fill: none; stroke-width: 14; stroke-linecap: round; + stroke-dasharray: 540; stroke-dashoffset: 540; + transition: stroke-dashoffset 1s var(--ease); filter: drop-shadow(0 0 6px color-mix(in srgb, var(--accent-a) 60%, transparent)); } +.ring-center { position: absolute; inset: 0; display: flex; flex-direction: column; + align-items: center; justify-content: center; } +.ring-pct { font-size: 34px; font-weight: 700; letter-spacing: -.03em; + font-variant-numeric: tabular-nums; } +.ring-pct::after { content: "%"; font-size: 15px; font-weight: 600; color: var(--text-dim); margin-left: 1px; } +.ring-pct.na::after { content: ""; } +.ring-label { font-size: 11px; color: var(--text-dim); text-transform: uppercase; letter-spacing: .08em; } +.gauge-meta h3 { margin-bottom: 12px; } +.meta-rows { display: flex; flex-direction: column; gap: 9px; } +.meta-rows > div { display: flex; justify-content: space-between; gap: 24px; font-size: 13px; } +.meta-rows .k { color: var(--text-dim); } +.meta-rows .v { font-weight: 600; font-variant-numeric: tabular-nums; } + +/* Sparkline */ +.spark-card { padding: 20px; display: flex; flex-direction: column; } +.spark-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 8px; } +.spark-now { font-size: 22px; font-weight: 700; font-variant-numeric: tabular-nums; } +.spark { flex: 1; width: 100%; height: 100%; min-height: 90px; } +.spark-line { fill: none; stroke: var(--accent-a); stroke-width: 2.5; + stroke-linejoin: round; stroke-linecap: round; filter: drop-shadow(0 0 5px var(--accent-a)); } + +/* ------------------------------------------------ Areas */ +.areas-card { padding: 22px; margin-bottom: 18px; } +.areas-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; margin-bottom: 16px; } +.areas-actions { display: flex; gap: 8px; } +.areas-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 10px; } +.area-chip { + display: flex; align-items: center; gap: 11px; padding: 13px 14px; border-radius: var(--radius-sm); + background: var(--glass-bg); border: 1px solid var(--glass-brd); cursor: pointer; + transition: all .18s var(--ease); text-align: left; +} +.area-chip:hover:not(.disabled) { background: var(--glass-bg-2); transform: translateY(-1px); } +.area-chip.disabled { opacity: .4; cursor: not-allowed; } +.area-box { width: 22px; height: 22px; border-radius: 7px; border: 1.5px solid var(--glass-brd); + display: grid; place-items: center; flex: 0 0 auto; transition: all .18s var(--ease); color: transparent; } +.area-chip.on .area-box { background: var(--accent-grad); border-color: transparent; color: #fff; + box-shadow: 0 0 14px -2px var(--accent-a); } +.area-box .ic { width: 14px; height: 14px; } +.area-name { font-size: 13px; font-weight: 550; } +.area-sub { font-size: 11px; color: var(--text-faint); } + +/* ------------------------------------------------ Optimize CTA */ +.cta-row { display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 6px 0 10px; } +.optimize-btn { + position: relative; width: min(440px, 80%); height: 62px; border: 0; border-radius: 999px; + cursor: pointer; color: #fff; font-size: 17px; font-weight: 650; letter-spacing: .01em; + background: var(--accent-grad); overflow: hidden; isolation: isolate; + box-shadow: 0 16px 40px -12px var(--accent-a), inset 0 1px 0 rgba(255,255,255,.4); + transition: transform .15s var(--ease), filter .2s; +} +.optimize-btn:hover { transform: translateY(-2px); filter: brightness(1.06); } +.optimize-btn:active { transform: translateY(0) scale(.99); } +.optimize-btn:disabled { cursor: default; filter: grayscale(.2) brightness(.85); transform: none; } +.opt-glow { position: absolute; inset: -40%; background: conic-gradient(from 0deg, transparent, rgba(255,255,255,.55), transparent 30%); + animation: spin 4s linear infinite; opacity: 0; transition: opacity .3s; z-index: -1; } +.optimize-btn.running .opt-glow { opacity: .5; } +@keyframes spin { to { transform: rotate(360deg); } } +.opt-fill { position: absolute; left: 0; top: 0; bottom: 0; width: 0%; background: rgba(255,255,255,.18); + z-index: -1; transition: width .3s var(--ease); } +.opt-label { display: inline-flex; align-items: center; gap: 9px; } +.opt-label .ic { width: 20px; height: 20px; } +.optimize-btn.running .opt-label .ic { animation: spin 1.6s linear infinite; } +.cta-hint { font-size: 12px; color: var(--text-faint); font-variant-numeric: tabular-nums; } + +/* ------------------------------------------------ Buttons & inputs */ +.ghost-btn, .primary-btn { + border-radius: 10px; padding: 9px 15px; font-size: 13px; font-weight: 550; cursor: pointer; + transition: all .16s var(--ease); border: 1px solid var(--glass-brd); +} +.ghost-btn { background: var(--glass-bg); color: var(--text-dim); } +.ghost-btn:hover { background: var(--glass-bg-2); color: var(--text); } +.primary-btn { background: var(--accent-grad); color: #fff; border-color: transparent; + box-shadow: 0 8px 20px -10px var(--accent-a); } +.primary-btn:hover { filter: brightness(1.07); transform: translateY(-1px); } + +.input { background: var(--glass-bg); border: 1px solid var(--glass-brd); color: var(--text); + border-radius: 10px; padding: 9px 12px; font-size: 13px; font-family: inherit; outline: none; + transition: border-color .16s; } +.input:focus { border-color: var(--accent-a); } +.input.small { padding: 6px 10px; } +select.input { cursor: pointer; } +option { background: var(--bg-1); color: var(--text); } + +.theme-toggle { width: 40px; height: 40px; border-radius: 12px; border: 1px solid var(--glass-brd); + background: var(--glass-bg); color: var(--text-dim); cursor: pointer; transition: all .18s; } +.theme-toggle:hover { color: var(--text); background: var(--glass-bg-2); transform: rotate(-15deg); } + +/* ------------------------------------------------ Setting blocks */ +.setting-block { padding: 22px; margin-bottom: 16px; } +.block-title { margin-bottom: 16px; color: var(--text-dim); text-transform: uppercase; + font-size: 11px; letter-spacing: .1em; } +.sb-row { display: flex; align-items: center; justify-content: space-between; gap: 24px; } +.range-wrap { display: flex; align-items: center; gap: 14px; min-width: 260px; } +.range-wrap output { font-variant-numeric: tabular-nums; font-weight: 650; min-width: 58px; + text-align: right; font-size: 14px; } +input[type="range"] { -webkit-appearance: none; appearance: none; width: 200px; height: 6px; + border-radius: 999px; background: var(--ring-track); cursor: pointer; } +input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; width: 18px; height: 18px; + border-radius: 50%; background: #fff; box-shadow: 0 2px 8px rgba(0,0,0,.4), 0 0 0 4px color-mix(in srgb, var(--accent-a) 45%, transparent); } +.hint-note { display: flex; align-items: center; gap: 8px; margin-top: 14px; font-size: 12px; + color: var(--text-faint); } +.hint-note.warn { color: var(--warn); } + +.toggle-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 24px; } +.toggle-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; + padding: 8px 0; } +.toggle-row .label { font-size: 13.5px; } +.switch { --w: 44px; --h: 26px; position: relative; width: var(--w); height: var(--h); flex: 0 0 auto; } +.switch input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; } +.switch .track { position: absolute; inset: 0; border-radius: 999px; background: var(--ring-track); + border: 1px solid var(--glass-brd); transition: background .2s var(--ease); } +.switch .thumb { position: absolute; top: 3px; left: 3px; width: 20px; height: 20px; border-radius: 50%; + background: #fff; box-shadow: 0 2px 6px rgba(0,0,0,.35); transition: transform .22s var(--ease); } +.switch input:checked ~ .track { background: var(--accent-grad); border-color: transparent; } +.switch input:checked ~ .thumb { transform: translateX(18px); } + +.hotkey-row { display: flex; align-items: center; justify-content: space-between; gap: 20px; flex-wrap: wrap; } +.hotkey-fields { display: flex; align-items: center; gap: 12px; } +.chk, .mini { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; cursor: pointer; } +.mini { font-size: 12px; color: var(--text-dim); } + +.appearance-row { display: flex; align-items: center; gap: 30px; flex-wrap: wrap; } +.seg { display: inline-flex; padding: 4px; border-radius: 12px; background: var(--glass-bg); + border: 1px solid var(--glass-brd); } +.seg button { border: 0; background: transparent; color: var(--text-dim); padding: 7px 18px; + border-radius: 9px; cursor: pointer; font-size: 13px; font-weight: 550; transition: all .18s; } +.seg button.active { background: var(--accent-grad); color: #fff; } +.field { display: flex; flex-direction: column; gap: 6px; font-size: 12px; color: var(--text-dim); } + +/* ------------------------------------------------ Processes */ +.proc-add { display: flex; gap: 10px; padding: 20px; align-items: center; } +.proc-add .input { flex: 1; } +.proc-list { padding: 0 20px 20px; display: flex; flex-direction: column; gap: 8px; max-height: 44vh; overflow-y: auto; } +.proc-item { display: flex; align-items: center; justify-content: space-between; padding: 11px 14px; + border-radius: var(--radius-sm); background: var(--glass-bg); border: 1px solid var(--glass-brd); font-size: 13px; } +.proc-item button { border: 0; background: transparent; color: var(--text-faint); cursor: pointer; + padding: 4px; border-radius: 6px; transition: color .15s; } +.proc-item button:hover { color: var(--danger); } +.proc-empty { text-align: center; color: var(--text-faint); padding: 30px; font-size: 13px; } + +/* ------------------------------------------------ About */ +.about-card { padding: 30px; max-width: 620px; } +.about-logo { margin-bottom: 18px; } +.about-card p { color: var(--text-dim); line-height: 1.6; font-size: 14px; margin-bottom: 18px; } +.about-facts { list-style: none; display: grid; grid-template-columns: 1fr 1fr; gap: 8px 20px; margin-bottom: 22px; } +.about-facts li { display: flex; justify-content: space-between; font-size: 12.5px; padding: 6px 0; + border-bottom: 1px solid var(--glass-brd); } +.about-facts .k { color: var(--text-faint); } +.about-links { display: flex; gap: 10px; } + +/* ------------------------------------------------ Toasts */ +.toast-host { position: fixed; right: 20px; bottom: 20px; z-index: 50; display: flex; + flex-direction: column; gap: 10px; align-items: flex-end; } +.toast { min-width: 260px; max-width: 380px; padding: 14px 16px; border-radius: 14px; + background: var(--glass-bg-2); border: 1px solid var(--glass-brd); + backdrop-filter: blur(24px) saturate(160%); -webkit-backdrop-filter: blur(24px) saturate(160%); + box-shadow: var(--shadow); animation: toastIn .4s var(--ease); } +.toast.out { animation: toastOut .35s var(--ease) forwards; } +.toast .t-title { font-size: 13px; font-weight: 650; display: flex; align-items: center; gap: 8px; } +.toast .t-title .ic { color: var(--good); } +.toast.err .t-title .ic { color: var(--danger); } +.toast .t-body { font-size: 12.5px; color: var(--text-dim); margin-top: 5px; line-height: 1.5; + white-space: pre-line; font-variant-numeric: tabular-nums; } +@keyframes toastIn { from { opacity: 0; transform: translateX(30px) scale(.96); } to { opacity: 1; transform: none; } } +@keyframes toastOut { to { opacity: 0; transform: translateX(30px) scale(.96); } } + +/* Responsive collapse */ +@media (max-width: 980px) { + .gauges { grid-template-columns: 1fr 1fr; } + .spark-card { grid-column: span 2; } + .toggle-grid { grid-template-columns: 1fr; } +}