diff --git a/codexbar-electron/.gitignore b/codexbar-electron/.gitignore new file mode 100644 index 00000000..60278539 --- /dev/null +++ b/codexbar-electron/.gitignore @@ -0,0 +1,6 @@ +node_modules/ +dist/ +release/ +*.log +.env +.env.local diff --git a/codexbar-electron/README.md b/codexbar-electron/README.md new file mode 100644 index 00000000..d0e11f09 --- /dev/null +++ b/codexbar-electron/README.md @@ -0,0 +1,159 @@ +# CodexBar for Windows/Linux + +This is the cross-platform port of [CodexBar](https://github.com/steipete/CodexBar), originally a macOS menu bar app for monitoring AI provider API usage. + +## Features + +- **System tray app** with usage menu (like macOS menu bar) +- **12 AI providers** supported: + - Codex (OpenAI) + - Claude (Anthropic) + - Cursor + - Gemini (Google) + - GitHub Copilot + - Antigravity + - Factory/Droid + - z.ai + - Kiro + - Vertex AI + - Augment + - MiniMax +- **Usage meters** with session + weekly + monthly tracking +- **Settings window** for provider toggles and preferences +- **Auto-updates** via electron-updater +- **CLI** for terminal usage + +## Installation + +### Download + +Download the latest release from [GitHub Releases](https://github.com/steipete/CodexBar/releases). + +- **Windows**: Download `CodexBar-Setup-x.x.x.exe` (installer) or `CodexBar-x.x.x-portable.exe` +- **Linux**: Download `CodexBar-x.x.x.AppImage` or `CodexBar-x.x.x.deb` + +### Build from Source + +```bash +cd codexbar-electron + +# Install dependencies +npm install + +# Development mode +npm run dev + +# Build for production +npm run build + +# Package for distribution +npm run dist:win # Windows +npm run dist:linux # Linux +``` + +## Development + +### Prerequisites + +- Node.js 18+ +- npm 9+ + +### Project Structure + +``` +codexbar-electron/ +├── src/ +│ ├── main/ # Electron main process +│ │ ├── providers/ # AI provider implementations +│ │ ├── store/ # Settings & usage persistence +│ │ ├── tray/ # System tray menu +│ │ └── utils/ # Utilities (logger, subprocess) +│ ├── renderer/ # React UI (settings window) +│ ├── cli/ # Command-line interface +│ └── shared/ # Shared types +├── assets/ # Icons and images +├── dist/ # Build output +└── release/ # Packaged apps +``` + +### Scripts + +```bash +npm run dev # Start in development mode +npm run build # Build TypeScript +npm run start # Run built app +npm run dist # Package for current platform +npm run lint # Run ESLint +npm run typecheck # TypeScript check +npm run test # Run tests +``` + +### Adding a New Provider + +1. Create a new directory under `src/main/providers//` +2. Create `Provider.ts` extending `BaseProvider` +3. Implement `isConfigured()` and `fetchUsage()` +4. Register in `ProviderManager.ts` + +Example: + +```typescript +import { BaseProvider, ProviderUsage } from '../BaseProvider'; + +export class NewProvider extends BaseProvider { + readonly id = 'newprovider'; + readonly name = 'New Provider'; + readonly icon = '🆕'; + readonly websiteUrl = 'https://newprovider.ai'; + + async isConfigured(): Promise { + // Check if provider is set up + return true; + } + + async fetchUsage(): Promise { + // Fetch and return usage data + return null; + } +} +``` + +## CLI Usage + +```bash +# Show status for all providers +codexbar status + +# Show status for specific provider +codexbar status -p claude + +# Output as JSON +codexbar status -j + +# List all providers +codexbar list + +# Refresh data +codexbar refresh +``` + +## Architecture + +This port uses: + +- **Electron** - Cross-platform desktop framework +- **React** - Settings UI +- **TypeScript** - Type safety +- **electron-store** - Settings persistence +- **electron-updater** - Auto-updates +- **winston** - Logging + +The architecture mirrors the macOS app: +- Provider-based design for extensibility +- Background polling for usage updates +- System tray integration +- IPC for main/renderer communication + +## License + +MIT License - see [LICENSE](../LICENSE) diff --git a/codexbar-electron/assets/icon.png b/codexbar-electron/assets/icon.png new file mode 100644 index 00000000..5bd6ce5a Binary files /dev/null and b/codexbar-electron/assets/icon.png differ diff --git a/codexbar-electron/package.json b/codexbar-electron/package.json new file mode 100644 index 00000000..5d81d79e --- /dev/null +++ b/codexbar-electron/package.json @@ -0,0 +1,99 @@ +{ + "name": "codexbar", + "version": "0.1.0", + "description": "Monitor API usage limits for AI providers - Windows/Linux port", + "main": "dist/main/index.js", + "author": "CodexBar Contributors", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/steipete/CodexBar" + }, + "pnpm": { + "onlyBuiltDependencies": [ + "electron", + "esbuild", + "keytar", + "node-pty" + ] + }, + "scripts": { + "dev": "concurrently \"npm run dev:main\" \"npm run dev:renderer\"", + "dev:main": "tsc -p tsconfig.main.json --watch", + "dev:renderer": "vite", + "build": "npm run build:main && npm run build:renderer", + "build:main": "tsc -p tsconfig.main.json", + "build:renderer": "vite build", + "start": "electron .", + "pack": "electron-builder --dir", + "dist": "electron-builder", + "dist:win": "electron-builder --win", + "dist:linux": "electron-builder --linux", + "dist:mac": "electron-builder --mac", + "lint": "eslint src --ext .ts,.tsx", + "typecheck": "tsc --noEmit", + "test": "vitest", + "cli": "node dist/cli/index.js" + }, + "dependencies": { + "electron-store": "^8.1.0", + "electron-updater": "^6.1.7", + "node-fetch": "^3.3.2", + "keytar": "^7.9.0", + "tough-cookie": "^4.1.3", + "winston": "^3.11.0", + "commander": "^11.1.0", + "node-pty": "^1.0.0" + }, + "devDependencies": { + "@types/node": "^20.10.0", + "@types/react": "^18.2.45", + "@types/react-dom": "^18.2.18", + "@types/tough-cookie": "^4.0.5", + "@typescript-eslint/eslint-plugin": "^6.14.0", + "@typescript-eslint/parser": "^6.14.0", + "@vitejs/plugin-react": "^4.2.1", + "concurrently": "^8.2.2", + "electron": "^28.0.0", + "electron-builder": "^24.9.1", + "eslint": "^8.56.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "typescript": "^5.3.3", + "vite": "^5.0.10", + "vitest": "^1.1.0" + }, + "build": { + "appId": "com.codexbar.app", + "productName": "CodexBar", + "directories": { + "output": "release" + }, + "files": [ + "dist/**/*", + "assets/**/*" + ], + "win": { + "target": ["nsis", "portable"], + "icon": "assets/icon.ico" + }, + "linux": { + "target": ["AppImage", "deb"], + "icon": "assets/icon.png", + "category": "Utility" + }, + "mac": { + "target": ["dmg"], + "icon": "assets/icon.icns" + }, + "nsis": { + "oneClick": false, + "allowToChangeInstallationDirectory": true + }, + "publish": { + "provider": "github", + "owner": "steipete", + "repo": "CodexBar" + } + } +} diff --git a/codexbar-electron/pnpm-lock.yaml b/codexbar-electron/pnpm-lock.yaml new file mode 100644 index 00000000..05821dcb --- /dev/null +++ b/codexbar-electron/pnpm-lock.yaml @@ -0,0 +1,5225 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + commander: + specifier: ^11.1.0 + version: 11.1.0 + electron-store: + specifier: ^8.1.0 + version: 8.2.0 + electron-updater: + specifier: ^6.1.7 + version: 6.7.3 + keytar: + specifier: ^7.9.0 + version: 7.9.0 + node-fetch: + specifier: ^3.3.2 + version: 3.3.2 + node-pty: + specifier: ^1.0.0 + version: 1.1.0 + tough-cookie: + specifier: ^4.1.3 + version: 4.1.4 + winston: + specifier: ^3.11.0 + version: 3.19.0 + devDependencies: + '@types/node': + specifier: ^20.10.0 + version: 20.19.27 + '@types/react': + specifier: ^18.2.45 + version: 18.3.27 + '@types/react-dom': + specifier: ^18.2.18 + version: 18.3.7(@types/react@18.3.27) + '@types/tough-cookie': + specifier: ^4.0.5 + version: 4.0.5 + '@typescript-eslint/eslint-plugin': + specifier: ^6.14.0 + version: 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/parser': + specifier: ^6.14.0 + version: 6.21.0(eslint@8.57.1)(typescript@5.9.3) + '@vitejs/plugin-react': + specifier: ^4.2.1 + version: 4.7.0(vite@5.4.21(@types/node@20.19.27)) + concurrently: + specifier: ^8.2.2 + version: 8.2.2 + electron: + specifier: ^28.0.0 + version: 28.3.3 + electron-builder: + specifier: ^24.9.1 + version: 24.13.3(electron-builder-squirrel-windows@24.13.3) + eslint: + specifier: ^8.56.0 + version: 8.57.1 + react: + specifier: ^18.2.0 + version: 18.3.1 + react-dom: + specifier: ^18.2.0 + version: 18.3.1(react@18.3.1) + typescript: + specifier: ^5.3.3 + version: 5.9.3 + vite: + specifier: ^5.0.10 + version: 5.4.21(@types/node@20.19.27) + vitest: + specifier: ^1.1.0 + version: 1.6.1(@types/node@20.19.27) + +packages: + + 7zip-bin@5.2.0: + resolution: {integrity: sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==} + + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.28.5': + resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.28.5': + resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.28.5': + resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.27.2': + resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.27.1': + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.28.3': + resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.27.1': + resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.28.4': + resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.28.5': + resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-transform-react-jsx-self@7.27.1': + resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.27.1': + resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/runtime@7.28.4': + resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.28.5': + resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.28.5': + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + engines: {node: '>=6.9.0'} + + '@colors/colors@1.6.0': + resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==} + engines: {node: '>=0.1.90'} + + '@dabh/diagnostics@2.0.8': + resolution: {integrity: sha512-R4MSXTVnuMzGD7bzHdW2ZhhdPC/igELENcq5IjEverBvq5hn1SXCWcsi6eSsdWP0/Ur+SItRRjAktmdoX/8R/Q==} + + '@develar/schema-utils@2.6.5': + resolution: {integrity: sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==} + engines: {node: '>= 8.9.0'} + + '@electron/asar@3.4.1': + resolution: {integrity: sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==} + engines: {node: '>=10.12.0'} + hasBin: true + + '@electron/get@2.0.3': + resolution: {integrity: sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==} + engines: {node: '>=12'} + + '@electron/notarize@2.2.1': + resolution: {integrity: sha512-aL+bFMIkpR0cmmj5Zgy0LMKEpgy43/hw5zadEArgmAMWWlKc5buwFvFT9G/o/YJkvXAJm5q3iuTuLaiaXW39sg==} + engines: {node: '>= 10.0.0'} + + '@electron/osx-sign@1.0.5': + resolution: {integrity: sha512-k9ZzUQtamSoweGQDV2jILiRIHUu7lYlJ3c6IEmjv1hC17rclE+eb9U+f6UFlOOETo0JzY1HNlXy4YOlCvl+Lww==} + engines: {node: '>=12.0.0'} + hasBin: true + + '@electron/universal@1.5.1': + resolution: {integrity: sha512-kbgXxyEauPJiQQUNG2VgUeyfQNFk6hBF11ISN2PNI6agUgPl55pv4eQmaqHzTAzchBvqZ2tQuRVaPStGf0mxGw==} + engines: {node: '>=8.6'} + + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/eslintrc@2.1.4': + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@eslint/js@8.57.1': + resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@humanwhocodes/config-array@0.13.0': + resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} + engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/object-schema@2.0.3': + resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + deprecated: Use @eslint/object-schema instead + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@jest/schemas@29.6.3': + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@malept/cross-spawn-promise@1.1.1': + resolution: {integrity: sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ==} + engines: {node: '>= 10'} + + '@malept/flatpak-bundler@0.4.0': + resolution: {integrity: sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==} + engines: {node: '>= 10.0.0'} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@rolldown/pluginutils@1.0.0-beta.27': + resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} + + '@rollup/rollup-android-arm-eabi@4.55.1': + resolution: {integrity: sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.55.1': + resolution: {integrity: sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.55.1': + resolution: {integrity: sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.55.1': + resolution: {integrity: sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.55.1': + resolution: {integrity: sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.55.1': + resolution: {integrity: sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.55.1': + resolution: {integrity: sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.55.1': + resolution: {integrity: sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.55.1': + resolution: {integrity: sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.55.1': + resolution: {integrity: sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.55.1': + resolution: {integrity: sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-loong64-musl@4.55.1': + resolution: {integrity: sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.55.1': + resolution: {integrity: sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-ppc64-musl@4.55.1': + resolution: {integrity: sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.55.1': + resolution: {integrity: sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.55.1': + resolution: {integrity: sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.55.1': + resolution: {integrity: sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.55.1': + resolution: {integrity: sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.55.1': + resolution: {integrity: sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openbsd-x64@4.55.1': + resolution: {integrity: sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.55.1': + resolution: {integrity: sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.55.1': + resolution: {integrity: sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.55.1': + resolution: {integrity: sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.55.1': + resolution: {integrity: sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.55.1': + resolution: {integrity: sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==} + cpu: [x64] + os: [win32] + + '@sinclair/typebox@0.27.8': + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + + '@sindresorhus/is@4.6.0': + resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} + engines: {node: '>=10'} + + '@so-ric/colorspace@1.1.6': + resolution: {integrity: sha512-/KiKkpHNOBgkFJwu9sh48LkHSMYGyuTcSFK/qMBdnOAlrRJzRSXAOFB5qwzaVQuDl8wAvHVMkaASQDReTahxuw==} + + '@szmarczak/http-timer@4.0.6': + resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} + engines: {node: '>=10'} + + '@tootallnate/once@2.0.0': + resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} + engines: {node: '>= 10'} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + + '@types/cacheable-request@6.0.3': + resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} + + '@types/debug@4.1.12': + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/fs-extra@9.0.13': + resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} + + '@types/http-cache-semantics@4.0.4': + resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/keyv@3.1.4': + resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/node@18.19.130': + resolution: {integrity: sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==} + + '@types/node@20.19.27': + resolution: {integrity: sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==} + + '@types/plist@3.0.5': + resolution: {integrity: sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==} + + '@types/prop-types@15.7.15': + resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} + + '@types/react-dom@18.3.7': + resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==} + peerDependencies: + '@types/react': ^18.0.0 + + '@types/react@18.3.27': + resolution: {integrity: sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==} + + '@types/responselike@1.0.3': + resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} + + '@types/semver@7.7.1': + resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==} + + '@types/tough-cookie@4.0.5': + resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} + + '@types/triple-beam@1.3.5': + resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==} + + '@types/verror@1.10.11': + resolution: {integrity: sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==} + + '@types/yauzl@2.10.3': + resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} + + '@typescript-eslint/eslint-plugin@6.21.0': + resolution: {integrity: sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/parser@6.21.0': + resolution: {integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/scope-manager@6.21.0': + resolution: {integrity: sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==} + engines: {node: ^16.0.0 || >=18.0.0} + + '@typescript-eslint/type-utils@6.21.0': + resolution: {integrity: sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/types@6.21.0': + resolution: {integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==} + engines: {node: ^16.0.0 || >=18.0.0} + + '@typescript-eslint/typescript-estree@6.21.0': + resolution: {integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/utils@6.21.0': + resolution: {integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + + '@typescript-eslint/visitor-keys@6.21.0': + resolution: {integrity: sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==} + engines: {node: ^16.0.0 || >=18.0.0} + + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + + '@vitejs/plugin-react@4.7.0': + resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + + '@vitest/expect@1.6.1': + resolution: {integrity: sha512-jXL+9+ZNIJKruofqXuuTClf44eSpcHlgj3CiuNihUF3Ioujtmc0zIa3UJOW5RjDK1YLBJZnWBlPuqhYycLioog==} + + '@vitest/runner@1.6.1': + resolution: {integrity: sha512-3nSnYXkVkf3mXFfE7vVyPmi3Sazhb/2cfZGGs0JRzFsPFvAMBEcrweV1V1GsrstdXeKCTXlJbvnQwGWgEIHmOA==} + + '@vitest/snapshot@1.6.1': + resolution: {integrity: sha512-WvidQuWAzU2p95u8GAKlRMqMyN1yOJkGHnx3M1PL9Raf7AQ1kwLKg04ADlCa3+OXUZE7BceOhVZiuWAbzCKcUQ==} + + '@vitest/spy@1.6.1': + resolution: {integrity: sha512-MGcMmpGkZebsMZhbQKkAf9CX5zGvjkBTqf8Zx3ApYWXr3wG+QvEu2eXWfnIIWYSJExIp4V9FCKDEeygzkYrXMw==} + + '@vitest/utils@1.6.1': + resolution: {integrity: sha512-jOrrUvXM4Av9ZWiG1EajNto0u96kWAhJ1LmPmJhXXQx/32MecEKd10pOLYgS2BQx1TgkGhloPU1ArDW2vvaY6g==} + + '@xmldom/xmldom@0.8.11': + resolution: {integrity: sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==} + engines: {node: '>=10.0.0'} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn-walk@8.3.4: + resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} + engines: {node: '>=0.4.0'} + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + + ajv-formats@2.1.1: + resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv-keywords@3.5.2: + resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==} + peerDependencies: + ajv: ^6.9.1 + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ajv@8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + + app-builder-bin@4.0.0: + resolution: {integrity: sha512-xwdG0FJPQMe0M0UA4Tz0zEB8rBJTRA5a476ZawAqiBkMv16GRK5xpXThOjMaEOFnZ6zabejjG4J3da0SXG63KA==} + + app-builder-lib@24.13.3: + resolution: {integrity: sha512-FAzX6IBit2POXYGnTCT8YHFO/lr5AapAII6zzhQO3Rw4cEDOgK+t1xhLc5tNcKlicTHlo9zxIwnYCX9X2DLkig==} + engines: {node: '>=14.0.0'} + peerDependencies: + dmg-builder: 24.13.3 + electron-builder-squirrel-windows: 24.13.3 + + archiver-utils@2.1.0: + resolution: {integrity: sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==} + engines: {node: '>= 6'} + + archiver-utils@3.0.4: + resolution: {integrity: sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==} + engines: {node: '>= 10'} + + archiver@5.3.2: + resolution: {integrity: sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==} + engines: {node: '>= 10'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + assert-plus@1.0.0: + resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} + engines: {node: '>=0.8'} + + assertion-error@1.1.0: + resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + + astral-regex@2.0.0: + resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} + engines: {node: '>=8'} + + async-exit-hook@2.0.1: + resolution: {integrity: sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==} + engines: {node: '>=0.12.0'} + + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + at-least-node@1.0.0: + resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} + engines: {node: '>= 4.0.0'} + + atomically@1.7.0: + resolution: {integrity: sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==} + engines: {node: '>=10.12.0'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + baseline-browser-mapping@2.9.13: + resolution: {integrity: sha512-WhtvB2NG2wjr04+h77sg3klAIwrgOqnjS49GGudnUPGFFgg7G17y7Qecqp+2Dr5kUDxNRBca0SK7cG8JwzkWDQ==} + hasBin: true + + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + + bluebird-lst@1.0.9: + resolution: {integrity: sha512-7B1Rtx82hjnSD4PGLAjVWeYH3tHAcVUmChh85a3lltKQm6FresXh9ErQo6oAv6CqxttczC3/kEg8SY5NluPuUw==} + + bluebird@3.7.2: + resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + + boolean@3.2.0: + resolution: {integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.28.1: + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + + buffer-equal@1.0.1: + resolution: {integrity: sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg==} + engines: {node: '>=0.4'} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + + builder-util-runtime@9.2.4: + resolution: {integrity: sha512-upp+biKpN/XZMLim7aguUyW8s0FUpDvOtK6sbanMFDAMBzpHDqdhgVYm6zc9HJ6nWo7u2Lxk60i2M6Jd3aiNrA==} + engines: {node: '>=12.0.0'} + + builder-util-runtime@9.5.1: + resolution: {integrity: sha512-qt41tMfgHTllhResqM5DcnHyDIWNgzHvuY2jDcYP9iaGpkWxTUzV6GQjDeLnlR1/DtdlcsWQbA7sByMpmJFTLQ==} + engines: {node: '>=12.0.0'} + + builder-util@24.13.1: + resolution: {integrity: sha512-NhbCSIntruNDTOVI9fdXz0dihaqX2YuE1D6zZMrwiErzH4ELZHE6mdiB40wEgZNprDia+FghRFgKoAqMZRRjSA==} + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + cacheable-lookup@5.0.4: + resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==} + engines: {node: '>=10.6.0'} + + cacheable-request@7.0.4: + resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==} + engines: {node: '>=8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + caniuse-lite@1.0.30001763: + resolution: {integrity: sha512-mh/dGtq56uN98LlNX9qdbKnzINhX0QzhiWBFEkFfsFO4QyCvL8YegrJAazCwXIeqkIob8BlZPGM3xdnY+sgmvQ==} + + chai@4.5.0: + resolution: {integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==} + engines: {node: '>=4'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + check-error@1.0.3: + resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} + + chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + + chownr@2.0.0: + resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} + engines: {node: '>=10'} + + chromium-pickle-js@0.2.0: + resolution: {integrity: sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==} + + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + + cli-truncate@2.1.0: + resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} + engines: {node: '>=8'} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + clone-response@1.0.3: + resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-convert@3.1.3: + resolution: {integrity: sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==} + engines: {node: '>=14.6'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + color-name@2.1.0: + resolution: {integrity: sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==} + engines: {node: '>=12.20'} + + color-string@2.1.4: + resolution: {integrity: sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==} + engines: {node: '>=18'} + + color@5.0.3: + resolution: {integrity: sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA==} + engines: {node: '>=18'} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + + commander@5.1.0: + resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} + engines: {node: '>= 6'} + + compare-version@0.1.2: + resolution: {integrity: sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==} + engines: {node: '>=0.10.0'} + + compress-commons@4.1.2: + resolution: {integrity: sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==} + engines: {node: '>= 10'} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + concurrently@8.2.2: + resolution: {integrity: sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==} + engines: {node: ^14.13.0 || >=16.0.0} + hasBin: true + + conf@10.2.0: + resolution: {integrity: sha512-8fLl9F04EJqjSqH+QjITQfJF8BrOVaYr1jewVgSRAEWePfxT0sku4w2hrGQ60BC/TNLGQ2pgxNlTbWQmMPFvXg==} + engines: {node: '>=12'} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + config-file-ts@0.2.6: + resolution: {integrity: sha512-6boGVaglwblBgJqGyxm4+xCmEGcWgnWHSWHY5jad58awQhB6gftq0G8HbzU39YqCIYHMLAiL1yjwiZ36m/CL8w==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + core-util-is@1.0.2: + resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} + + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + + crc32-stream@4.0.3: + resolution: {integrity: sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==} + engines: {node: '>= 10'} + + crc@3.8.0: + resolution: {integrity: sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + + date-fns@2.30.0: + resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} + engines: {node: '>=0.11'} + + debounce-fn@4.0.0: + resolution: {integrity: sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ==} + engines: {node: '>=10'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + + deep-eql@4.1.4: + resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==} + engines: {node: '>=6'} + + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + defer-to-connect@2.0.1: + resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} + engines: {node: '>=10'} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + detect-node@2.1.0: + resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} + + diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + dir-compare@3.3.0: + resolution: {integrity: sha512-J7/et3WlGUCxjdnD3HAAzQ6nsnc0WL6DD7WcwJb7c39iH1+AWfg+9OqzJNaI6PkBwBvm1mhZNL9iY/nRiZXlPg==} + + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + dmg-builder@24.13.3: + resolution: {integrity: sha512-rcJUkMfnJpfCboZoOOPf4L29TRtEieHNOeAbYPWPxlaBw/Z1RKrRA86dOI9rwaI4tQSc/RD82zTNHprfUHXsoQ==} + + dmg-license@1.0.11: + resolution: {integrity: sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==} + engines: {node: '>=8'} + os: [darwin] + hasBin: true + + doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + + dot-prop@6.0.1: + resolution: {integrity: sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==} + engines: {node: '>=10'} + + dotenv-expand@5.1.0: + resolution: {integrity: sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==} + + dotenv@9.0.2: + resolution: {integrity: sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==} + engines: {node: '>=10'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + ejs@3.1.10: + resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} + engines: {node: '>=0.10.0'} + hasBin: true + + electron-builder-squirrel-windows@24.13.3: + resolution: {integrity: sha512-oHkV0iogWfyK+ah9ZIvMDpei1m9ZRpdXcvde1wTpra2U8AFDNNpqJdnin5z+PM1GbQ5BoaKCWas2HSjtR0HwMg==} + + electron-builder@24.13.3: + resolution: {integrity: sha512-yZSgVHft5dNVlo31qmJAe4BVKQfFdwpRw7sFp1iQglDRCDD6r22zfRJuZlhtB5gp9FHUxCMEoWGq10SkCnMAIg==} + engines: {node: '>=14.0.0'} + hasBin: true + + electron-publish@24.13.1: + resolution: {integrity: sha512-2ZgdEqJ8e9D17Hwp5LEq5mLQPjqU3lv/IALvgp+4W8VeNhryfGhYEQC/PgDPMrnWUp+l60Ou5SJLsu+k4mhQ8A==} + + electron-store@8.2.0: + resolution: {integrity: sha512-ukLL5Bevdil6oieAOXz3CMy+OgaItMiVBg701MNlG6W5RaC0AHN7rvlqTCmeb6O7jP0Qa1KKYTE0xV0xbhF4Hw==} + + electron-to-chromium@1.5.267: + resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} + + electron-updater@6.7.3: + resolution: {integrity: sha512-EgkT8Z9noqXKbwc3u5FkJA+r48jwZ5DTUiOkJMOTEEH//n5Am6wfQGz7nvSFEA2oIAMv9jRzn5JKTyWeSKOPgg==} + + electron@28.3.3: + resolution: {integrity: sha512-ObKMLSPNhomtCOBAxFS8P2DW/4umkh72ouZUlUKzXGtYuPzgr1SYhskhFWgzAsPtUzhL2CzyV2sfbHcEW4CXqw==} + engines: {node: '>= 12.20.55'} + hasBin: true + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + enabled@2.0.0: + resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==} + + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + + env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + + err-code@2.0.3: + resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + es6-error@4.1.1: + resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} + + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint@8.57.1: + resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + hasBin: true + + espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + + expand-template@2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} + + extract-zip@2.0.1: + resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} + engines: {node: '>= 10.17.0'} + hasBin: true + + extsprintf@1.4.1: + resolution: {integrity: sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==} + engines: {'0': node >=0.6.0} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + + fd-slicer@1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + + fecha@4.2.3: + resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==} + + fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + + file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + + filelist@1.0.4: + resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@3.0.0: + resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} + engines: {node: '>=6'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} + + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + + fn.name@1.1.0: + resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==} + + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + engines: {node: '>= 6'} + + formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + + fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + + fs-extra@8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + + fs-extra@9.1.0: + resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} + engines: {node: '>=10'} + + fs-minipass@2.1.0: + resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} + engines: {node: '>= 8'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-func-name@2.0.2: + resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + + get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + + github-from-package@0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob@10.5.0: + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + hasBin: true + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + + global-agent@3.0.0: + resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==} + engines: {node: '>=10.0'} + + globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + engines: {node: '>=8'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + got@11.8.6: + resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} + engines: {node: '>=10.19.0'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + hosted-git-info@4.1.0: + resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} + engines: {node: '>=10'} + + http-cache-semantics@4.2.0: + resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} + + http-proxy-agent@5.0.0: + resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} + engines: {node: '>= 6'} + + http2-wrapper@1.0.3: + resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} + engines: {node: '>=10.19.0'} + + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + + human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + + iconv-corefoundation@1.1.7: + resolution: {integrity: sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==} + engines: {node: ^8.11.2 || >=10} + os: [darwin] + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inflight@1.0.6: + resolution: {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. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + + is-ci@3.0.1: + resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} + hasBin: true + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-obj@2.0.0: + resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} + engines: {node: '>=8'} + + is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + + isbinaryfile@4.0.10: + resolution: {integrity: sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==} + engines: {node: '>= 8.0.0'} + + isbinaryfile@5.0.7: + resolution: {integrity: sha512-gnWD14Jh3FzS3CPhF0AxNOJ8CxqeblPTADzI38r0wt8ZyQl5edpy75myt08EG2oKvpyiqSqsx+Wkz9vtkbTqYQ==} + engines: {node: '>= 18.0.0'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + jake@10.9.4: + resolution: {integrity: sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==} + engines: {node: '>=10'} + hasBin: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-tokens@9.0.1: + resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-schema-typed@7.0.3: + resolution: {integrity: sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonfile@4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + + jsonfile@6.2.0: + resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} + + keytar@7.9.0: + resolution: {integrity: sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + kuler@2.0.0: + resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==} + + lazy-val@1.0.5: + resolution: {integrity: sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==} + + lazystream@1.0.1: + resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} + engines: {node: '>= 0.6.3'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + local-pkg@0.5.1: + resolution: {integrity: sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==} + engines: {node: '>=14'} + + locate-path@3.0.0: + resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} + engines: {node: '>=6'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.defaults@4.2.0: + resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + + lodash.difference@4.5.0: + resolution: {integrity: sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==} + + lodash.escaperegexp@4.1.2: + resolution: {integrity: sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==} + + lodash.flatten@4.4.0: + resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==} + + lodash.isequal@4.5.0: + resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead. + + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash.union@4.6.0: + resolution: {integrity: sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + logform@2.7.0: + resolution: {integrity: sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==} + engines: {node: '>= 12.0.0'} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + loupe@2.3.7: + resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} + + lowercase-keys@2.0.0: + resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} + engines: {node: '>=8'} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + matcher@3.0.0: + resolution: {integrity: sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==} + engines: {node: '>=10'} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime@2.6.0: + resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} + engines: {node: '>=4.0.0'} + hasBin: true + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + mimic-fn@3.1.0: + resolution: {integrity: sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==} + engines: {node: '>=8'} + + mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + + mimic-response@1.0.1: + resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} + engines: {node: '>=4'} + + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + + minimatch@9.0.3: + resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} + engines: {node: '>=16 || 14 >=14.17'} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass@3.3.6: + resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} + engines: {node: '>=8'} + + minipass@5.0.0: + resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} + engines: {node: '>=8'} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + minizlib@2.1.2: + resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} + engines: {node: '>= 8'} + + mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + + mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + + mlly@1.8.0: + resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + napi-build-utils@2.0.0: + resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + node-abi@3.85.0: + resolution: {integrity: sha512-zsFhmbkAzwhTft6nd3VxcG0cvJsT70rL+BIGHWVq5fi6MwGrHwzqKaxXE+Hl2GmnGItnDKPPkO5/LQqjVkIdFg==} + engines: {node: '>=10'} + + node-addon-api@1.7.2: + resolution: {integrity: sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==} + + node-addon-api@4.3.0: + resolution: {integrity: sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==} + + node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead + + node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + node-pty@1.1.0: + resolution: {integrity: sha512-20JqtutY6JPXTUnL0ij1uad7Qe1baT46lyolh2sSENDd4sTzKZ4nmAFkeAARDKwmlLjPx6XKRlwRUxwjOy+lUg==} + + node-releases@2.0.27: + resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + normalize-url@6.1.0: + resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} + engines: {node: '>=10'} + + npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + one-time@1.0.0: + resolution: {integrity: sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + p-cancelable@2.1.1: + resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} + engines: {node: '>=8'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-limit@5.0.0: + resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==} + engines: {node: '>=18'} + + p-locate@3.0.0: + resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==} + engines: {node: '>=6'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + path-exists@3.0.0: + resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} + engines: {node: '>=4'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + pathval@1.1.1: + resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + + pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + pkg-up@3.1.0: + resolution: {integrity: sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==} + engines: {node: '>=8'} + + plist@3.1.0: + resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==} + engines: {node: '>=10.4.0'} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + prebuild-install@7.1.3: + resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} + engines: {node: '>=10'} + hasBin: true + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + progress@2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + + promise-retry@2.0.1: + resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} + engines: {node: '>=10'} + + psl@1.15.0: + resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} + + pump@3.0.3: + resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + querystringify@2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + quick-lru@5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} + + rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + + react-dom@18.3.1: + resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} + peerDependencies: + react: ^18.3.1 + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + react-refresh@0.17.0: + resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} + engines: {node: '>=0.10.0'} + + react@18.3.1: + resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} + engines: {node: '>=0.10.0'} + + read-config-file@6.3.2: + resolution: {integrity: sha512-M80lpCjnE6Wt6zb98DoW8WHR09nzMSpu8XHtPkiTHrJ5Az9CybfeQhTJ8D7saeBHpGhLPIVyA8lcL6ZmdKwY6Q==} + engines: {node: '>=12.0.0'} + + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + readdir-glob@1.1.3: + resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + + resolve-alpn@1.2.1: + resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + responselike@2.0.1: + resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} + + retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + roarr@2.15.4: + resolution: {integrity: sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==} + engines: {node: '>=8.0'} + + rollup@4.55.1: + resolution: {integrity: sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-stable-stringify@2.5.0: + resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} + engines: {node: '>=10'} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + sanitize-filename@1.6.3: + resolution: {integrity: sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==} + + sax@1.4.4: + resolution: {integrity: sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==} + engines: {node: '>=11.0.0'} + + scheduler@0.23.2: + resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} + + semver-compare@1.0.0: + resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + + serialize-error@7.0.1: + resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} + engines: {node: '>=10'} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + shell-quote@1.8.3: + resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} + engines: {node: '>= 0.4'} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + + simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + + simple-update-notifier@2.0.0: + resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} + engines: {node: '>=10'} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + slice-ansi@3.0.0: + resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==} + engines: {node: '>=8'} + + smart-buffer@4.2.0: + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + spawn-command@0.0.2: + resolution: {integrity: sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==} + + sprintf-js@1.1.3: + resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + + stack-trace@0.0.10: + resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + stat-mode@1.0.0: + resolution: {integrity: sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==} + engines: {node: '>= 6'} + + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.1.2: + resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} + engines: {node: '>=12'} + + strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + strip-literal@2.1.1: + resolution: {integrity: sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==} + + sumchecker@3.0.1: + resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==} + engines: {node: '>= 8.0'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + tar-fs@2.1.4: + resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==} + + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + + tar@6.2.1: + resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} + engines: {node: '>=10'} + + temp-file@3.4.0: + resolution: {integrity: sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==} + + text-hex@1.0.0: + resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==} + + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + + tiny-typed-emitter@2.1.0: + resolution: {integrity: sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinypool@0.8.4: + resolution: {integrity: sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==} + engines: {node: '>=14.0.0'} + + tinyspy@2.2.1: + resolution: {integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==} + engines: {node: '>=14.0.0'} + + tmp-promise@3.0.3: + resolution: {integrity: sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==} + + tmp@0.2.5: + resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==} + engines: {node: '>=14.14'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + tough-cookie@4.1.4: + resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} + engines: {node: '>=6'} + + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + + triple-beam@1.4.1: + resolution: {integrity: sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==} + engines: {node: '>= 14.0.0'} + + truncate-utf8-bytes@1.0.2: + resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==} + + ts-api-utils@1.4.3: + resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==} + engines: {node: '>=16'} + peerDependencies: + typescript: '>=4.2.0' + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-detect@4.1.0: + resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==} + engines: {node: '>=4'} + + type-fest@0.13.1: + resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} + engines: {node: '>=10'} + + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + + type-fest@2.19.0: + resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} + engines: {node: '>=12.20'} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + ufo@1.6.2: + resolution: {integrity: sha512-heMioaxBcG9+Znsda5Q8sQbWnLJSl98AFDXTO80wELWEzX3hordXsTdxrIfMQoO9IY1MEnoGoPjpoKpMj+Yx0Q==} + + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + universalify@0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + + universalify@0.2.0: + resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} + engines: {node: '>= 4.0.0'} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + url-parse@1.5.10: + resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + + utf8-byte-length@1.0.5: + resolution: {integrity: sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + verror@1.10.1: + resolution: {integrity: sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==} + engines: {node: '>=0.6.0'} + + vite-node@1.6.1: + resolution: {integrity: sha512-YAXkfvGtuTzwWbDSACdJSg4A4DZiAqckWe90Zapc/sEX3XvHcw1NdurM/6od8J207tSDqNbSsgdCacBgvJKFuA==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + + vite@5.4.21: + resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + + vitest@1.6.1: + resolution: {integrity: sha512-Ljb1cnSJSivGN0LqXd/zmDbWEM0RNNg2t1QW/XUhYl/qPqyu7CsqeWtqQXHVaJsecLPuDoak2oJcZN2QoRIOag==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': 1.6.1 + '@vitest/ui': 1.6.1 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + winston-transport@4.9.0: + resolution: {integrity: sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==} + engines: {node: '>= 12.0.0'} + + winston@3.19.0: + resolution: {integrity: sha512-LZNJgPzfKR+/J3cHkxcpHKpKKvGfDZVPS4hfJCc4cCG0CgYzvlD6yE/S3CIL/Yt91ak327YCpiF/0MyeZHEHKA==} + engines: {node: '>= 12.0.0'} + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + xmlbuilder@15.1.1: + resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} + engines: {node: '>=8.0'} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yauzl@2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + yocto-queue@1.2.2: + resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} + engines: {node: '>=12.20'} + + zip-stream@4.1.1: + resolution: {integrity: sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==} + engines: {node: '>= 10'} + +snapshots: + + 7zip-bin@5.2.0: {} + + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.28.5': {} + + '@babel/core@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) + '@babel/helpers': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.28.5': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.27.2': + dependencies: + '@babel/compat-data': 7.28.5 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.28.1 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.27.1': + dependencies: + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.27.1': {} + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.28.4': + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + + '@babel/parser@7.28.5': + dependencies: + '@babel/types': 7.28.5 + + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/runtime@7.28.4': {} + + '@babel/template@7.27.2': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + + '@babel/traverse@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.28.5': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@colors/colors@1.6.0': {} + + '@dabh/diagnostics@2.0.8': + dependencies: + '@so-ric/colorspace': 1.1.6 + enabled: 2.0.0 + kuler: 2.0.0 + + '@develar/schema-utils@2.6.5': + dependencies: + ajv: 6.12.6 + ajv-keywords: 3.5.2(ajv@6.12.6) + + '@electron/asar@3.4.1': + dependencies: + commander: 5.1.0 + glob: 7.2.3 + minimatch: 3.1.2 + + '@electron/get@2.0.3': + dependencies: + debug: 4.4.3 + env-paths: 2.2.1 + fs-extra: 8.1.0 + got: 11.8.6 + progress: 2.0.3 + semver: 6.3.1 + sumchecker: 3.0.1 + optionalDependencies: + global-agent: 3.0.0 + transitivePeerDependencies: + - supports-color + + '@electron/notarize@2.2.1': + dependencies: + debug: 4.4.3 + fs-extra: 9.1.0 + promise-retry: 2.0.1 + transitivePeerDependencies: + - supports-color + + '@electron/osx-sign@1.0.5': + dependencies: + compare-version: 0.1.2 + debug: 4.4.3 + fs-extra: 10.1.0 + isbinaryfile: 4.0.10 + minimist: 1.2.8 + plist: 3.1.0 + transitivePeerDependencies: + - supports-color + + '@electron/universal@1.5.1': + dependencies: + '@electron/asar': 3.4.1 + '@malept/cross-spawn-promise': 1.1.1 + debug: 4.4.3 + dir-compare: 3.3.0 + fs-extra: 9.1.0 + minimatch: 3.1.2 + plist: 3.1.0 + transitivePeerDependencies: + - supports-color + + '@esbuild/aix-ppc64@0.21.5': + optional: true + + '@esbuild/android-arm64@0.21.5': + optional: true + + '@esbuild/android-arm@0.21.5': + optional: true + + '@esbuild/android-x64@0.21.5': + optional: true + + '@esbuild/darwin-arm64@0.21.5': + optional: true + + '@esbuild/darwin-x64@0.21.5': + optional: true + + '@esbuild/freebsd-arm64@0.21.5': + optional: true + + '@esbuild/freebsd-x64@0.21.5': + optional: true + + '@esbuild/linux-arm64@0.21.5': + optional: true + + '@esbuild/linux-arm@0.21.5': + optional: true + + '@esbuild/linux-ia32@0.21.5': + optional: true + + '@esbuild/linux-loong64@0.21.5': + optional: true + + '@esbuild/linux-mips64el@0.21.5': + optional: true + + '@esbuild/linux-ppc64@0.21.5': + optional: true + + '@esbuild/linux-riscv64@0.21.5': + optional: true + + '@esbuild/linux-s390x@0.21.5': + optional: true + + '@esbuild/linux-x64@0.21.5': + optional: true + + '@esbuild/netbsd-x64@0.21.5': + optional: true + + '@esbuild/openbsd-x64@0.21.5': + optional: true + + '@esbuild/sunos-x64@0.21.5': + optional: true + + '@esbuild/win32-arm64@0.21.5': + optional: true + + '@esbuild/win32-ia32@0.21.5': + optional: true + + '@esbuild/win32-x64@0.21.5': + optional: true + + '@eslint-community/eslint-utils@4.9.1(eslint@8.57.1)': + dependencies: + eslint: 8.57.1 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/eslintrc@2.1.4': + dependencies: + ajv: 6.12.6 + debug: 4.4.3 + espree: 9.6.1 + globals: 13.24.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@8.57.1': {} + + '@humanwhocodes/config-array@0.13.0': + dependencies: + '@humanwhocodes/object-schema': 2.0.3 + debug: 4.4.3 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/object-schema@2.0.3': {} + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.2 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@jest/schemas@29.6.3': + dependencies: + '@sinclair/typebox': 0.27.8 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@malept/cross-spawn-promise@1.1.1': + dependencies: + cross-spawn: 7.0.6 + + '@malept/flatpak-bundler@0.4.0': + dependencies: + debug: 4.4.3 + fs-extra: 9.1.0 + lodash: 4.17.21 + tmp-promise: 3.0.3 + transitivePeerDependencies: + - supports-color + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.20.1 + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@rolldown/pluginutils@1.0.0-beta.27': {} + + '@rollup/rollup-android-arm-eabi@4.55.1': + optional: true + + '@rollup/rollup-android-arm64@4.55.1': + optional: true + + '@rollup/rollup-darwin-arm64@4.55.1': + optional: true + + '@rollup/rollup-darwin-x64@4.55.1': + optional: true + + '@rollup/rollup-freebsd-arm64@4.55.1': + optional: true + + '@rollup/rollup-freebsd-x64@4.55.1': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.55.1': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.55.1': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.55.1': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.55.1': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.55.1': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.55.1': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.55.1': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.55.1': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.55.1': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.55.1': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.55.1': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.55.1': + optional: true + + '@rollup/rollup-linux-x64-musl@4.55.1': + optional: true + + '@rollup/rollup-openbsd-x64@4.55.1': + optional: true + + '@rollup/rollup-openharmony-arm64@4.55.1': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.55.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.55.1': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.55.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.55.1': + optional: true + + '@sinclair/typebox@0.27.8': {} + + '@sindresorhus/is@4.6.0': {} + + '@so-ric/colorspace@1.1.6': + dependencies: + color: 5.0.3 + text-hex: 1.0.0 + + '@szmarczak/http-timer@4.0.6': + dependencies: + defer-to-connect: 2.0.1 + + '@tootallnate/once@2.0.0': {} + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.28.5 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.28.5 + + '@types/cacheable-request@6.0.3': + dependencies: + '@types/http-cache-semantics': 4.0.4 + '@types/keyv': 3.1.4 + '@types/node': 20.19.27 + '@types/responselike': 1.0.3 + + '@types/debug@4.1.12': + dependencies: + '@types/ms': 2.1.0 + + '@types/estree@1.0.8': {} + + '@types/fs-extra@9.0.13': + dependencies: + '@types/node': 20.19.27 + + '@types/http-cache-semantics@4.0.4': {} + + '@types/json-schema@7.0.15': {} + + '@types/keyv@3.1.4': + dependencies: + '@types/node': 20.19.27 + + '@types/ms@2.1.0': {} + + '@types/node@18.19.130': + dependencies: + undici-types: 5.26.5 + + '@types/node@20.19.27': + dependencies: + undici-types: 6.21.0 + + '@types/plist@3.0.5': + dependencies: + '@types/node': 20.19.27 + xmlbuilder: 15.1.1 + optional: true + + '@types/prop-types@15.7.15': {} + + '@types/react-dom@18.3.7(@types/react@18.3.27)': + dependencies: + '@types/react': 18.3.27 + + '@types/react@18.3.27': + dependencies: + '@types/prop-types': 15.7.15 + csstype: 3.2.3 + + '@types/responselike@1.0.3': + dependencies: + '@types/node': 20.19.27 + + '@types/semver@7.7.1': {} + + '@types/tough-cookie@4.0.5': {} + + '@types/triple-beam@1.3.5': {} + + '@types/verror@1.10.11': + optional: true + + '@types/yauzl@2.10.3': + dependencies: + '@types/node': 20.19.27 + optional: true + + '@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/scope-manager': 6.21.0 + '@typescript-eslint/type-utils': 6.21.0(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/utils': 6.21.0(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 6.21.0 + debug: 4.4.3 + eslint: 8.57.1 + graphemer: 1.4.0 + ignore: 5.3.2 + natural-compare: 1.4.0 + semver: 7.7.3 + ts-api-utils: 1.4.3(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 6.21.0 + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 6.21.0 + debug: 4.4.3 + eslint: 8.57.1 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@6.21.0': + dependencies: + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/visitor-keys': 6.21.0 + + '@typescript-eslint/type-utils@6.21.0(eslint@8.57.1)(typescript@5.9.3)': + dependencies: + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.9.3) + '@typescript-eslint/utils': 6.21.0(eslint@8.57.1)(typescript@5.9.3) + debug: 4.4.3 + eslint: 8.57.1 + ts-api-utils: 1.4.3(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@6.21.0': {} + + '@typescript-eslint/typescript-estree@6.21.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/visitor-keys': 6.21.0 + debug: 4.4.3 + globby: 11.1.0 + is-glob: 4.0.3 + minimatch: 9.0.3 + semver: 7.7.3 + ts-api-utils: 1.4.3(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@6.21.0(eslint@8.57.1)(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@8.57.1) + '@types/json-schema': 7.0.15 + '@types/semver': 7.7.1 + '@typescript-eslint/scope-manager': 6.21.0 + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.9.3) + eslint: 8.57.1 + semver: 7.7.3 + transitivePeerDependencies: + - supports-color + - typescript + + '@typescript-eslint/visitor-keys@6.21.0': + dependencies: + '@typescript-eslint/types': 6.21.0 + eslint-visitor-keys: 3.4.3 + + '@ungap/structured-clone@1.3.0': {} + + '@vitejs/plugin-react@4.7.0(vite@5.4.21(@types/node@20.19.27))': + dependencies: + '@babel/core': 7.28.5 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.5) + '@rolldown/pluginutils': 1.0.0-beta.27 + '@types/babel__core': 7.20.5 + react-refresh: 0.17.0 + vite: 5.4.21(@types/node@20.19.27) + transitivePeerDependencies: + - supports-color + + '@vitest/expect@1.6.1': + dependencies: + '@vitest/spy': 1.6.1 + '@vitest/utils': 1.6.1 + chai: 4.5.0 + + '@vitest/runner@1.6.1': + dependencies: + '@vitest/utils': 1.6.1 + p-limit: 5.0.0 + pathe: 1.1.2 + + '@vitest/snapshot@1.6.1': + dependencies: + magic-string: 0.30.21 + pathe: 1.1.2 + pretty-format: 29.7.0 + + '@vitest/spy@1.6.1': + dependencies: + tinyspy: 2.2.1 + + '@vitest/utils@1.6.1': + dependencies: + diff-sequences: 29.6.3 + estree-walker: 3.0.3 + loupe: 2.3.7 + pretty-format: 29.7.0 + + '@xmldom/xmldom@0.8.11': {} + + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn-walk@8.3.4: + dependencies: + acorn: 8.15.0 + + acorn@8.15.0: {} + + agent-base@6.0.2: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + ajv-formats@2.1.1(ajv@8.17.1): + optionalDependencies: + ajv: 8.17.1 + + ajv-keywords@3.5.2(ajv@6.12.6): + dependencies: + ajv: 6.12.6 + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ajv@8.17.1: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + ansi-regex@5.0.1: {} + + ansi-regex@6.2.2: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@5.2.0: {} + + ansi-styles@6.2.3: {} + + app-builder-bin@4.0.0: {} + + app-builder-lib@24.13.3(dmg-builder@24.13.3)(electron-builder-squirrel-windows@24.13.3): + dependencies: + '@develar/schema-utils': 2.6.5 + '@electron/notarize': 2.2.1 + '@electron/osx-sign': 1.0.5 + '@electron/universal': 1.5.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: 24.13.1 + builder-util-runtime: 9.2.4 + chromium-pickle-js: 0.2.0 + debug: 4.4.3 + dmg-builder: 24.13.3(electron-builder-squirrel-windows@24.13.3) + ejs: 3.1.10 + electron-builder-squirrel-windows: 24.13.3(dmg-builder@24.13.3) + electron-publish: 24.13.1 + form-data: 4.0.5 + fs-extra: 10.1.0 + hosted-git-info: 4.1.0 + is-ci: 3.0.1 + isbinaryfile: 5.0.7 + js-yaml: 4.1.1 + lazy-val: 1.0.5 + minimatch: 5.1.6 + read-config-file: 6.3.2 + sanitize-filename: 1.6.3 + semver: 7.7.3 + tar: 6.2.1 + temp-file: 3.4.0 + transitivePeerDependencies: + - supports-color + + archiver-utils@2.1.0: + dependencies: + glob: 7.2.3 + graceful-fs: 4.2.11 + lazystream: 1.0.1 + 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.3.8 + + archiver-utils@3.0.4: + dependencies: + glob: 7.2.3 + graceful-fs: 4.2.11 + lazystream: 1.0.1 + 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.2 + + archiver@5.3.2: + dependencies: + archiver-utils: 2.1.0 + async: 3.2.6 + buffer-crc32: 0.2.13 + readable-stream: 3.6.2 + readdir-glob: 1.1.3 + tar-stream: 2.2.0 + zip-stream: 4.1.1 + + argparse@2.0.1: {} + + array-union@2.1.0: {} + + assert-plus@1.0.0: + optional: true + + assertion-error@1.1.0: {} + + astral-regex@2.0.0: + optional: true + + async-exit-hook@2.0.1: {} + + async@3.2.6: {} + + asynckit@0.4.0: {} + + at-least-node@1.0.0: {} + + atomically@1.7.0: {} + + balanced-match@1.0.2: {} + + base64-js@1.5.1: {} + + baseline-browser-mapping@2.9.13: {} + + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + + bluebird-lst@1.0.9: + dependencies: + bluebird: 3.7.2 + + bluebird@3.7.2: {} + + boolean@3.2.0: + optional: true + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.28.1: + dependencies: + baseline-browser-mapping: 2.9.13 + caniuse-lite: 1.0.30001763 + electron-to-chromium: 1.5.267 + node-releases: 2.0.27 + update-browserslist-db: 1.2.3(browserslist@4.28.1) + + buffer-crc32@0.2.13: {} + + buffer-equal@1.0.1: {} + + buffer-from@1.1.2: {} + + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + builder-util-runtime@9.2.4: + dependencies: + debug: 4.4.3 + sax: 1.4.4 + transitivePeerDependencies: + - supports-color + + builder-util-runtime@9.5.1: + dependencies: + debug: 4.4.3 + sax: 1.4.4 + transitivePeerDependencies: + - supports-color + + builder-util@24.13.1: + dependencies: + 7zip-bin: 5.2.0 + '@types/debug': 4.1.12 + app-builder-bin: 4.0.0 + bluebird-lst: 1.0.9 + builder-util-runtime: 9.2.4 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + fs-extra: 10.1.0 + http-proxy-agent: 5.0.0 + https-proxy-agent: 5.0.1 + is-ci: 3.0.1 + js-yaml: 4.1.1 + source-map-support: 0.5.21 + stat-mode: 1.0.0 + temp-file: 3.4.0 + transitivePeerDependencies: + - supports-color + + cac@6.7.14: {} + + cacheable-lookup@5.0.4: {} + + cacheable-request@7.0.4: + dependencies: + clone-response: 1.0.3 + get-stream: 5.2.0 + http-cache-semantics: 4.2.0 + keyv: 4.5.4 + lowercase-keys: 2.0.0 + normalize-url: 6.1.0 + responselike: 2.0.1 + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + callsites@3.1.0: {} + + caniuse-lite@1.0.30001763: {} + + chai@4.5.0: + dependencies: + assertion-error: 1.1.0 + check-error: 1.0.3 + deep-eql: 4.1.4 + get-func-name: 2.0.2 + loupe: 2.3.7 + pathval: 1.1.1 + type-detect: 4.1.0 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + check-error@1.0.3: + dependencies: + get-func-name: 2.0.2 + + chownr@1.1.4: {} + + chownr@2.0.0: {} + + chromium-pickle-js@0.2.0: {} + + ci-info@3.9.0: {} + + cli-truncate@2.1.0: + dependencies: + slice-ansi: 3.0.0 + string-width: 4.2.3 + optional: true + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + clone-response@1.0.3: + dependencies: + mimic-response: 1.0.1 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-convert@3.1.3: + dependencies: + color-name: 2.1.0 + + color-name@1.1.4: {} + + color-name@2.1.0: {} + + color-string@2.1.4: + dependencies: + color-name: 2.1.0 + + color@5.0.3: + dependencies: + color-convert: 3.1.3 + color-string: 2.1.4 + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + commander@11.1.0: {} + + commander@5.1.0: {} + + compare-version@0.1.2: {} + + compress-commons@4.1.2: + dependencies: + buffer-crc32: 0.2.13 + crc32-stream: 4.0.3 + normalize-path: 3.0.0 + readable-stream: 3.6.2 + + concat-map@0.0.1: {} + + concurrently@8.2.2: + dependencies: + chalk: 4.1.2 + date-fns: 2.30.0 + lodash: 4.17.21 + rxjs: 7.8.2 + shell-quote: 1.8.3 + spawn-command: 0.0.2 + supports-color: 8.1.1 + tree-kill: 1.2.2 + yargs: 17.7.2 + + conf@10.2.0: + dependencies: + ajv: 8.17.1 + ajv-formats: 2.1.1(ajv@8.17.1) + atomically: 1.7.0 + debounce-fn: 4.0.0 + dot-prop: 6.0.1 + env-paths: 2.2.1 + json-schema-typed: 7.0.3 + onetime: 5.1.2 + pkg-up: 3.1.0 + semver: 7.7.3 + + confbox@0.1.8: {} + + config-file-ts@0.2.6: + dependencies: + glob: 10.5.0 + typescript: 5.9.3 + + convert-source-map@2.0.0: {} + + core-util-is@1.0.2: + optional: true + + core-util-is@1.0.3: {} + + crc-32@1.2.2: {} + + crc32-stream@4.0.3: + dependencies: + crc-32: 1.2.2 + readable-stream: 3.6.2 + + crc@3.8.0: + dependencies: + buffer: 5.7.1 + optional: true + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.2.3: {} + + data-uri-to-buffer@4.0.1: {} + + date-fns@2.30.0: + dependencies: + '@babel/runtime': 7.28.4 + + debounce-fn@4.0.0: + dependencies: + mimic-fn: 3.1.0 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + + deep-eql@4.1.4: + dependencies: + type-detect: 4.1.0 + + deep-extend@0.6.0: {} + + deep-is@0.1.4: {} + + defer-to-connect@2.0.1: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + optional: true + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + optional: true + + delayed-stream@1.0.0: {} + + detect-libc@2.1.2: {} + + detect-node@2.1.0: + optional: true + + diff-sequences@29.6.3: {} + + dir-compare@3.3.0: + dependencies: + buffer-equal: 1.0.1 + minimatch: 3.1.2 + + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3): + dependencies: + app-builder-lib: 24.13.3(dmg-builder@24.13.3)(electron-builder-squirrel-windows@24.13.3) + builder-util: 24.13.1 + builder-util-runtime: 9.2.4 + fs-extra: 10.1.0 + iconv-lite: 0.6.3 + js-yaml: 4.1.1 + optionalDependencies: + dmg-license: 1.0.11 + transitivePeerDependencies: + - electron-builder-squirrel-windows + - supports-color + + dmg-license@1.0.11: + dependencies: + '@types/plist': 3.0.5 + '@types/verror': 1.10.11 + ajv: 6.12.6 + crc: 3.8.0 + iconv-corefoundation: 1.1.7 + plist: 3.1.0 + smart-buffer: 4.2.0 + verror: 1.10.1 + optional: true + + doctrine@3.0.0: + dependencies: + esutils: 2.0.3 + + dot-prop@6.0.1: + dependencies: + is-obj: 2.0.0 + + dotenv-expand@5.1.0: {} + + dotenv@9.0.2: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + eastasianwidth@0.2.0: {} + + ejs@3.1.10: + dependencies: + jake: 10.9.4 + + electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3): + dependencies: + app-builder-lib: 24.13.3(dmg-builder@24.13.3)(electron-builder-squirrel-windows@24.13.3) + archiver: 5.3.2 + builder-util: 24.13.1 + fs-extra: 10.1.0 + transitivePeerDependencies: + - dmg-builder + - supports-color + + electron-builder@24.13.3(electron-builder-squirrel-windows@24.13.3): + dependencies: + app-builder-lib: 24.13.3(dmg-builder@24.13.3)(electron-builder-squirrel-windows@24.13.3) + builder-util: 24.13.1 + builder-util-runtime: 9.2.4 + chalk: 4.1.2 + dmg-builder: 24.13.3(electron-builder-squirrel-windows@24.13.3) + fs-extra: 10.1.0 + is-ci: 3.0.1 + lazy-val: 1.0.5 + read-config-file: 6.3.2 + simple-update-notifier: 2.0.0 + yargs: 17.7.2 + transitivePeerDependencies: + - electron-builder-squirrel-windows + - supports-color + + electron-publish@24.13.1: + dependencies: + '@types/fs-extra': 9.0.13 + builder-util: 24.13.1 + builder-util-runtime: 9.2.4 + chalk: 4.1.2 + fs-extra: 10.1.0 + lazy-val: 1.0.5 + mime: 2.6.0 + transitivePeerDependencies: + - supports-color + + electron-store@8.2.0: + dependencies: + conf: 10.2.0 + type-fest: 2.19.0 + + electron-to-chromium@1.5.267: {} + + electron-updater@6.7.3: + dependencies: + builder-util-runtime: 9.5.1 + fs-extra: 10.1.0 + js-yaml: 4.1.1 + lazy-val: 1.0.5 + lodash.escaperegexp: 4.1.2 + lodash.isequal: 4.5.0 + semver: 7.7.3 + tiny-typed-emitter: 2.1.0 + transitivePeerDependencies: + - supports-color + + electron@28.3.3: + dependencies: + '@electron/get': 2.0.3 + '@types/node': 18.19.130 + extract-zip: 2.0.1 + transitivePeerDependencies: + - supports-color + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + enabled@2.0.0: {} + + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + + env-paths@2.2.1: {} + + err-code@2.0.3: {} + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es6-error@4.1.1: + optional: true + + esbuild@0.21.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + + escalade@3.2.0: {} + + escape-string-regexp@4.0.0: {} + + eslint-scope@7.2.2: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint@8.57.1: + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@8.57.1) + '@eslint-community/regexpp': 4.12.2 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.57.1 + '@humanwhocodes/config-array': 0.13.0 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.3.0 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.24.0 + graphemer: 1.4.0 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.1 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + + espree@9.6.1: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 3.4.3 + + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + + esutils@2.0.3: {} + + execa@8.0.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.3.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + + expand-template@2.0.3: {} + + extract-zip@2.0.1: + dependencies: + debug: 4.4.3 + get-stream: 5.2.0 + yauzl: 2.10.0 + optionalDependencies: + '@types/yauzl': 2.10.3 + transitivePeerDependencies: + - supports-color + + extsprintf@1.4.1: + optional: true + + fast-deep-equal@3.1.3: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-uri@3.1.0: {} + + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + + fd-slicer@1.1.0: + dependencies: + pend: 1.2.0 + + fecha@4.2.3: {} + + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + + file-entry-cache@6.0.1: + dependencies: + flat-cache: 3.2.0 + + filelist@1.0.4: + dependencies: + minimatch: 5.1.6 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@3.0.0: + dependencies: + locate-path: 3.0.0 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@3.2.0: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + rimraf: 3.0.2 + + flatted@3.3.3: {} + + fn.name@1.1.0: {} + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + form-data@4.0.5: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + + formdata-polyfill@4.0.10: + dependencies: + fetch-blob: 3.2.0 + + fs-constants@1.0.0: {} + + fs-extra@10.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + + fs-extra@8.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + + fs-extra@9.1.0: + dependencies: + at-least-node: 1.0.0 + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + + fs-minipass@2.1.0: + dependencies: + minipass: 3.3.6 + + fs.realpath@1.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-func-name@2.0.2: {} + + get-intrinsic@1.3.0: + 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 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-stream@5.2.0: + dependencies: + pump: 3.0.3 + + get-stream@8.0.1: {} + + github-from-package@0.0.0: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob@10.5.0: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + global-agent@3.0.0: + dependencies: + boolean: 3.2.0 + es6-error: 4.1.1 + matcher: 3.0.0 + roarr: 2.15.4 + semver: 7.7.3 + serialize-error: 7.0.1 + optional: true + + globals@13.24.0: + dependencies: + type-fest: 0.20.2 + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + optional: true + + globby@11.1.0: + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.3 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 3.0.0 + + gopd@1.2.0: {} + + got@11.8.6: + dependencies: + '@sindresorhus/is': 4.6.0 + '@szmarczak/http-timer': 4.0.6 + '@types/cacheable-request': 6.0.3 + '@types/responselike': 1.0.3 + cacheable-lookup: 5.0.4 + cacheable-request: 7.0.4 + decompress-response: 6.0.0 + http2-wrapper: 1.0.3 + lowercase-keys: 2.0.0 + p-cancelable: 2.1.1 + responselike: 2.0.1 + + graceful-fs@4.2.11: {} + + graphemer@1.4.0: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + optional: true + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + hosted-git-info@4.1.0: + dependencies: + lru-cache: 6.0.0 + + http-cache-semantics@4.2.0: {} + + http-proxy-agent@5.0.0: + dependencies: + '@tootallnate/once': 2.0.0 + agent-base: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + http2-wrapper@1.0.3: + dependencies: + quick-lru: 5.1.1 + resolve-alpn: 1.2.1 + + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + human-signals@5.0.0: {} + + iconv-corefoundation@1.1.7: + dependencies: + cli-truncate: 2.1.0 + node-addon-api: 1.7.2 + optional: true + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + ieee754@1.2.1: {} + + ignore@5.3.2: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + ini@1.3.8: {} + + is-ci@3.0.1: + dependencies: + ci-info: 3.9.0 + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + is-obj@2.0.0: {} + + is-path-inside@3.0.3: {} + + is-stream@2.0.1: {} + + is-stream@3.0.0: {} + + isarray@1.0.0: {} + + isbinaryfile@4.0.10: {} + + isbinaryfile@5.0.7: {} + + isexe@2.0.0: {} + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jake@10.9.4: + dependencies: + async: 3.2.6 + filelist: 1.0.4 + picocolors: 1.1.1 + + js-tokens@4.0.0: {} + + js-tokens@9.0.1: {} + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + json-schema-typed@7.0.3: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json-stringify-safe@5.0.1: + optional: true + + json5@2.2.3: {} + + jsonfile@4.0.0: + optionalDependencies: + graceful-fs: 4.2.11 + + jsonfile@6.2.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + keytar@7.9.0: + dependencies: + node-addon-api: 4.3.0 + prebuild-install: 7.1.3 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + kuler@2.0.0: {} + + lazy-val@1.0.5: {} + + lazystream@1.0.1: + dependencies: + readable-stream: 2.3.8 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + local-pkg@0.5.1: + dependencies: + mlly: 1.8.0 + pkg-types: 1.3.1 + + locate-path@3.0.0: + dependencies: + p-locate: 3.0.0 + path-exists: 3.0.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.defaults@4.2.0: {} + + lodash.difference@4.5.0: {} + + lodash.escaperegexp@4.1.2: {} + + lodash.flatten@4.4.0: {} + + lodash.isequal@4.5.0: {} + + lodash.isplainobject@4.0.6: {} + + lodash.merge@4.6.2: {} + + lodash.union@4.6.0: {} + + lodash@4.17.21: {} + + logform@2.7.0: + dependencies: + '@colors/colors': 1.6.0 + '@types/triple-beam': 1.3.5 + fecha: 4.2.3 + ms: 2.1.3 + safe-stable-stringify: 2.5.0 + triple-beam: 1.4.1 + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + loupe@2.3.7: + dependencies: + get-func-name: 2.0.2 + + lowercase-keys@2.0.0: {} + + lru-cache@10.4.3: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lru-cache@6.0.0: + dependencies: + yallist: 4.0.0 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + matcher@3.0.0: + dependencies: + escape-string-regexp: 4.0.0 + optional: true + + math-intrinsics@1.1.0: {} + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime@2.6.0: {} + + mimic-fn@2.1.0: {} + + mimic-fn@3.1.0: {} + + mimic-fn@4.0.0: {} + + mimic-response@1.0.1: {} + + mimic-response@3.1.0: {} + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.12 + + minimatch@5.1.6: + dependencies: + brace-expansion: 2.0.2 + + minimatch@9.0.3: + dependencies: + brace-expansion: 2.0.2 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 + + minimist@1.2.8: {} + + minipass@3.3.6: + dependencies: + yallist: 4.0.0 + + minipass@5.0.0: {} + + minipass@7.1.2: {} + + minizlib@2.1.2: + dependencies: + minipass: 3.3.6 + yallist: 4.0.0 + + mkdirp-classic@0.5.3: {} + + mkdirp@1.0.4: {} + + mlly@1.8.0: + dependencies: + acorn: 8.15.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.2 + + ms@2.1.3: {} + + nanoid@3.3.11: {} + + napi-build-utils@2.0.0: {} + + natural-compare@1.4.0: {} + + node-abi@3.85.0: + dependencies: + semver: 7.7.3 + + node-addon-api@1.7.2: + optional: true + + node-addon-api@4.3.0: {} + + node-addon-api@7.1.1: {} + + node-domexception@1.0.0: {} + + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + + node-pty@1.1.0: + dependencies: + node-addon-api: 7.1.1 + + node-releases@2.0.27: {} + + normalize-path@3.0.0: {} + + normalize-url@6.1.0: {} + + npm-run-path@5.3.0: + dependencies: + path-key: 4.0.0 + + object-keys@1.1.1: + optional: true + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + one-time@1.0.0: + dependencies: + fn.name: 1.1.0 + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + onetime@6.0.0: + dependencies: + mimic-fn: 4.0.0 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + p-cancelable@2.1.1: {} + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-limit@5.0.0: + dependencies: + yocto-queue: 1.2.2 + + p-locate@3.0.0: + dependencies: + p-limit: 2.3.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + p-try@2.2.0: {} + + package-json-from-dist@1.0.1: {} + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + path-exists@3.0.0: {} + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-key@4.0.0: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + + path-type@4.0.0: {} + + pathe@1.1.2: {} + + pathe@2.0.3: {} + + pathval@1.1.1: {} + + pend@1.2.0: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.0 + pathe: 2.0.3 + + pkg-up@3.1.0: + dependencies: + find-up: 3.0.0 + + plist@3.1.0: + dependencies: + '@xmldom/xmldom': 0.8.11 + base64-js: 1.5.1 + xmlbuilder: 15.1.1 + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prebuild-install@7.1.3: + dependencies: + detect-libc: 2.1.2 + expand-template: 2.0.3 + github-from-package: 0.0.0 + minimist: 1.2.8 + mkdirp-classic: 0.5.3 + napi-build-utils: 2.0.0 + node-abi: 3.85.0 + pump: 3.0.3 + rc: 1.2.8 + simple-get: 4.0.1 + tar-fs: 2.1.4 + tunnel-agent: 0.6.0 + + prelude-ls@1.2.1: {} + + pretty-format@29.7.0: + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.3.1 + + process-nextick-args@2.0.1: {} + + progress@2.0.3: {} + + promise-retry@2.0.1: + dependencies: + err-code: 2.0.3 + retry: 0.12.0 + + psl@1.15.0: + dependencies: + punycode: 2.3.1 + + pump@3.0.3: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + + punycode@2.3.1: {} + + querystringify@2.2.0: {} + + queue-microtask@1.2.3: {} + + quick-lru@5.1.1: {} + + rc@1.2.8: + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + + react-dom@18.3.1(react@18.3.1): + dependencies: + loose-envify: 1.4.0 + react: 18.3.1 + scheduler: 0.23.2 + + react-is@18.3.1: {} + + react-refresh@0.17.0: {} + + react@18.3.1: + dependencies: + loose-envify: 1.4.0 + + read-config-file@6.3.2: + dependencies: + config-file-ts: 0.2.6 + dotenv: 9.0.2 + dotenv-expand: 5.1.0 + js-yaml: 4.1.1 + json5: 2.2.3 + lazy-val: 1.0.5 + + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + readdir-glob@1.1.3: + dependencies: + minimatch: 5.1.6 + + require-directory@2.1.1: {} + + require-from-string@2.0.2: {} + + requires-port@1.0.0: {} + + resolve-alpn@1.2.1: {} + + resolve-from@4.0.0: {} + + responselike@2.0.1: + dependencies: + lowercase-keys: 2.0.0 + + retry@0.12.0: {} + + reusify@1.1.0: {} + + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + + roarr@2.15.4: + dependencies: + boolean: 3.2.0 + detect-node: 2.1.0 + globalthis: 1.0.4 + json-stringify-safe: 5.0.1 + semver-compare: 1.0.0 + sprintf-js: 1.1.3 + optional: true + + rollup@4.55.1: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.55.1 + '@rollup/rollup-android-arm64': 4.55.1 + '@rollup/rollup-darwin-arm64': 4.55.1 + '@rollup/rollup-darwin-x64': 4.55.1 + '@rollup/rollup-freebsd-arm64': 4.55.1 + '@rollup/rollup-freebsd-x64': 4.55.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.55.1 + '@rollup/rollup-linux-arm-musleabihf': 4.55.1 + '@rollup/rollup-linux-arm64-gnu': 4.55.1 + '@rollup/rollup-linux-arm64-musl': 4.55.1 + '@rollup/rollup-linux-loong64-gnu': 4.55.1 + '@rollup/rollup-linux-loong64-musl': 4.55.1 + '@rollup/rollup-linux-ppc64-gnu': 4.55.1 + '@rollup/rollup-linux-ppc64-musl': 4.55.1 + '@rollup/rollup-linux-riscv64-gnu': 4.55.1 + '@rollup/rollup-linux-riscv64-musl': 4.55.1 + '@rollup/rollup-linux-s390x-gnu': 4.55.1 + '@rollup/rollup-linux-x64-gnu': 4.55.1 + '@rollup/rollup-linux-x64-musl': 4.55.1 + '@rollup/rollup-openbsd-x64': 4.55.1 + '@rollup/rollup-openharmony-arm64': 4.55.1 + '@rollup/rollup-win32-arm64-msvc': 4.55.1 + '@rollup/rollup-win32-ia32-msvc': 4.55.1 + '@rollup/rollup-win32-x64-gnu': 4.55.1 + '@rollup/rollup-win32-x64-msvc': 4.55.1 + fsevents: 2.3.3 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + rxjs@7.8.2: + dependencies: + tslib: 2.8.1 + + safe-buffer@5.1.2: {} + + safe-buffer@5.2.1: {} + + safe-stable-stringify@2.5.0: {} + + safer-buffer@2.1.2: {} + + sanitize-filename@1.6.3: + dependencies: + truncate-utf8-bytes: 1.0.2 + + sax@1.4.4: {} + + scheduler@0.23.2: + dependencies: + loose-envify: 1.4.0 + + semver-compare@1.0.0: + optional: true + + semver@6.3.1: {} + + semver@7.7.3: {} + + serialize-error@7.0.1: + dependencies: + type-fest: 0.13.1 + optional: true + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + shell-quote@1.8.3: {} + + siginfo@2.0.0: {} + + signal-exit@4.1.0: {} + + simple-concat@1.0.1: {} + + simple-get@4.0.1: + dependencies: + decompress-response: 6.0.0 + once: 1.4.0 + simple-concat: 1.0.1 + + simple-update-notifier@2.0.0: + dependencies: + semver: 7.7.3 + + slash@3.0.0: {} + + slice-ansi@3.0.0: + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + optional: true + + smart-buffer@4.2.0: + optional: true + + source-map-js@1.2.1: {} + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + spawn-command@0.0.2: {} + + sprintf-js@1.1.3: + optional: true + + stack-trace@0.0.10: {} + + stackback@0.0.2: {} + + stat-mode@1.0.0: {} + + std-env@3.10.0: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.2 + + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.2: + dependencies: + ansi-regex: 6.2.2 + + strip-final-newline@3.0.0: {} + + strip-json-comments@2.0.1: {} + + strip-json-comments@3.1.1: {} + + strip-literal@2.1.1: + dependencies: + js-tokens: 9.0.1 + + sumchecker@3.0.1: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + tar-fs@2.1.4: + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.3 + tar-stream: 2.2.0 + + tar-stream@2.2.0: + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.5 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + + tar@6.2.1: + dependencies: + chownr: 2.0.0 + fs-minipass: 2.1.0 + minipass: 5.0.0 + minizlib: 2.1.2 + mkdirp: 1.0.4 + yallist: 4.0.0 + + temp-file@3.4.0: + dependencies: + async-exit-hook: 2.0.1 + fs-extra: 10.1.0 + + text-hex@1.0.0: {} + + text-table@0.2.0: {} + + tiny-typed-emitter@2.1.0: {} + + tinybench@2.9.0: {} + + tinypool@0.8.4: {} + + tinyspy@2.2.1: {} + + tmp-promise@3.0.3: + dependencies: + tmp: 0.2.5 + + tmp@0.2.5: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + tough-cookie@4.1.4: + dependencies: + psl: 1.15.0 + punycode: 2.3.1 + universalify: 0.2.0 + url-parse: 1.5.10 + + tree-kill@1.2.2: {} + + triple-beam@1.4.1: {} + + truncate-utf8-bytes@1.0.2: + dependencies: + utf8-byte-length: 1.0.5 + + ts-api-utils@1.4.3(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + + tslib@2.8.1: {} + + tunnel-agent@0.6.0: + dependencies: + safe-buffer: 5.2.1 + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-detect@4.1.0: {} + + type-fest@0.13.1: + optional: true + + type-fest@0.20.2: {} + + type-fest@2.19.0: {} + + typescript@5.9.3: {} + + ufo@1.6.2: {} + + undici-types@5.26.5: {} + + undici-types@6.21.0: {} + + universalify@0.1.2: {} + + universalify@0.2.0: {} + + universalify@2.0.1: {} + + update-browserslist-db@1.2.3(browserslist@4.28.1): + dependencies: + browserslist: 4.28.1 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + url-parse@1.5.10: + dependencies: + querystringify: 2.2.0 + requires-port: 1.0.0 + + utf8-byte-length@1.0.5: {} + + util-deprecate@1.0.2: {} + + verror@1.10.1: + dependencies: + assert-plus: 1.0.0 + core-util-is: 1.0.2 + extsprintf: 1.4.1 + optional: true + + vite-node@1.6.1(@types/node@20.19.27): + dependencies: + cac: 6.7.14 + debug: 4.4.3 + pathe: 1.1.2 + picocolors: 1.1.1 + vite: 5.4.21(@types/node@20.19.27) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + vite@5.4.21(@types/node@20.19.27): + dependencies: + esbuild: 0.21.5 + postcss: 8.5.6 + rollup: 4.55.1 + optionalDependencies: + '@types/node': 20.19.27 + fsevents: 2.3.3 + + vitest@1.6.1(@types/node@20.19.27): + dependencies: + '@vitest/expect': 1.6.1 + '@vitest/runner': 1.6.1 + '@vitest/snapshot': 1.6.1 + '@vitest/spy': 1.6.1 + '@vitest/utils': 1.6.1 + acorn-walk: 8.3.4 + chai: 4.5.0 + debug: 4.4.3 + execa: 8.0.1 + local-pkg: 0.5.1 + magic-string: 0.30.21 + pathe: 1.1.2 + picocolors: 1.1.1 + std-env: 3.10.0 + strip-literal: 2.1.1 + tinybench: 2.9.0 + tinypool: 0.8.4 + vite: 5.4.21(@types/node@20.19.27) + vite-node: 1.6.1(@types/node@20.19.27) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 20.19.27 + transitivePeerDependencies: + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + web-streams-polyfill@3.3.3: {} + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + winston-transport@4.9.0: + dependencies: + logform: 2.7.0 + readable-stream: 3.6.2 + triple-beam: 1.4.1 + + winston@3.19.0: + dependencies: + '@colors/colors': 1.6.0 + '@dabh/diagnostics': 2.0.8 + async: 3.2.6 + is-stream: 2.0.1 + logform: 2.7.0 + one-time: 1.0.0 + readable-stream: 3.6.2 + safe-stable-stringify: 2.5.0 + stack-trace: 0.0.10 + triple-beam: 1.4.1 + winston-transport: 4.9.0 + + word-wrap@1.2.5: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 5.1.2 + strip-ansi: 7.1.2 + + wrappy@1.0.2: {} + + xmlbuilder@15.1.1: {} + + y18n@5.0.8: {} + + yallist@3.1.1: {} + + yallist@4.0.0: {} + + yargs-parser@21.1.1: {} + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yauzl@2.10.0: + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + + yocto-queue@0.1.0: {} + + yocto-queue@1.2.2: {} + + zip-stream@4.1.1: + dependencies: + archiver-utils: 3.0.4 + compress-commons: 4.1.2 + readable-stream: 3.6.2 diff --git a/codexbar-electron/src/cli/index.ts b/codexbar-electron/src/cli/index.ts new file mode 100644 index 00000000..51c0f5e0 --- /dev/null +++ b/codexbar-electron/src/cli/index.ts @@ -0,0 +1,156 @@ +#!/usr/bin/env node +/** + * CodexBar CLI + * + * Command-line interface for querying AI provider usage. + * Mirrors the functionality of the macOS bundled CLI. + */ + +import { Command } from 'commander'; +import { CodexProvider } from '../main/providers/codex/CodexProvider'; +import { ClaudeProvider } from '../main/providers/claude/ClaudeProvider'; +import { CursorProvider } from '../main/providers/cursor/CursorProvider'; +import { GeminiProvider } from '../main/providers/gemini/GeminiProvider'; +import { BaseProvider } from '../main/providers/BaseProvider'; + +const program = new Command(); + +// All available providers +const providers: Record = { + codex: new CodexProvider(), + claude: new ClaudeProvider(), + cursor: new CursorProvider(), + gemini: new GeminiProvider(), + // Add more as needed +}; + +program + .name('codexbar') + .description('Monitor API usage limits for AI providers') + .version('0.1.0'); + +program + .command('status') + .description('Show usage status for all configured providers') + .option('-p, --provider ', 'Specific provider to check') + .option('-j, --json', 'Output as JSON') + .action(async (options) => { + const providersToCheck = options.provider + ? [options.provider] + : Object.keys(providers); + + const results: Record = {}; + + for (const name of providersToCheck) { + const provider = providers[name]; + if (!provider) { + console.error(`Unknown provider: ${name}`); + continue; + } + + const configured = await provider.isConfigured(); + if (!configured) { + results[name] = { status: 'not configured' }; + continue; + } + + const result = await provider.refresh(); + results[name] = { + status: result.state, + usage: result.usage, + error: result.error, + }; + } + + if (options.json) { + console.log(JSON.stringify(results, null, 2)); + } else { + printStatus(results); + } + }); + +program + .command('list') + .description('List all available providers') + .action(() => { + console.log('Available providers:\n'); + for (const [id, provider] of Object.entries(providers)) { + console.log(` ${provider.icon} ${provider.name} (${id})`); + } + }); + +program + .command('refresh') + .description('Refresh usage data for all providers') + .option('-p, --provider ', 'Specific provider to refresh') + .action(async (options) => { + const providersToRefresh = options.provider + ? [options.provider] + : Object.keys(providers); + + console.log('Refreshing...\n'); + + for (const name of providersToRefresh) { + const provider = providers[name]; + if (!provider) continue; + + const configured = await provider.isConfigured(); + if (!configured) { + console.log(` ${provider.icon} ${provider.name}: not configured`); + continue; + } + + const result = await provider.refresh(); + const status = result.state === 'success' ? '✓' : '✗'; + console.log(` ${provider.icon} ${provider.name}: ${status}`); + } + }); + +function printStatus(results: Record) { + console.log('CodexBar Status\n'); + console.log('─'.repeat(50)); + + for (const [name, data] of Object.entries(results)) { + const provider = providers[name]; + if (!provider) continue; + + console.log(`\n${provider.icon} ${provider.name}`); + + if (data.status === 'not configured') { + console.log(' Status: Not configured'); + continue; + } + + if (data.status === 'error') { + console.log(` Status: Error - ${data.error}`); + continue; + } + + if (data.usage) { + if (data.usage.session) { + const s = data.usage.session; + console.log(` Session: ${s.displayString} (${s.percentage}%)`); + if (s.resetCountdown) { + console.log(` Resets: ${s.resetCountdown}`); + } + } + if (data.usage.weekly) { + const w = data.usage.weekly; + console.log(` Weekly: ${w.displayString} (${w.percentage}%)`); + } + if (data.usage.monthly) { + const m = data.usage.monthly; + console.log(` Monthly: ${m.displayString} (${m.percentage}%)`); + } + if (data.usage.cost) { + console.log(` Cost: ${data.usage.cost.displayString}`); + } + } else { + console.log(' No usage data available'); + } + } + + console.log('\n' + '─'.repeat(50)); +} + +program.parse(); diff --git a/codexbar-electron/src/main/index.ts b/codexbar-electron/src/main/index.ts new file mode 100644 index 00000000..5dd1337a --- /dev/null +++ b/codexbar-electron/src/main/index.ts @@ -0,0 +1,238 @@ +/** + * CodexBar - Main Process Entry Point + * + * This is the Electron main process that handles: + * - System tray integration + * - Provider management and polling + * - IPC communication with renderer + * - Auto-updates + */ + +import { app, BrowserWindow, Tray, Menu, nativeImage, ipcMain } from 'electron'; +import path from 'path'; +import { ProviderManager } from './providers/ProviderManager'; +import { SettingsStore } from './store/SettingsStore'; +import { UsageStore } from './store/UsageStore'; +import { setupAutoUpdater } from './updater'; +import { createTrayMenu } from './tray/TrayMenu'; +import { logger } from './utils/logger'; + +// Keep references to prevent garbage collection +let tray: Tray | null = null; +let settingsWindow: BrowserWindow | null = null; +let providerManager: ProviderManager | null = null; +let settingsStore: SettingsStore | null = null; +let usageStore: UsageStore | null = null; + +// Prevent multiple instances +const gotTheLock = app.requestSingleInstanceLock(); +if (!gotTheLock) { + app.quit(); +} + +async function createTray(): Promise { + // Create tray icon + const iconPath = path.join(__dirname, '../../assets/icon.png'); + let trayIcon: Electron.NativeImage; + + try { + trayIcon = nativeImage.createFromPath(iconPath); + if (trayIcon.isEmpty()) { + throw new Error('Icon loaded but is empty'); + } + // Resize for system tray (16x16 on Windows) + trayIcon = trayIcon.resize({ width: 16, height: 16 }); + logger.info('Tray icon loaded from:', iconPath); + } catch (err) { + // Create a simple colored icon as fallback + logger.warn('Tray icon not found, creating fallback icon:', err); + // Create a 16x16 icon with a simple design + const size = 16; + const canvas = ` + + + C + + `; + trayIcon = nativeImage.createFromDataURL( + `data:image/svg+xml;base64,${Buffer.from(canvas).toString('base64')}` + ); + trayIcon = trayIcon.resize({ width: 16, height: 16 }); + } + + tray = new Tray(trayIcon); + tray.setToolTip('CodexBar - AI Usage Monitor'); + + // Update tray menu + await updateTrayMenu(); + + // Handle click (Windows: show menu, Linux: might differ) + tray.on('click', () => { + tray?.popUpContextMenu(); + }); +} + +async function updateTrayMenu(): Promise { + if (!tray || !providerManager || !settingsStore || !usageStore) return; + + const menu = await createTrayMenu({ + providerManager, + settingsStore, + usageStore, + onSettingsClick: () => createSettingsWindow(), + onQuitClick: () => app.quit(), + onRefreshClick: () => providerManager?.refreshAll(), + }); + + tray.setContextMenu(menu); +} + +function createSettingsWindow(): void { + if (settingsWindow) { + settingsWindow.focus(); + return; + } + + const iconPath = path.join(__dirname, '../../assets/icon.png'); + + settingsWindow = new BrowserWindow({ + width: 500, + height: 600, + title: 'CodexBar', + icon: iconPath, // Set the window icon explicitly for taskbar + backgroundColor: '#09090b', + titleBarStyle: 'hidden', + titleBarOverlay: { + color: '#09090b', + symbolColor: '#a1a1aa', + height: 36 + }, + trafficLightPosition: { x: 16, y: 16 }, + resizable: true, + minimizable: true, + maximizable: false, + show: false, // Don't show until ready-to-show to prevent white flash + webPreferences: { + nodeIntegration: false, + contextIsolation: true, + preload: path.join(__dirname, 'preload.js'), + sandbox: false // Required for some electron-store operations in renderer if used directly + }, + }); + + // Graceful showing + settingsWindow.once('ready-to-show', () => { + settingsWindow?.show(); + }); + + // Load the renderer + if (process.env.NODE_ENV === 'development') { + settingsWindow.loadURL('http://localhost:5173'); + // settingsWindow.webContents.openDevTools({ mode: 'detach' }); + } else { + settingsWindow.loadFile(path.join(__dirname, '../renderer/index.html')); + } + + settingsWindow.on('closed', () => { + settingsWindow = null; + }); +} + +function setupIPC(): void { + // Get all provider states + ipcMain.handle('get-providers', async () => { + return providerManager?.getAllProviderStates() ?? []; + }); + + // Get settings + ipcMain.handle('get-settings', async () => { + return settingsStore?.getAll() ?? {}; + }); + + // Update settings + ipcMain.handle('set-setting', async (_event, key: string, value: unknown) => { + settingsStore?.setAny(key, value); + await updateTrayMenu(); + }); + + // Toggle provider + ipcMain.handle('toggle-provider', async (_event, providerId: string, enabled: boolean) => { + settingsStore?.setProviderEnabled(providerId, enabled); + if (enabled) { + await providerManager?.refreshProvider(providerId); + } + await updateTrayMenu(); + }); + + // Manual refresh + ipcMain.handle('refresh-all', async () => { + await providerManager?.refreshAll(); + await updateTrayMenu(); + }); + + // Get usage data + ipcMain.handle('get-usage', async () => { + return usageStore?.getAll() ?? {}; + }); +} + +async function initialize(): Promise { + logger.info('CodexBar starting...'); + + // Remove default menu for a cleaner look + Menu.setApplicationMenu(null); + + // Initialize stores + settingsStore = new SettingsStore(); + usageStore = new UsageStore(); + + // Initialize provider manager + providerManager = new ProviderManager(settingsStore, usageStore); + + // Set up IPC handlers + setupIPC(); + + // Create system tray + await createTray(); + + // Start provider polling + providerManager.on('update', async () => { + await updateTrayMenu(); + }); + + await providerManager.startPolling(); + + // Set up auto-updater (production only) + if (process.env.NODE_ENV !== 'development') { + setupAutoUpdater(); + } + + logger.info('CodexBar initialized successfully'); +} + +// App lifecycle +app.on('ready', initialize); + +app.on('window-all-closed', () => { + // Don't quit on window close - we're a tray app +}); + +app.on('before-quit', () => { + providerManager?.stopPolling(); +}); + +app.on('second-instance', () => { + // Focus settings window if trying to launch second instance + if (settingsWindow) { + settingsWindow.focus(); + } +}); + +// Handle uncaught errors +process.on('uncaughtException', (error) => { + logger.error('Uncaught exception:', error); +}); + +process.on('unhandledRejection', (reason) => { + logger.error('Unhandled rejection:', reason); +}); diff --git a/codexbar-electron/src/main/preload.ts b/codexbar-electron/src/main/preload.ts new file mode 100644 index 00000000..e532859a --- /dev/null +++ b/codexbar-electron/src/main/preload.ts @@ -0,0 +1,74 @@ +/** + * Preload script - exposes safe APIs to renderer process + */ + +import { contextBridge, ipcRenderer } from 'electron'; + +// Expose protected methods to the renderer process +contextBridge.exposeInMainWorld('codexbar', { + // Provider methods + getProviders: () => ipcRenderer.invoke('get-providers'), + toggleProvider: (id: string, enabled: boolean) => + ipcRenderer.invoke('toggle-provider', id, enabled), + refreshAll: () => ipcRenderer.invoke('refresh-all'), + + // Settings methods + getSettings: () => ipcRenderer.invoke('get-settings'), + setSetting: (key: string, value: unknown) => + ipcRenderer.invoke('set-setting', key, value), + + // Usage methods + getUsage: () => ipcRenderer.invoke('get-usage'), + + // Event listeners + onUpdate: (callback: () => void) => { + ipcRenderer.on('providers-updated', callback); + return () => ipcRenderer.removeListener('providers-updated', callback); + }, +}); + +// Type definitions for the exposed API +export interface CodexBarAPI { + getProviders: () => Promise; + toggleProvider: (id: string, enabled: boolean) => Promise; + refreshAll: () => Promise; + getSettings: () => Promise; + setSetting: (key: string, value: unknown) => Promise; + getUsage: () => Promise; + onUpdate: (callback: () => void) => () => void; +} + +export interface ProviderState { + id: string; + name: string; + enabled: boolean; + status: 'ok' | 'loading' | 'error' | 'disabled'; + usage?: { + used: number; + limit: number; + percentage: number; + resetTime?: string; + }; + error?: string; +} + +export interface Settings { + enabledProviders: string[]; + refreshInterval: number; + showNotifications: boolean; + startAtLogin: boolean; +} + +export interface UsageData { + [providerId: string]: { + session: { used: number; limit: number }; + weekly: { used: number; limit: number }; + lastUpdated: string; + }; +} + +declare global { + interface Window { + codexbar: CodexBarAPI; + } +} diff --git a/codexbar-electron/src/main/providers/BaseProvider.ts b/codexbar-electron/src/main/providers/BaseProvider.ts new file mode 100644 index 00000000..33e275bb --- /dev/null +++ b/codexbar-electron/src/main/providers/BaseProvider.ts @@ -0,0 +1,178 @@ +/** + * Base Provider Interface + * + * All AI providers must implement this interface. + * Mirrors the Swift architecture from the macOS app. + */ + +export interface UsageInfo { + /** Amount used (requests, tokens, or credits depending on provider) */ + used: number; + /** Maximum limit */ + limit: number; + /** Percentage used (0-100) */ + percentage: number; + /** Human-readable usage string */ + displayString: string; + /** When the usage resets (ISO 8601) */ + resetTime?: string; + /** Human-readable reset countdown */ + resetCountdown?: string; +} + +export interface ProviderUsage { + /** Session/daily usage */ + session?: UsageInfo; + /** Weekly usage */ + weekly?: UsageInfo; + /** Monthly usage */ + monthly?: UsageInfo; + /** Cost in dollars (for cost-based providers) */ + cost?: { + amount: number; + currency: string; + displayString: string; + }; +} + +export interface ProviderStatus { + /** Provider is operational */ + operational: boolean; + /** Current status message */ + message?: string; + /** Active incidents */ + incidents?: Array<{ + title: string; + status: string; + url?: string; + }>; +} + +export type ProviderState = 'idle' | 'loading' | 'success' | 'error'; + +export interface ProviderResult { + state: ProviderState; + usage?: ProviderUsage; + status?: ProviderStatus; + error?: string; + lastUpdated: Date; +} + +/** + * Base class for all AI providers + */ +export abstract class BaseProvider { + /** Unique identifier for this provider */ + abstract readonly id: string; + + /** Display name */ + abstract readonly name: string; + + /** Provider icon (emoji or path) */ + abstract readonly icon: string; + + /** Provider website URL */ + abstract readonly websiteUrl: string; + + /** Status page URL (for incident checking) */ + abstract readonly statusPageUrl?: string; + + /** Current state */ + protected _result: ProviderResult = { + state: 'idle', + lastUpdated: new Date(), + }; + + get result(): ProviderResult { + return this._result; + } + + /** + * Fetch usage data from the provider + */ + abstract fetchUsage(): Promise; + + /** + * Fetch provider status (optional) + */ + async fetchStatus(): Promise { + return null; + } + + /** + * Check if the provider is configured/authenticated + */ + abstract isConfigured(): Promise; + + /** + * Refresh all data for this provider + */ + async refresh(): Promise { + this._result = { + ...this._result, + state: 'loading', + }; + + try { + const [usage, status] = await Promise.all([ + this.fetchUsage(), + this.fetchStatus(), + ]); + + this._result = { + state: 'success', + usage: usage ?? undefined, + status: status ?? undefined, + lastUpdated: new Date(), + }; + } catch (error) { + this._result = { + state: 'error', + error: error instanceof Error ? error.message : 'Unknown error', + lastUpdated: new Date(), + }; + } + + return this._result; + } +} + +/** + * Helper to calculate percentage + */ +export function calculatePercentage(used: number, limit: number): number { + if (limit <= 0) return 0; + return Math.min(100, Math.round((used / limit) * 100)); +} + +/** + * Helper to format usage string + */ +export function formatUsage(used: number, limit: number, unit = ''): string { + const suffix = unit ? ` ${unit}` : ''; + return `${used.toLocaleString()}${suffix} / ${limit.toLocaleString()}${suffix}`; +} + +/** + * Helper to format reset countdown + */ +export function formatResetCountdown(resetTime: Date): string { + const now = new Date(); + const diff = resetTime.getTime() - now.getTime(); + + if (diff <= 0) return 'Resetting...'; + + const hours = Math.floor(diff / (1000 * 60 * 60)); + const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)); + + if (hours > 24) { + const days = Math.floor(hours / 24); + return `${days}d ${hours % 24}h`; + } + + if (hours > 0) { + return `${hours}h ${minutes}m`; + } + + return `${minutes}m`; +} diff --git a/codexbar-electron/src/main/providers/ProviderManager.ts b/codexbar-electron/src/main/providers/ProviderManager.ts new file mode 100644 index 00000000..2a7f8575 --- /dev/null +++ b/codexbar-electron/src/main/providers/ProviderManager.ts @@ -0,0 +1,203 @@ +/** + * Provider Manager + * + * Manages all AI providers, handles polling, and emits updates. + */ + +import { EventEmitter } from 'events'; +import { BaseProvider, ProviderResult } from './BaseProvider'; +import { SettingsStore } from '../store/SettingsStore'; +import { UsageStore } from '../store/UsageStore'; +import { logger } from '../utils/logger'; + +// Import all providers +import { CodexProvider } from './codex/CodexProvider'; +import { ClaudeProvider } from './claude/ClaudeProvider'; +import { CursorProvider } from './cursor/CursorProvider'; +import { GeminiProvider } from './gemini/GeminiProvider'; +import { CopilotProvider } from './copilot/CopilotProvider'; +import { AntigravityProvider } from './antigravity/AntigravityProvider'; +import { FactoryProvider } from './factory/FactoryProvider'; +import { ZaiProvider } from './zai/ZaiProvider'; +import { KiroProvider } from './kiro/KiroProvider'; +import { VertexAIProvider } from './vertexai/VertexAIProvider'; +import { AugmentProvider } from './augment/AugmentProvider'; +import { MiniMaxProvider } from './minimax/MiniMaxProvider'; + +export interface ProviderManagerEvents { + update: () => void; + error: (providerId: string, error: Error) => void; +} + +export class ProviderManager extends EventEmitter { + private providers: Map = new Map(); + private pollingInterval: NodeJS.Timeout | null = null; + private settingsStore: SettingsStore; + private usageStore: UsageStore; + + constructor(settingsStore: SettingsStore, usageStore: UsageStore) { + super(); + this.settingsStore = settingsStore; + this.usageStore = usageStore; + this.initializeProviders(); + } + + private initializeProviders(): void { + // Register all providers + const allProviders: BaseProvider[] = [ + new CodexProvider(), + new ClaudeProvider(), + new CursorProvider(), + new GeminiProvider(), + new CopilotProvider(), + new AntigravityProvider(), + new FactoryProvider(), + new ZaiProvider(), + new KiroProvider(), + new VertexAIProvider(), + new AugmentProvider(), + new MiniMaxProvider(), + ]; + + for (const provider of allProviders) { + this.providers.set(provider.id, provider); + logger.info(`Registered provider: ${provider.name} (${provider.id})`); + } + } + + /** + * Get all registered providers + */ + getAllProviders(): BaseProvider[] { + return Array.from(this.providers.values()); + } + + /** + * Get a specific provider by ID + */ + getProvider(id: string): BaseProvider | undefined { + return this.providers.get(id); + } + + /** + * Get enabled providers based on settings + */ + getEnabledProviders(): BaseProvider[] { + return this.getAllProviders().filter(p => + this.settingsStore.isProviderEnabled(p.id) + ); + } + + /** + * Get state for all providers (for IPC) + */ + getAllProviderStates(): Array<{ + id: string; + name: string; + icon: string; + enabled: boolean; + result: ProviderResult; + }> { + return this.getAllProviders().map(p => ({ + id: p.id, + name: p.name, + icon: p.icon, + enabled: this.settingsStore.isProviderEnabled(p.id), + result: p.result, + })); + } + + /** + * Refresh a specific provider + */ + async refreshProvider(id: string): Promise { + const provider = this.providers.get(id); + if (!provider) { + logger.warn(`Provider not found: ${id}`); + return null; + } + + if (!this.settingsStore.isProviderEnabled(id)) { + logger.debug(`Provider disabled, skipping: ${id}`); + return null; + } + + try { + const isConfigured = await provider.isConfigured(); + if (!isConfigured) { + logger.debug(`Provider not configured: ${id}`); + return null; + } + + logger.info(`Refreshing provider: ${provider.name}`); + const result = await provider.refresh(); + + // Store usage data + if (result.usage) { + this.usageStore.setProviderUsage(id, result.usage); + } + + this.emit('update'); + return result; + } catch (error) { + logger.error(`Error refreshing provider ${id}:`, error); + this.emit('error', id, error); + return null; + } + } + + /** + * Refresh all enabled providers + */ + async refreshAll(): Promise { + logger.info('Refreshing all providers...'); + + const enabledProviders = this.getEnabledProviders(); + + await Promise.allSettled( + enabledProviders.map(p => this.refreshProvider(p.id)) + ); + + logger.info('All providers refreshed'); + this.emit('update'); + } + + /** + * Start polling for updates + */ + async startPolling(): Promise { + // Initial refresh + await this.refreshAll(); + + // Set up polling interval + const intervalMs = this.settingsStore.getRefreshInterval() * 1000; + + this.pollingInterval = setInterval(() => { + this.refreshAll().catch(err => { + logger.error('Polling error:', err); + }); + }, intervalMs); + + logger.info(`Polling started with interval: ${intervalMs}ms`); + } + + /** + * Stop polling + */ + stopPolling(): void { + if (this.pollingInterval) { + clearInterval(this.pollingInterval); + this.pollingInterval = null; + logger.info('Polling stopped'); + } + } + + /** + * Update polling interval + */ + updatePollingInterval(seconds: number): void { + this.stopPolling(); + this.settingsStore.setRefreshInterval(seconds); + this.startPolling(); + } +} diff --git a/codexbar-electron/src/main/providers/antigravity/AntigravityProvider.ts b/codexbar-electron/src/main/providers/antigravity/AntigravityProvider.ts new file mode 100644 index 00000000..592b0810 --- /dev/null +++ b/codexbar-electron/src/main/providers/antigravity/AntigravityProvider.ts @@ -0,0 +1,136 @@ +/** + * Antigravity Provider + * + * Antigravity stores conversation data in ~/.gemini/antigravity/conversations/ + * as .pb (protobuf) files. Since protobuf parsing is complex, we'll check + * for the presence of conversations and provide basic stats. + */ + +import { BaseProvider, ProviderUsage, ProviderStatus } from '../BaseProvider'; +import { runCommand } from '../../utils/subprocess'; +import { logger } from '../../utils/logger'; +import path from 'path'; +import fs from 'fs/promises'; +import os from 'os'; + +export class AntigravityProvider extends BaseProvider { + readonly id = 'antigravity'; + readonly name = 'Antigravity'; + readonly icon = '🚀'; + readonly websiteUrl = 'https://antigravity.dev'; + readonly statusPageUrl = undefined; + + private antigravityDir = path.join(os.homedir(), '.gemini', 'antigravity'); + + async isConfigured(): Promise { + try { + // Check if antigravity CLI is available + const result = await runCommand('antigravity', ['--version']); + if (result.exitCode === 0) return true; + } catch { + // CLI not found + } + + // Check for antigravity directory + try { + await fs.access(this.antigravityDir); + return true; + } catch { + return false; + } + } + + async fetchUsage(): Promise { + try { + const conversationsDir = path.join(this.antigravityDir, 'conversations'); + + try { + await fs.access(conversationsDir); + } catch { + logger.debug('Antigravity conversations directory not found'); + return null; + } + + // Count conversation files + const files = await fs.readdir(conversationsDir); + const pbFiles = files.filter(f => f.endsWith('.pb')); + + if (pbFiles.length === 0) { + return null; + } + + // Get file stats to calculate total size (proxy for usage) + let totalSize = 0; + let latestModified = new Date(0); + + for (const file of pbFiles) { + try { + const stat = await fs.stat(path.join(conversationsDir, file)); + totalSize += stat.size; + if (stat.mtime > latestModified) { + latestModified = stat.mtime; + } + } catch { + // Skip files we can't stat + } + } + + // Format size + const sizeStr = formatSize(totalSize); + const lastUsed = formatRelativeTime(latestModified); + + return { + session: { + used: pbFiles.length, + limit: 0, // No limit + percentage: 0, + displayString: `${pbFiles.length} conversations · ${sizeStr}`, + }, + monthly: { + used: pbFiles.length, + limit: 0, + percentage: 0, + displayString: `Last active: ${lastUsed}`, + }, + }; + } catch (error) { + logger.error('Failed to fetch Antigravity usage:', error); + return null; + } + } + + async fetchStatus(): Promise { + return { operational: true }; + } +} + +/** + * Format bytes to human readable size + */ +function formatSize(bytes: number): string { + if (bytes >= 1024 * 1024) { + return `${(bytes / (1024 * 1024)).toFixed(1)} MB`; + } + if (bytes >= 1024) { + return `${(bytes / 1024).toFixed(1)} KB`; + } + return `${bytes} B`; +} + +/** + * Format date to relative time string + */ +function formatRelativeTime(date: Date): string { + const now = new Date(); + const diffMs = now.getTime() - date.getTime(); + const diffMins = Math.floor(diffMs / 60000); + const diffHours = Math.floor(diffMins / 60); + const diffDays = Math.floor(diffHours / 24); + + if (diffMins < 1) return 'just now'; + if (diffMins < 60) return `${diffMins}m ago`; + if (diffHours < 24) return `${diffHours}h ago`; + if (diffDays < 7) return `${diffDays}d ago`; + + return date.toLocaleDateString(); +} diff --git a/codexbar-electron/src/main/providers/augment/AugmentProvider.ts b/codexbar-electron/src/main/providers/augment/AugmentProvider.ts new file mode 100644 index 00000000..2c4df472 --- /dev/null +++ b/codexbar-electron/src/main/providers/augment/AugmentProvider.ts @@ -0,0 +1,113 @@ +/** + * Augment Provider + * + * Augment is an AI coding assistant. This provider checks for + * Augment CLI, VS Code extension, or configuration files. + */ + +import { BaseProvider, ProviderUsage, ProviderStatus } from '../BaseProvider'; +import { runCommand } from '../../utils/subprocess'; +import { logger } from '../../utils/logger'; +import path from 'path'; +import fs from 'fs/promises'; +import os from 'os'; + +export class AugmentProvider extends BaseProvider { + readonly id = 'augment'; + readonly name = 'Augment'; + readonly icon = '🔮'; + readonly websiteUrl = 'https://augment.dev'; + readonly statusPageUrl = undefined; + + async isConfigured(): Promise { + // Check for augment CLI + try { + const result = await runCommand('augment', ['--version']); + if (result.exitCode === 0) return true; + } catch { + // CLI not found + } + + // Check for VS Code extension + const vscodeExtensions = path.join(os.homedir(), '.vscode', 'extensions'); + try { + const extensions = await fs.readdir(vscodeExtensions); + const hasAugment = extensions.some(ext => + ext.toLowerCase().includes('augment') + ); + if (hasAugment) return true; + } catch { + // Extensions dir not found + } + + // Check for config directories + const configPaths = [ + path.join(os.homedir(), '.augment'), + path.join(os.homedir(), '.config', 'augment'), + path.join(os.homedir(), 'AppData', 'Roaming', 'Augment'), + path.join(os.homedir(), 'AppData', 'Local', 'Augment'), + ]; + + for (const configPath of configPaths) { + try { + await fs.access(configPath); + return true; + } catch { + // Try next + } + } + + return false; + } + + async fetchUsage(): Promise { + // Try to get version from CLI + try { + const result = await runCommand('augment', ['--version']); + if (result.exitCode === 0) { + return { + session: { + used: 0, + limit: 0, + percentage: 0, + displayString: `CLI ${result.stdout.trim() || 'installed'}`, + }, + }; + } + } catch { + // CLI not available + } + + // Check for VS Code extension + const vscodeExtensions = path.join(os.homedir(), '.vscode', 'extensions'); + try { + const extensions = await fs.readdir(vscodeExtensions); + const augmentExt = extensions.find(ext => + ext.toLowerCase().includes('augment') + ); + if (augmentExt) { + // Try to extract version + const versionMatch = augmentExt.match(/augment[^-]*-(\d+\.\d+\.\d+)/i); + const version = versionMatch ? `v${versionMatch[1]}` : ''; + + return { + session: { + used: 0, + limit: 0, + percentage: 0, + displayString: `VS Code${version ? ` ${version}` : ''}`, + }, + }; + } + } catch { + // Extensions dir not found + } + + logger.debug('Augment: Not configured'); + return null; + } + + async fetchStatus(): Promise { + return { operational: true }; + } +} diff --git a/codexbar-electron/src/main/providers/claude/ClaudeProvider.ts b/codexbar-electron/src/main/providers/claude/ClaudeProvider.ts new file mode 100644 index 00000000..d13e37f2 --- /dev/null +++ b/codexbar-electron/src/main/providers/claude/ClaudeProvider.ts @@ -0,0 +1,200 @@ +/** + * Claude (Anthropic) Provider + * + * Fetches usage from Claude CLI's stats-cache.json file stored in ~/.claude/ + * This file contains detailed usage statistics including: + * - Daily activity (message count, session count, tool calls) + * - Token usage by model + * - Total sessions and messages + */ + +import { BaseProvider, ProviderUsage, ProviderStatus, calculatePercentage } from '../BaseProvider'; +import { runCommand } from '../../utils/subprocess'; +import { logger } from '../../utils/logger'; +import path from 'path'; +import fs from 'fs/promises'; +import os from 'os'; + +interface DailyActivity { + date: string; + messageCount: number; + sessionCount: number; + toolCallCount: number; +} + +interface DailyModelTokens { + date: string; + tokensByModel: Record; +} + +interface ModelUsageStats { + inputTokens: number; + outputTokens: number; + cacheReadInputTokens: number; + cacheCreationInputTokens: number; + webSearchRequests: number; + costUSD: number; + contextWindow: number; +} + +interface ClaudeStatsCache { + version: number; + lastComputedDate: string; + dailyActivity: DailyActivity[]; + dailyModelTokens: DailyModelTokens[]; + modelUsage: Record; + totalSessions: number; + totalMessages: number; + longestSession?: { + sessionId: string; + duration: number; + messageCount: number; + timestamp: string; + }; + firstSessionDate?: string; + hourCounts?: Record; +} + +export class ClaudeProvider extends BaseProvider { + readonly id = 'claude'; + readonly name = 'Claude'; + readonly icon = '🎭'; + readonly websiteUrl = 'https://claude.ai'; + readonly statusPageUrl = 'https://status.anthropic.com'; + + private claudeDir = path.join(os.homedir(), '.claude'); + + async isConfigured(): Promise { + try { + // Check if claude CLI is available + const result = await runCommand('claude', ['--version']); + if (result.exitCode === 0) return true; + } catch { + // CLI not found, check for config directory + } + + // Check for .claude directory with stats + const statsPath = path.join(this.claudeDir, 'stats-cache.json'); + try { + await fs.access(statsPath); + return true; + } catch { + return false; + } + } + + async fetchUsage(): Promise { + try { + // Read stats from ~/.claude/stats-cache.json + const statsPath = path.join(this.claudeDir, 'stats-cache.json'); + + try { + await fs.access(statsPath); + } catch { + logger.debug('Claude stats-cache.json not found'); + return null; + } + + const content = await fs.readFile(statsPath, 'utf-8'); + const stats: ClaudeStatsCache = JSON.parse(content); + + return this.parseStatsCache(stats); + } catch (error) { + logger.error('Failed to fetch Claude usage:', error); + return null; + } + } + + private parseStatsCache(stats: ClaudeStatsCache): ProviderUsage | null { + const usage: ProviderUsage = {}; + + // Get today's date + const today = new Date(); + const todayStr = today.toISOString().split('T')[0]; + + // Get week start (Sunday) + const weekStart = new Date(today); + weekStart.setDate(today.getDate() - today.getDay()); + const weekStartStr = weekStart.toISOString().split('T')[0]; + + // Get month start + const monthStart = new Date(today.getFullYear(), today.getMonth(), 1); + const monthStartStr = monthStart.toISOString().split('T')[0]; + + // Calculate daily usage + const todayActivity = stats.dailyActivity.find(a => a.date === todayStr); + const todayTokens = stats.dailyModelTokens.find(t => t.date === todayStr); + + if (todayActivity || todayTokens) { + const messages = todayActivity?.messageCount ?? 0; + const sessions = todayActivity?.sessionCount ?? 0; + const tokens = todayTokens ? Object.values(todayTokens.tokensByModel).reduce((a, b) => a + b, 0) : 0; + + usage.session = { + used: tokens, + limit: 1000000, // No hard limit, using arbitrary high value + percentage: Math.min(100, Math.round((tokens / 1000000) * 100)), + displayString: `${messages} msgs · ${sessions} sessions · ${formatTokenCount(tokens)} tokens`, + }; + } + + // Calculate weekly usage + const weeklyActivity = stats.dailyActivity.filter(a => a.date >= weekStartStr); + const weeklyTokensData = stats.dailyModelTokens.filter(t => t.date >= weekStartStr); + + if (weeklyActivity.length > 0 || weeklyTokensData.length > 0) { + const messages = weeklyActivity.reduce((sum, a) => sum + a.messageCount, 0); + const sessions = weeklyActivity.reduce((sum, a) => sum + a.sessionCount, 0); + const tokens = weeklyTokensData.reduce((sum, t) => + sum + Object.values(t.tokensByModel).reduce((a, b) => a + b, 0), 0 + ); + + usage.weekly = { + used: tokens, + limit: 10000000, + percentage: Math.min(100, Math.round((tokens / 10000000) * 100)), + displayString: `${messages} msgs · ${sessions} sessions · ${formatTokenCount(tokens)} tokens`, + }; + } + + // Calculate monthly usage (all time from model usage) + const totalInputTokens = Object.values(stats.modelUsage).reduce((sum, m) => sum + m.inputTokens, 0); + const totalOutputTokens = Object.values(stats.modelUsage).reduce((sum, m) => sum + m.outputTokens, 0); + const totalTokens = totalInputTokens + totalOutputTokens; + + if (stats.totalMessages > 0) { + usage.monthly = { + used: totalTokens, + limit: 50000000, + percentage: Math.min(100, Math.round((totalTokens / 50000000) * 100)), + displayString: `${stats.totalMessages} msgs · ${stats.totalSessions} sessions · ${formatTokenCount(totalTokens)} tokens`, + }; + } + + // Log model breakdown + logger.info('Claude usage by model:'); + for (const [model, modelStats] of Object.entries(stats.modelUsage)) { + const modelTokens = modelStats.inputTokens + modelStats.outputTokens; + logger.info(` ${model}: ${formatTokenCount(modelStats.inputTokens)} in, ${formatTokenCount(modelStats.outputTokens)} out`); + } + + return Object.keys(usage).length > 0 ? usage : null; + } + + async fetchStatus(): Promise { + return { operational: true }; + } +} + +/** + * Format token count for display (e.g., 1234 -> "1.2K", 1234567 -> "1.2M") + */ +function formatTokenCount(count: number): string { + if (count >= 1000000) { + return `${(count / 1000000).toFixed(1)}M`; + } + if (count >= 1000) { + return `${(count / 1000).toFixed(1)}K`; + } + return count.toString(); +} diff --git a/codexbar-electron/src/main/providers/codex/CodexProvider.ts b/codexbar-electron/src/main/providers/codex/CodexProvider.ts new file mode 100644 index 00000000..2b6c6f71 --- /dev/null +++ b/codexbar-electron/src/main/providers/codex/CodexProvider.ts @@ -0,0 +1,67 @@ +/** + * Codex (OpenAI) Provider + * + * The Codex CLI doesn't store usage data locally or provide a status command. + * This provider checks if the CLI is installed and configured. + * Usage tracking would require API integration with OpenAI's usage dashboard. + */ + +import { BaseProvider, ProviderUsage, ProviderStatus } from '../BaseProvider'; +import { runCommand } from '../../utils/subprocess'; +import { logger } from '../../utils/logger'; +import path from 'path'; +import fs from 'fs/promises'; +import os from 'os'; + +export class CodexProvider extends BaseProvider { + readonly id = 'codex'; + readonly name = 'Codex'; + readonly icon = '🤖'; + readonly websiteUrl = 'https://platform.openai.com'; + readonly statusPageUrl = 'https://status.openai.com'; + + private codexDir = path.join(os.homedir(), '.codex'); + + async isConfigured(): Promise { + try { + // Check if codex CLI is available + const result = await runCommand('codex', ['--version']); + return result.exitCode === 0; + } catch { + return false; + } + } + + async fetchUsage(): Promise { + // The Codex CLI doesn't have a status/usage command + // and doesn't store usage data locally. + // We can only confirm the CLI is installed and working. + + try { + const result = await runCommand('codex', ['--version']); + + if (result.exitCode === 0) { + // CLI is working, return a basic status + // Extract version from output + const version = result.stdout.trim() || 'installed'; + + return { + session: { + used: 0, + limit: 0, + percentage: 0, + displayString: `CLI ${version}`, + }, + }; + } + } catch (error) { + logger.debug('Codex CLI check failed:', error); + } + + return null; + } + + async fetchStatus(): Promise { + return { operational: true }; + } +} diff --git a/codexbar-electron/src/main/providers/copilot/CopilotProvider.ts b/codexbar-electron/src/main/providers/copilot/CopilotProvider.ts new file mode 100644 index 00000000..3e24deb3 --- /dev/null +++ b/codexbar-electron/src/main/providers/copilot/CopilotProvider.ts @@ -0,0 +1,116 @@ +/** + * GitHub Copilot Provider + * + * GitHub Copilot is typically accessed through VS Code or other IDE extensions. + * This provider checks for the presence of the Copilot extension and GitHub CLI auth. + * Copilot doesn't expose usage limits - it's unlimited for paid subscribers. + */ + +import { BaseProvider, ProviderUsage, ProviderStatus } from '../BaseProvider'; +import { runCommand } from '../../utils/subprocess'; +import { logger } from '../../utils/logger'; +import path from 'path'; +import fs from 'fs/promises'; +import os from 'os'; + +export class CopilotProvider extends BaseProvider { + readonly id = 'copilot'; + readonly name = 'GitHub Copilot'; + readonly icon = '🐙'; + readonly websiteUrl = 'https://github.com/features/copilot'; + readonly statusPageUrl = 'https://www.githubstatus.com'; + + async isConfigured(): Promise { + // Check multiple possible configurations + + // 1. Check GitHub CLI auth + const ghConfigPaths = [ + path.join(os.homedir(), '.config', 'gh', 'hosts.yml'), + path.join(os.homedir(), 'AppData', 'Roaming', 'GitHub CLI', 'hosts.yml'), + ]; + + for (const configPath of ghConfigPaths) { + try { + await fs.access(configPath); + return true; + } catch { + // Try next path + } + } + + // 2. Check for VS Code Copilot extension + const vscodeExtensions = path.join(os.homedir(), '.vscode', 'extensions'); + try { + const extensions = await fs.readdir(vscodeExtensions); + const hasCopilot = extensions.some(ext => + ext.startsWith('github.copilot') || ext.includes('copilot') + ); + if (hasCopilot) return true; + } catch { + // VS Code extensions dir not found + } + + // 3. Check for GitHub CLI with copilot extension + try { + const result = await runCommand('gh', ['extension', 'list']); + if (result.exitCode === 0 && result.stdout.toLowerCase().includes('copilot')) { + return true; + } + } catch { + // gh CLI not available + } + + return false; + } + + async fetchUsage(): Promise { + // GitHub Copilot doesn't have usage limits for paid subscribers + // We can check the subscription status via gh CLI if available + + let subscriptionInfo = 'Active'; + + try { + // Try to get GitHub user info to confirm auth + const result = await runCommand('gh', ['auth', 'status'], { timeout: 10000 }); + + if (result.exitCode === 0) { + // Extract account info from output + const accountMatch = result.stdout.match(/Logged in to [^\s]+ account (\w+)/i) || + result.stderr.match(/Logged in to [^\s]+ account (\w+)/i); + if (accountMatch) { + subscriptionInfo = `@${accountMatch[1]}`; + } + } + } catch (error) { + logger.debug('Could not get GitHub auth status:', error); + } + + // Check for Copilot extension version + const vscodeExtensions = path.join(os.homedir(), '.vscode', 'extensions'); + try { + const extensions = await fs.readdir(vscodeExtensions); + const copilotExt = extensions.find(ext => ext.startsWith('github.copilot-')); + if (copilotExt) { + const versionMatch = copilotExt.match(/github\.copilot-(\d+\.\d+\.\d+)/); + if (versionMatch) { + subscriptionInfo += ` · v${versionMatch[1]}`; + } + } + } catch { + // Ignore + } + + return { + session: { + used: 0, + limit: 0, // 0 limit indicates unlimited + percentage: 0, + displayString: subscriptionInfo, + }, + }; + } + + async fetchStatus(): Promise { + return { operational: true }; + } +} diff --git a/codexbar-electron/src/main/providers/cursor/CursorProvider.ts b/codexbar-electron/src/main/providers/cursor/CursorProvider.ts new file mode 100644 index 00000000..5622aafa --- /dev/null +++ b/codexbar-electron/src/main/providers/cursor/CursorProvider.ts @@ -0,0 +1,170 @@ +/** + * Cursor Provider + * + * Cursor is an AI-powered code editor. This provider checks for Cursor installation + * and attempts to read usage data if available. + * + * Note: Cursor doesn't have a CLI and stores auth in various locations depending + * on the platform. The API requires authentication that's tied to the desktop app. + */ + +import { BaseProvider, ProviderUsage, ProviderStatus, calculatePercentage, formatUsage } from '../BaseProvider'; +import { logger } from '../../utils/logger'; +import path from 'path'; +import fs from 'fs/promises'; +import os from 'os'; + +interface CursorUsageResponse { + 'gpt-4': { numRequests: number; maxRequestUsage: number | null }; + 'gpt-3.5-turbo': { numRequests: number; maxRequestUsage: number | null }; + 'gpt-4o'?: { numRequests: number; maxRequestUsage: number | null }; + startOfMonth?: string; +} + +export class CursorProvider extends BaseProvider { + readonly id = 'cursor'; + readonly name = 'Cursor'; + readonly icon = '📝'; + readonly websiteUrl = 'https://cursor.sh'; + readonly statusPageUrl = 'https://status.cursor.sh'; + + async isConfigured(): Promise { + // Check if Cursor is installed by looking for its data directories + const cursorPaths = [ + // Windows + path.join(os.homedir(), 'AppData', 'Roaming', 'Cursor'), + path.join(os.homedir(), 'AppData', 'Local', 'Programs', 'cursor'), + // macOS + path.join(os.homedir(), 'Library', 'Application Support', 'Cursor'), + // Linux + path.join(os.homedir(), '.config', 'Cursor'), + path.join(os.homedir(), '.cursor'), + ]; + + for (const cursorPath of cursorPaths) { + try { + await fs.access(cursorPath); + return true; + } catch { + // Try next path + } + } + + return false; + } + + private async getAuthToken(): Promise { + // Cursor stores auth in different locations per platform + const possiblePaths = [ + path.join(os.homedir(), '.cursor', 'auth.json'), + path.join(os.homedir(), 'AppData', 'Roaming', 'Cursor', 'auth.json'), + path.join(os.homedir(), 'AppData', 'Roaming', 'Cursor', 'User', 'globalStorage', 'auth.json'), + path.join(os.homedir(), '.config', 'Cursor', 'auth.json'), + path.join(os.homedir(), 'Library', 'Application Support', 'Cursor', 'auth.json'), + ]; + + for (const authPath of possiblePaths) { + try { + const content = await fs.readFile(authPath, 'utf-8'); + const auth = JSON.parse(content); + if (auth.accessToken) { + return auth.accessToken; + } + } catch { + // Try next path + } + } + + return null; + } + + async fetchUsage(): Promise { + // Check if Cursor is installed + const isInstalled = await this.isConfigured(); + + if (!isInstalled) { + return null; + } + + // Try to get auth token and fetch from API + const token = await this.getAuthToken(); + + if (token) { + try { + const response = await fetch('https://www.cursor.com/api/usage', { + headers: { + 'Authorization': `Bearer ${token}`, + 'Content-Type': 'application/json', + }, + }); + + if (response.ok) { + const data = await response.json() as CursorUsageResponse; + return this.parseUsageResponse(data); + } + } catch (error) { + logger.debug('Cursor API request failed:', error); + } + } + + // If no API access, return basic installed status + return { + session: { + used: 0, + limit: 0, + percentage: 0, + displayString: 'Installed', + }, + }; + } + + private parseUsageResponse(data: CursorUsageResponse): ProviderUsage { + // Combine usage across models + let totalUsed = 0; + let totalLimit = 0; + + // GPT-4 usage + if (data['gpt-4']) { + totalUsed += data['gpt-4'].numRequests; + if (data['gpt-4'].maxRequestUsage) { + totalLimit += data['gpt-4'].maxRequestUsage; + } + } + + // GPT-4o usage + if (data['gpt-4o']) { + totalUsed += data['gpt-4o'].numRequests; + if (data['gpt-4o'].maxRequestUsage) { + totalLimit += data['gpt-4o'].maxRequestUsage; + } + } + + // Default limit if not specified (Pro plan typically has 500/month) + if (totalLimit === 0) { + totalLimit = 500; + } + + // Calculate reset time (start of next month) + let resetTime: string | undefined; + if (data.startOfMonth) { + const start = new Date(data.startOfMonth); + const nextMonth = new Date(start); + nextMonth.setMonth(nextMonth.getMonth() + 1); + resetTime = nextMonth.toISOString(); + } + + return { + monthly: { + used: totalUsed, + limit: totalLimit, + percentage: calculatePercentage(totalUsed, totalLimit), + displayString: formatUsage(totalUsed, totalLimit, 'requests'), + resetTime, + }, + }; + } + + async fetchStatus(): Promise { + return { operational: true }; + } +} diff --git a/codexbar-electron/src/main/providers/factory/FactoryProvider.ts b/codexbar-electron/src/main/providers/factory/FactoryProvider.ts new file mode 100644 index 00000000..4d910bc8 --- /dev/null +++ b/codexbar-electron/src/main/providers/factory/FactoryProvider.ts @@ -0,0 +1,100 @@ +/** + * Factory/Droid Provider + * + * Factory.ai (formerly Droid) is an AI coding assistant. + * This provider checks for Factory CLI or configuration files. + */ + +import { BaseProvider, ProviderUsage, ProviderStatus } from '../BaseProvider'; +import { runCommand } from '../../utils/subprocess'; +import { logger } from '../../utils/logger'; +import path from 'path'; +import fs from 'fs/promises'; +import os from 'os'; + +export class FactoryProvider extends BaseProvider { + readonly id = 'factory'; + readonly name = 'Factory'; + readonly icon = '🏭'; + readonly websiteUrl = 'https://factory.ai'; + readonly statusPageUrl = undefined; + + async isConfigured(): Promise { + // Check for factory CLI + try { + const result = await runCommand('factory', ['--version']); + if (result.exitCode === 0) return true; + } catch { + // CLI not found + } + + // Check for droid CLI (old name) + try { + const result = await runCommand('droid', ['--version']); + if (result.exitCode === 0) return true; + } catch { + // CLI not found + } + + // Check for config directories + const configPaths = [ + path.join(os.homedir(), '.factory'), + path.join(os.homedir(), '.droid'), + path.join(os.homedir(), '.config', 'factory'), + ]; + + for (const configPath of configPaths) { + try { + await fs.access(configPath); + return true; + } catch { + // Try next + } + } + + return false; + } + + async fetchUsage(): Promise { + // Try to get version/status from CLI + try { + const result = await runCommand('factory', ['--version']); + if (result.exitCode === 0) { + return { + session: { + used: 0, + limit: 0, + percentage: 0, + displayString: `CLI ${result.stdout.trim() || 'installed'}`, + }, + }; + } + } catch { + // CLI not available + } + + // Try droid CLI + try { + const result = await runCommand('droid', ['--version']); + if (result.exitCode === 0) { + return { + session: { + used: 0, + limit: 0, + percentage: 0, + displayString: `Droid ${result.stdout.trim() || 'installed'}`, + }, + }; + } + } catch { + // CLI not available + } + + logger.debug('Factory: No CLI found'); + return null; + } + + async fetchStatus(): Promise { + return { operational: true }; + } +} diff --git a/codexbar-electron/src/main/providers/gemini/GeminiProvider.ts b/codexbar-electron/src/main/providers/gemini/GeminiProvider.ts new file mode 100644 index 00000000..f84697ba --- /dev/null +++ b/codexbar-electron/src/main/providers/gemini/GeminiProvider.ts @@ -0,0 +1,296 @@ +/** + * Gemini (Google) Provider + * + * Fetches usage from Gemini CLI session files stored in ~/.gemini/tmp/ + * Each session contains messages with token counts that we aggregate. + */ + +import { BaseProvider, ProviderUsage, ProviderStatus, calculatePercentage, formatUsage } from '../BaseProvider'; +import { runCommand } from '../../utils/subprocess'; +import { logger } from '../../utils/logger'; +import path from 'path'; +import fs from 'fs/promises'; +import os from 'os'; + +interface GeminiTokens { + input: number; + output: number; + cached?: number; + thoughts?: number; + tool?: number; + total?: number; +} + +interface GeminiMessage { + id: string; + timestamp: string; + type: string; + content?: string; + tokens?: GeminiTokens; + model?: string; +} + +interface GeminiSession { + sessionId: string; + projectHash: string; + startTime: string; + lastUpdated: string; + messages: GeminiMessage[]; + summary?: string; +} + +interface ModelUsage { + model: string; + requests: number; + inputTokens: number; + outputTokens: number; + cachedTokens: number; +} + +export class GeminiProvider extends BaseProvider { + readonly id = 'gemini'; + readonly name = 'Gemini'; + readonly icon = '💎'; + readonly websiteUrl = 'https://gemini.google.com'; + readonly statusPageUrl = 'https://status.cloud.google.com'; + + private geminiDir = path.join(os.homedir(), '.gemini'); + + async isConfigured(): Promise { + try { + // Check if gemini CLI exists + const result = await runCommand('gemini', ['--version']); + if (result.exitCode === 0) return true; + } catch { + // CLI not found + } + + // Check for .gemini directory with oauth credentials + const oauthPath = path.join(this.geminiDir, 'oauth_creds.json'); + try { + await fs.access(oauthPath); + return true; + } catch { + // Also check for Google Cloud credentials + const credPath = path.join(os.homedir(), '.config', 'gcloud', 'application_default_credentials.json'); + try { + await fs.access(credPath); + return true; + } catch { + return false; + } + } + } + + async fetchUsage(): Promise { + try { + // Read all session files from ~/.gemini/tmp/*/chats/*.json + const usage = await this.aggregateSessionUsage(); + + if (usage) { + return usage; + } + } catch (error) { + logger.error('Failed to fetch Gemini usage:', error); + } + + return null; + } + + /** + * Aggregate usage from all Gemini CLI session files + */ + private async aggregateSessionUsage(): Promise { + const tmpDir = path.join(this.geminiDir, 'tmp'); + + try { + await fs.access(tmpDir); + } catch { + logger.debug('Gemini tmp directory not found'); + return null; + } + + const modelUsage = new Map(); + let totalRequests = 0; + let totalInputTokens = 0; + let totalOutputTokens = 0; + let totalCachedTokens = 0; + + // Get today's date for daily filtering + const today = new Date(); + const todayStr = today.toISOString().split('T')[0]; + + // Get week start (Sunday) + const weekStart = new Date(today); + weekStart.setDate(today.getDate() - today.getDay()); + weekStart.setHours(0, 0, 0, 0); + + // Get month start + const monthStart = new Date(today.getFullYear(), today.getMonth(), 1); + + let dailyInputTokens = 0; + let dailyOutputTokens = 0; + let dailyRequests = 0; + + let weeklyInputTokens = 0; + let weeklyOutputTokens = 0; + let weeklyRequests = 0; + + let monthlyInputTokens = 0; + let monthlyOutputTokens = 0; + let monthlyRequests = 0; + + try { + // List all project directories in tmp + const entries = await fs.readdir(tmpDir, { withFileTypes: true }); + + for (const entry of entries) { + if (!entry.isDirectory() || entry.name === 'bin') continue; + + const chatsDir = path.join(tmpDir, entry.name, 'chats'); + + try { + await fs.access(chatsDir); + } catch { + continue; // No chats directory + } + + // Read all session files + const sessionFiles = await fs.readdir(chatsDir); + + for (const file of sessionFiles) { + if (!file.endsWith('.json') || !file.startsWith('session-')) continue; + + const sessionPath = path.join(chatsDir, file); + + try { + const content = await fs.readFile(sessionPath, 'utf-8'); + const session: GeminiSession = JSON.parse(content); + + // Process each message with tokens + for (const message of session.messages) { + if (!message.tokens || message.type !== 'gemini') continue; + + const { input, output, cached = 0 } = message.tokens; + const model = message.model || 'unknown'; + const msgDate = new Date(message.timestamp); + + // Aggregate by model + const existing = modelUsage.get(model) || { + model, + requests: 0, + inputTokens: 0, + outputTokens: 0, + cachedTokens: 0, + }; + + existing.requests += 1; + existing.inputTokens += input; + existing.outputTokens += output; + existing.cachedTokens += cached; + modelUsage.set(model, existing); + + // Total counters + totalRequests += 1; + totalInputTokens += input; + totalOutputTokens += output; + totalCachedTokens += cached; + + // Time-based filtering + if (msgDate.toISOString().split('T')[0] === todayStr) { + dailyRequests += 1; + dailyInputTokens += input; + dailyOutputTokens += output; + } + + if (msgDate >= weekStart) { + weeklyRequests += 1; + weeklyInputTokens += input; + weeklyOutputTokens += output; + } + + if (msgDate >= monthStart) { + monthlyRequests += 1; + monthlyInputTokens += input; + monthlyOutputTokens += output; + } + } + } catch (err) { + logger.debug(`Failed to parse session file ${file}:`, err); + } + } + } + } catch (error) { + logger.error('Failed to read Gemini sessions:', error); + return null; + } + + if (totalRequests === 0) { + return null; + } + + // Gemini CLI doesn't have explicit limits, so we show usage without percentage + // For free tier, there are rate limits but no monthly caps + // We'll show token counts with a reasonable display + + const usage: ProviderUsage = {}; + + // Session = today's usage + if (dailyRequests > 0) { + const dailyTotalTokens = dailyInputTokens + dailyOutputTokens; + usage.session = { + used: dailyTotalTokens, + limit: 1000000, // Arbitrary high limit for display + percentage: Math.min(100, Math.round((dailyTotalTokens / 1000000) * 100)), + displayString: `${dailyRequests} reqs · ${formatTokenCount(dailyInputTokens)} in · ${formatTokenCount(dailyOutputTokens)} out`, + }; + } + + // Weekly usage + if (weeklyRequests > 0) { + const weeklyTotalTokens = weeklyInputTokens + weeklyOutputTokens; + usage.weekly = { + used: weeklyTotalTokens, + limit: 10000000, // Arbitrary high limit + percentage: Math.min(100, Math.round((weeklyTotalTokens / 10000000) * 100)), + displayString: `${weeklyRequests} reqs · ${formatTokenCount(weeklyInputTokens)} in · ${formatTokenCount(weeklyOutputTokens)} out`, + }; + } + + // Monthly usage + if (monthlyRequests > 0) { + const monthlyTotalTokens = monthlyInputTokens + monthlyOutputTokens; + usage.monthly = { + used: monthlyTotalTokens, + limit: 50000000, // Arbitrary high limit + percentage: Math.min(100, Math.round((monthlyTotalTokens / 50000000) * 100)), + displayString: `${monthlyRequests} reqs · ${formatTokenCount(monthlyInputTokens)} in · ${formatTokenCount(monthlyOutputTokens)} out`, + }; + } + + // Log model breakdown for debugging + logger.info('Gemini usage by model:'); + for (const [model, stats] of modelUsage) { + logger.info(` ${model}: ${stats.requests} reqs, ${stats.inputTokens} in, ${stats.outputTokens} out`); + } + + return Object.keys(usage).length > 0 ? usage : null; + } + + async fetchStatus(): Promise { + return { operational: true }; + } +} + +/** + * Format token count for display (e.g., 1234 -> "1.2K", 1234567 -> "1.2M") + */ +function formatTokenCount(count: number): string { + if (count >= 1000000) { + return `${(count / 1000000).toFixed(1)}M`; + } + if (count >= 1000) { + return `${(count / 1000).toFixed(1)}K`; + } + return count.toString(); +} diff --git a/codexbar-electron/src/main/providers/kiro/KiroProvider.ts b/codexbar-electron/src/main/providers/kiro/KiroProvider.ts new file mode 100644 index 00000000..7ef1be38 --- /dev/null +++ b/codexbar-electron/src/main/providers/kiro/KiroProvider.ts @@ -0,0 +1,108 @@ +/** + * Kiro Provider + * + * Kiro is an AI coding assistant from Amazon (AWS). + * This provider checks for Kiro CLI or VS Code extension. + */ + +import { BaseProvider, ProviderUsage, ProviderStatus } from '../BaseProvider'; +import { runCommand } from '../../utils/subprocess'; +import { logger } from '../../utils/logger'; +import path from 'path'; +import fs from 'fs/promises'; +import os from 'os'; + +export class KiroProvider extends BaseProvider { + readonly id = 'kiro'; + readonly name = 'Kiro'; + readonly icon = '🎯'; + readonly websiteUrl = 'https://kiro.dev'; + readonly statusPageUrl = undefined; + + async isConfigured(): Promise { + // Check for kiro CLI + try { + const result = await runCommand('kiro', ['--version']); + if (result.exitCode === 0) return true; + } catch { + // CLI not found + } + + // Check for VS Code extension + const vscodeExtensions = path.join(os.homedir(), '.vscode', 'extensions'); + try { + const extensions = await fs.readdir(vscodeExtensions); + const hasKiro = extensions.some(ext => + ext.toLowerCase().includes('kiro') || ext.includes('amazon.kiro') + ); + if (hasKiro) return true; + } catch { + // Extensions dir not found + } + + // Check for config directories + const configPaths = [ + path.join(os.homedir(), '.kiro'), + path.join(os.homedir(), '.config', 'kiro'), + path.join(os.homedir(), 'AppData', 'Roaming', 'Kiro'), + ]; + + for (const configPath of configPaths) { + try { + await fs.access(configPath); + return true; + } catch { + // Try next + } + } + + return false; + } + + async fetchUsage(): Promise { + // Try to get version from CLI + try { + const result = await runCommand('kiro', ['--version']); + if (result.exitCode === 0) { + return { + session: { + used: 0, + limit: 0, + percentage: 0, + displayString: `CLI ${result.stdout.trim() || 'installed'}`, + }, + }; + } + } catch { + // CLI not available + } + + // Check for VS Code extension + const vscodeExtensions = path.join(os.homedir(), '.vscode', 'extensions'); + try { + const extensions = await fs.readdir(vscodeExtensions); + const kiroExt = extensions.find(ext => + ext.toLowerCase().includes('kiro') || ext.includes('amazon.kiro') + ); + if (kiroExt) { + return { + session: { + used: 0, + limit: 0, + percentage: 0, + displayString: 'VS Code Extension', + }, + }; + } + } catch { + // Extensions dir not found + } + + logger.debug('Kiro: Not configured'); + return null; + } + + async fetchStatus(): Promise { + return { operational: true }; + } +} diff --git a/codexbar-electron/src/main/providers/minimax/MiniMaxProvider.ts b/codexbar-electron/src/main/providers/minimax/MiniMaxProvider.ts new file mode 100644 index 00000000..b532845b --- /dev/null +++ b/codexbar-electron/src/main/providers/minimax/MiniMaxProvider.ts @@ -0,0 +1,105 @@ +/** + * MiniMax Provider + * + * MiniMax is an AI model provider. This provider checks for + * MiniMax API configuration or CLI tools. + */ + +import { BaseProvider, ProviderUsage, ProviderStatus, calculatePercentage, formatUsage } from '../BaseProvider'; +import { runCommand } from '../../utils/subprocess'; +import { logger } from '../../utils/logger'; +import path from 'path'; +import fs from 'fs/promises'; +import os from 'os'; + +export class MiniMaxProvider extends BaseProvider { + readonly id = 'minimax'; + readonly name = 'MiniMax'; + readonly icon = '🎨'; + readonly websiteUrl = 'https://minimax.io'; + readonly statusPageUrl = undefined; + + async isConfigured(): Promise { + // Check for MiniMax API key in environment + if (process.env.MINIMAX_API_KEY) { + return true; + } + + // Check for config files + const configPaths = [ + path.join(os.homedir(), '.minimax', 'config.json'), + path.join(os.homedir(), '.config', 'minimax', 'config.json'), + ]; + + for (const configPath of configPaths) { + try { + await fs.access(configPath); + return true; + } catch { + // Try next + } + } + + return false; + } + + async fetchUsage(): Promise { + // Try to read config file for usage info + const configPaths = [ + path.join(os.homedir(), '.minimax', 'config.json'), + path.join(os.homedir(), '.config', 'minimax', 'config.json'), + ]; + + for (const configPath of configPaths) { + try { + const content = await fs.readFile(configPath, 'utf-8'); + const config = JSON.parse(content); + + if (config.usage) { + const used = config.usage.tokens ?? config.usage.credits ?? 0; + const limit = config.usage.limit ?? 1000000; + + return { + session: { + used, + limit, + percentage: calculatePercentage(used, limit), + displayString: formatUsage(used, limit, 'tokens'), + }, + }; + } + + // Config exists but no usage data + return { + session: { + used: 0, + limit: 0, + percentage: 0, + displayString: 'Configured', + }, + }; + } catch { + // Try next path + } + } + + // Check for API key in environment + if (process.env.MINIMAX_API_KEY) { + return { + session: { + used: 0, + limit: 0, + percentage: 0, + displayString: 'API Key Set', + }, + }; + } + + logger.debug('MiniMax: Not configured'); + return null; + } + + async fetchStatus(): Promise { + return { operational: true }; + } +} diff --git a/codexbar-electron/src/main/providers/vertexai/VertexAIProvider.ts b/codexbar-electron/src/main/providers/vertexai/VertexAIProvider.ts new file mode 100644 index 00000000..b2cdd632 --- /dev/null +++ b/codexbar-electron/src/main/providers/vertexai/VertexAIProvider.ts @@ -0,0 +1,116 @@ +/** + * Vertex AI (Google Cloud) Provider + * + * Vertex AI is Google Cloud's AI platform. This provider checks for + * Google Cloud credentials and gcloud CLI configuration. + */ + +import { BaseProvider, ProviderUsage, ProviderStatus } from '../BaseProvider'; +import { runCommand } from '../../utils/subprocess'; +import { logger } from '../../utils/logger'; +import path from 'path'; +import fs from 'fs/promises'; +import os from 'os'; + +export class VertexAIProvider extends BaseProvider { + readonly id = 'vertexai'; + readonly name = 'Vertex AI'; + readonly icon = '☁️'; + readonly websiteUrl = 'https://cloud.google.com/vertex-ai'; + readonly statusPageUrl = 'https://status.cloud.google.com'; + + async isConfigured(): Promise { + // Check for Google Cloud credentials + const credPaths = [ + path.join(os.homedir(), '.config', 'gcloud', 'application_default_credentials.json'), + path.join(os.homedir(), 'AppData', 'Roaming', 'gcloud', 'application_default_credentials.json'), + ]; + + for (const credPath of credPaths) { + try { + await fs.access(credPath); + return true; + } catch { + // Try next + } + } + + // Check GOOGLE_APPLICATION_CREDENTIALS env var + if (process.env.GOOGLE_APPLICATION_CREDENTIALS) { + try { + await fs.access(process.env.GOOGLE_APPLICATION_CREDENTIALS); + return true; + } catch { + // File doesn't exist + } + } + + // Check for gcloud CLI + try { + const result = await runCommand('gcloud', ['--version']); + if (result.exitCode === 0) { + // Check if authenticated + const authResult = await runCommand('gcloud', ['auth', 'list', '--format=json']); + if (authResult.exitCode === 0) { + try { + const accounts = JSON.parse(authResult.stdout); + if (Array.isArray(accounts) && accounts.length > 0) { + return true; + } + } catch { + // Parse failed + } + } + } + } catch { + // gcloud not found + } + + return false; + } + + async fetchUsage(): Promise { + // Try to get current project and account from gcloud + try { + const projectResult = await runCommand('gcloud', ['config', 'get-value', 'project']); + const accountResult = await runCommand('gcloud', ['config', 'get-value', 'account']); + + if (projectResult.exitCode === 0 || accountResult.exitCode === 0) { + const project = projectResult.stdout.trim() || 'unknown'; + const account = accountResult.stdout.trim() || ''; + + let displayString = `Project: ${project}`; + if (account) { + // Truncate email for display + const shortAccount = account.split('@')[0]; + displayString = `${shortAccount} · ${project}`; + } + + return { + session: { + used: 0, + limit: 0, + percentage: 0, + displayString, + }, + }; + } + } catch (error) { + logger.debug('Vertex AI: gcloud command failed:', error); + } + + // If we have credentials but no gcloud CLI + return { + session: { + used: 0, + limit: 0, + percentage: 0, + displayString: 'Configured', + }, + }; + } + + async fetchStatus(): Promise { + return { operational: true }; + } +} diff --git a/codexbar-electron/src/main/providers/zai/ZaiProvider.ts b/codexbar-electron/src/main/providers/zai/ZaiProvider.ts new file mode 100644 index 00000000..1f115268 --- /dev/null +++ b/codexbar-electron/src/main/providers/zai/ZaiProvider.ts @@ -0,0 +1,93 @@ +/** + * z.ai Provider + * + * z.ai is an AI assistant. This provider checks for z.ai CLI or configuration. + */ + +import { BaseProvider, ProviderUsage, ProviderStatus, calculatePercentage, formatUsage } from '../BaseProvider'; +import { runCommand } from '../../utils/subprocess'; +import { logger } from '../../utils/logger'; +import path from 'path'; +import fs from 'fs/promises'; +import os from 'os'; + +export class ZaiProvider extends BaseProvider { + readonly id = 'zai'; + readonly name = 'z.ai'; + readonly icon = '⚡'; + readonly websiteUrl = 'https://z.ai'; + readonly statusPageUrl = undefined; + + private zaiDir = path.join(os.homedir(), '.zai'); + + async isConfigured(): Promise { + // Check for z.ai CLI + try { + const result = await runCommand('zai', ['--version']); + if (result.exitCode === 0) return true; + } catch { + // CLI not found + } + + // Check for config directory + try { + await fs.access(this.zaiDir); + return true; + } catch { + return false; + } + } + + async fetchUsage(): Promise { + try { + // Try to read config file + const configPath = path.join(this.zaiDir, 'config.json'); + + try { + const content = await fs.readFile(configPath, 'utf-8'); + const config = JSON.parse(content); + + if (config.usage) { + const used = config.usage.current ?? 0; + const limit = config.usage.limit ?? 1000; + + return { + session: { + used, + limit, + percentage: calculatePercentage(used, limit), + displayString: formatUsage(used, limit, 'credits'), + }, + }; + } + } catch { + // Config file not found or invalid + } + + // Try CLI version as fallback + try { + const result = await runCommand('zai', ['--version']); + if (result.exitCode === 0) { + return { + session: { + used: 0, + limit: 0, + percentage: 0, + displayString: `CLI ${result.stdout.trim() || 'installed'}`, + }, + }; + } + } catch { + // CLI not available + } + } catch (error) { + logger.debug('z.ai: Could not read config:', error); + } + + return null; + } + + async fetchStatus(): Promise { + return { operational: true }; + } +} diff --git a/codexbar-electron/src/main/store/SettingsStore.ts b/codexbar-electron/src/main/store/SettingsStore.ts new file mode 100644 index 00000000..89b4646b --- /dev/null +++ b/codexbar-electron/src/main/store/SettingsStore.ts @@ -0,0 +1,113 @@ +/** + * Settings Store + * + * Persists user settings using electron-store. + */ + +import Store from 'electron-store'; +import { logger } from '../utils/logger'; + +interface SettingsSchema { + enabledProviders: string[]; + refreshInterval: number; // seconds + showNotifications: boolean; + startAtLogin: boolean; + showInDock: boolean; + theme: 'system' | 'light' | 'dark'; +} + +const defaults: SettingsSchema = { + enabledProviders: ['codex', 'claude', 'cursor', 'gemini'], + refreshInterval: 300, // 5 minutes + showNotifications: true, + startAtLogin: false, + showInDock: false, + theme: 'system', +}; + +export class SettingsStore { + private store: Store; + + constructor() { + this.store = new Store({ + name: 'settings', + defaults, + }); + + logger.info('Settings loaded:', this.store.store); + } + + /** + * Get all settings + */ + getAll(): SettingsSchema { + return this.store.store; + } + + /** + * Get a specific setting + */ + get(key: K): SettingsSchema[K] { + return this.store.get(key); + } + + /** + * Set a specific setting + */ + set(key: K, value: SettingsSchema[K]): void { + this.store.set(key, value); + logger.debug(`Setting updated: ${key} = ${JSON.stringify(value)}`); + } + + /** + * Set a setting by string key (for IPC) + */ + setAny(key: string, value: unknown): void { + if (key in defaults) { + this.store.set(key as keyof SettingsSchema, value as any); + logger.debug(`Setting updated: ${key} = ${JSON.stringify(value)}`); + } + } + + /** + * Check if a provider is enabled + */ + isProviderEnabled(providerId: string): boolean { + return this.store.get('enabledProviders').includes(providerId); + } + + /** + * Enable or disable a provider + */ + setProviderEnabled(providerId: string, enabled: boolean): void { + const providers = this.store.get('enabledProviders'); + + if (enabled && !providers.includes(providerId)) { + this.store.set('enabledProviders', [...providers, providerId]); + } else if (!enabled && providers.includes(providerId)) { + this.store.set('enabledProviders', providers.filter(p => p !== providerId)); + } + } + + /** + * Get refresh interval in seconds + */ + getRefreshInterval(): number { + return this.store.get('refreshInterval'); + } + + /** + * Set refresh interval in seconds + */ + setRefreshInterval(seconds: number): void { + this.store.set('refreshInterval', Math.max(60, seconds)); // Minimum 1 minute + } + + /** + * Reset all settings to defaults + */ + reset(): void { + this.store.clear(); + logger.info('Settings reset to defaults'); + } +} diff --git a/codexbar-electron/src/main/store/UsageStore.ts b/codexbar-electron/src/main/store/UsageStore.ts new file mode 100644 index 00000000..2316b6a3 --- /dev/null +++ b/codexbar-electron/src/main/store/UsageStore.ts @@ -0,0 +1,107 @@ +/** + * Usage Store + * + * Stores and tracks usage data for all providers. + */ + +import Store from 'electron-store'; +import { ProviderUsage } from '../providers/BaseProvider'; +import { logger } from '../utils/logger'; + +interface UsageEntry { + usage: ProviderUsage; + lastUpdated: string; // ISO 8601 +} + +interface UsageSchema { + providers: Record; + history: Record>; +} + +const defaults: UsageSchema = { + providers: {}, + history: {}, +}; + +export class UsageStore { + private store: Store; + + constructor() { + this.store = new Store({ + name: 'usage', + defaults, + }); + } + + /** + * Get all usage data + */ + getAll(): Record { + return this.store.get('providers'); + } + + /** + * Get usage for a specific provider + */ + getProviderUsage(providerId: string): UsageEntry | null { + const providers = this.store.get('providers'); + return providers[providerId] ?? null; + } + + /** + * Set usage for a provider + */ + setProviderUsage(providerId: string, usage: ProviderUsage): void { + const providers = this.store.get('providers'); + const now = new Date().toISOString(); + + providers[providerId] = { + usage, + lastUpdated: now, + }; + + this.store.set('providers', providers); + + // Also add to history (keep last 100 entries per provider) + this.addToHistory(providerId, usage); + + logger.debug(`Usage updated for ${providerId}`); + } + + /** + * Add usage to history + */ + private addToHistory(providerId: string, usage: ProviderUsage): void { + const history = this.store.get('history'); + const providerHistory = history[providerId] ?? []; + + providerHistory.push({ + timestamp: new Date().toISOString(), + usage, + }); + + // Keep only last 100 entries + if (providerHistory.length > 100) { + providerHistory.shift(); + } + + history[providerId] = providerHistory; + this.store.set('history', history); + } + + /** + * Get usage history for a provider + */ + getHistory(providerId: string): Array<{ timestamp: string; usage: ProviderUsage }> { + const history = this.store.get('history'); + return history[providerId] ?? []; + } + + /** + * Clear all usage data + */ + clear(): void { + this.store.clear(); + logger.info('Usage data cleared'); + } +} diff --git a/codexbar-electron/src/main/tray/TrayMenu.ts b/codexbar-electron/src/main/tray/TrayMenu.ts new file mode 100644 index 00000000..bdfdfd85 --- /dev/null +++ b/codexbar-electron/src/main/tray/TrayMenu.ts @@ -0,0 +1,184 @@ +/** + * System Tray Menu Builder + * + * Creates the context menu shown when clicking the tray icon. + */ + +import { Menu, MenuItem, shell } from 'electron'; +import { ProviderManager } from '../providers/ProviderManager'; +import { SettingsStore } from '../store/SettingsStore'; +import { UsageStore } from '../store/UsageStore'; + +interface TrayMenuOptions { + providerManager: ProviderManager; + settingsStore: SettingsStore; + usageStore: UsageStore; + onSettingsClick: () => void; + onQuitClick: () => void; + onRefreshClick: () => void; +} + +export async function createTrayMenu(options: TrayMenuOptions): Promise { + const { providerManager, settingsStore, onSettingsClick, onQuitClick, onRefreshClick } = options; + + const menu = new Menu(); + + // Header + menu.append(new MenuItem({ + label: 'CodexBar', + enabled: false, + })); + + menu.append(new MenuItem({ type: 'separator' })); + + // Provider usage items + const providers = providerManager.getAllProviderStates(); + const enabledProviders = providers.filter(p => p.enabled); + + if (enabledProviders.length === 0) { + menu.append(new MenuItem({ + label: 'No providers enabled', + enabled: false, + })); + } else { + for (const provider of enabledProviders) { + const submenu = new Menu(); + + // Usage info + if (provider.result.usage) { + const { usage } = provider.result; + + if (usage.session) { + submenu.append(new MenuItem({ + label: `Session: ${usage.session.displayString} (${usage.session.percentage}%)`, + enabled: false, + })); + + if (usage.session.resetCountdown) { + submenu.append(new MenuItem({ + label: ` Resets in: ${usage.session.resetCountdown}`, + enabled: false, + })); + } + } + + if (usage.weekly) { + submenu.append(new MenuItem({ + label: `Weekly: ${usage.weekly.displayString} (${usage.weekly.percentage}%)`, + enabled: false, + })); + } + + if (usage.monthly) { + submenu.append(new MenuItem({ + label: `Monthly: ${usage.monthly.displayString} (${usage.monthly.percentage}%)`, + enabled: false, + })); + } + + if (usage.cost) { + submenu.append(new MenuItem({ + label: `Cost: ${usage.cost.displayString}`, + enabled: false, + })); + } + } else if (provider.result.state === 'loading') { + submenu.append(new MenuItem({ + label: 'Loading...', + enabled: false, + })); + } else if (provider.result.state === 'error') { + submenu.append(new MenuItem({ + label: `Error: ${provider.result.error}`, + enabled: false, + })); + } else { + submenu.append(new MenuItem({ + label: 'No data', + enabled: false, + })); + } + + submenu.append(new MenuItem({ type: 'separator' })); + + // Open website + submenu.append(new MenuItem({ + label: 'Open Website', + click: () => { + const p = providerManager.getProvider(provider.id); + if (p?.websiteUrl) { + shell.openExternal(p.websiteUrl); + } + }, + })); + + // Status indicator + let statusIcon = '⚪'; // idle + if (provider.result.state === 'success') statusIcon = '🟢'; + else if (provider.result.state === 'loading') statusIcon = '🟡'; + else if (provider.result.state === 'error') statusIcon = '🔴'; + + menu.append(new MenuItem({ + label: `${provider.icon} ${provider.name} ${statusIcon}`, + submenu, + })); + } + } + + menu.append(new MenuItem({ type: 'separator' })); + + // Actions + menu.append(new MenuItem({ + label: 'Refresh All', + accelerator: 'CmdOrCtrl+R', + click: onRefreshClick, + })); + + menu.append(new MenuItem({ type: 'separator' })); + + // Settings + menu.append(new MenuItem({ + label: 'Settings...', + accelerator: 'CmdOrCtrl+,', + click: onSettingsClick, + })); + + // Provider toggles submenu + const toggleSubmenu = new Menu(); + for (const provider of providers) { + toggleSubmenu.append(new MenuItem({ + label: `${provider.icon} ${provider.name}`, + type: 'checkbox', + checked: provider.enabled, + click: () => { + settingsStore.setProviderEnabled(provider.id, !provider.enabled); + if (!provider.enabled) { + providerManager.refreshProvider(provider.id); + } + }, + })); + } + + menu.append(new MenuItem({ + label: 'Providers', + submenu: toggleSubmenu, + })); + + menu.append(new MenuItem({ type: 'separator' })); + + // About & Quit + menu.append(new MenuItem({ + label: 'About CodexBar', + click: () => { + shell.openExternal('https://github.com/steipete/CodexBar'); + }, + })); + + menu.append(new MenuItem({ + label: 'Quit CodexBar', + accelerator: 'CmdOrCtrl+Q', + click: onQuitClick, + })); + + return menu; +} diff --git a/codexbar-electron/src/main/updater.ts b/codexbar-electron/src/main/updater.ts new file mode 100644 index 00000000..e8303b19 --- /dev/null +++ b/codexbar-electron/src/main/updater.ts @@ -0,0 +1,70 @@ +/** + * Auto-updater setup using electron-updater + */ + +import { autoUpdater } from 'electron-updater'; +import { logger } from './utils/logger'; + +export function setupAutoUpdater(): void { + // Configure auto-updater + autoUpdater.autoDownload = false; + autoUpdater.autoInstallOnAppQuit = true; + + // Event handlers + autoUpdater.on('checking-for-update', () => { + logger.info('Checking for updates...'); + }); + + autoUpdater.on('update-available', (info) => { + logger.info(`Update available: ${info.version}`); + // TODO: Show notification or prompt user + // For now, auto-download + autoUpdater.downloadUpdate(); + }); + + autoUpdater.on('update-not-available', () => { + logger.info('No updates available'); + }); + + autoUpdater.on('download-progress', (progress) => { + logger.debug(`Download progress: ${progress.percent.toFixed(1)}%`); + }); + + autoUpdater.on('update-downloaded', (info) => { + logger.info(`Update downloaded: ${info.version}`); + // TODO: Notify user that update is ready + // autoUpdater.quitAndInstall() to install immediately + }); + + autoUpdater.on('error', (error) => { + logger.error('Auto-updater error:', error); + }); + + // Check for updates on startup (after a delay) + setTimeout(() => { + autoUpdater.checkForUpdates().catch((err) => { + logger.warn('Failed to check for updates:', err); + }); + }, 10000); // 10 second delay + + // Check for updates every 4 hours + setInterval(() => { + autoUpdater.checkForUpdates().catch((err) => { + logger.warn('Failed to check for updates:', err); + }); + }, 4 * 60 * 60 * 1000); +} + +/** + * Manually check for updates + */ +export async function checkForUpdates(): Promise { + await autoUpdater.checkForUpdates(); +} + +/** + * Quit and install downloaded update + */ +export function installUpdate(): void { + autoUpdater.quitAndInstall(); +} diff --git a/codexbar-electron/src/main/utils/logger.ts b/codexbar-electron/src/main/utils/logger.ts new file mode 100644 index 00000000..1228ee03 --- /dev/null +++ b/codexbar-electron/src/main/utils/logger.ts @@ -0,0 +1,54 @@ +/** + * Logger utility using winston + */ + +import winston from 'winston'; +import path from 'path'; +import { app } from 'electron'; + +// Get user data path for log files +const getLogPath = (): string => { + try { + return path.join(app.getPath('userData'), 'logs'); + } catch { + // App not ready yet, use temp directory + return path.join(process.env.TEMP ?? '/tmp', 'codexbar', 'logs'); + } +}; + +export const logger = winston.createLogger({ + level: process.env.NODE_ENV === 'development' ? 'debug' : 'info', + format: winston.format.combine( + winston.format.timestamp(), + winston.format.errors({ stack: true }), + winston.format.printf(({ timestamp, level, message, stack }) => { + const msg = stack ?? message; + return `${timestamp} [${level.toUpperCase()}] ${msg}`; + }) + ), + transports: [ + // Console output + new winston.transports.Console({ + format: winston.format.combine( + winston.format.colorize(), + winston.format.printf(({ timestamp, level, message }) => { + return `${timestamp} [${level}] ${message}`; + }) + ), + }), + // File output (only when app is ready) + ...(process.type === 'browser' ? [ + new winston.transports.File({ + filename: path.join(getLogPath(), 'error.log'), + level: 'error', + maxsize: 5 * 1024 * 1024, // 5MB + maxFiles: 3, + }), + new winston.transports.File({ + filename: path.join(getLogPath(), 'combined.log'), + maxsize: 10 * 1024 * 1024, // 10MB + maxFiles: 5, + }), + ] : []), + ], +}); diff --git a/codexbar-electron/src/main/utils/subprocess.ts b/codexbar-electron/src/main/utils/subprocess.ts new file mode 100644 index 00000000..e4c27149 --- /dev/null +++ b/codexbar-electron/src/main/utils/subprocess.ts @@ -0,0 +1,91 @@ +/** + * Subprocess utilities for running CLI commands + */ + +import { spawn, SpawnOptions } from 'child_process'; +import { logger } from './logger'; + +export interface CommandResult { + stdout: string; + stderr: string; + exitCode: number; +} + +export interface CommandOptions { + timeout?: number; // milliseconds + cwd?: string; + env?: NodeJS.ProcessEnv; +} + +/** + * Run a command and capture output + */ +export async function runCommand( + command: string, + args: string[] = [], + options: CommandOptions = {} +): Promise { + const { timeout = 30000, cwd, env } = options; + + return new Promise((resolve, reject) => { + logger.debug(`Running command: ${command} ${args.join(' ')}`); + + const spawnOptions: SpawnOptions = { + cwd, + env: { ...process.env, ...env }, + shell: true, // Use shell on Windows for better compatibility + windowsHide: true, + }; + + const child = spawn(command, args, spawnOptions); + + let stdout = ''; + let stderr = ''; + let killed = false; + + // Set up timeout + const timer = setTimeout(() => { + killed = true; + child.kill('SIGTERM'); + reject(new Error(`Command timed out after ${timeout}ms`)); + }, timeout); + + child.stdout?.on('data', (data) => { + stdout += data.toString(); + }); + + child.stderr?.on('data', (data) => { + stderr += data.toString(); + }); + + child.on('error', (error) => { + clearTimeout(timer); + reject(error); + }); + + child.on('close', (code) => { + clearTimeout(timer); + if (!killed) { + resolve({ + stdout: stdout.trim(), + stderr: stderr.trim(), + exitCode: code ?? 0, + }); + } + }); + }); +} + +/** + * Check if a command exists in PATH + */ +export async function commandExists(command: string): Promise { + try { + // Use 'where' on Windows, 'which' on Unix + const checkCmd = process.platform === 'win32' ? 'where' : 'which'; + const result = await runCommand(checkCmd, [command], { timeout: 5000 }); + return result.exitCode === 0; + } catch { + return false; + } +} diff --git a/codexbar-electron/src/renderer/App.tsx b/codexbar-electron/src/renderer/App.tsx new file mode 100644 index 00000000..dacfd431 --- /dev/null +++ b/codexbar-electron/src/renderer/App.tsx @@ -0,0 +1,176 @@ +import React, { useEffect, useState } from 'react'; +import { ProviderList } from './components/ProviderList'; +import './styles.css'; + +type Tab = 'providers' | 'settings' | 'about'; + +interface Provider { + id: string; + name: string; + icon: string; + enabled: boolean; + result: { + state: 'idle' | 'loading' | 'success' | 'error'; + usage?: { + session?: { used: number; limit: number; percentage: number; displayString: string }; + weekly?: { used: number; limit: number; percentage: number; displayString: string }; + monthly?: { used: number; limit: number; percentage: number; displayString: string }; + }; + error?: string; + }; +} + +interface Settings { + refreshInterval?: number; + showNotifications?: boolean; + startAtLogin?: boolean; + theme?: string; +} + +export function App() { + const [tab, setTab] = useState('providers'); + const [providers, setProviders] = useState([]); + const [settings, setSettings] = useState({}); + const [refreshing, setRefreshing] = useState(false); + + useEffect(() => { + loadData(); + const unsub = window.codexbar?.onUpdate(() => loadData()); + return () => unsub?.(); + }, []); + + const loadData = async () => { + const [p, s] = await Promise.all([ + window.codexbar?.getProviders() ?? [], + window.codexbar?.getSettings() ?? {}, + ]); + setProviders(p); + setSettings(s); + }; + + const handleRefresh = async () => { + setRefreshing(true); + await window.codexbar?.refreshAll(); + await loadData(); + setTimeout(() => setRefreshing(false), 400); + }; + + const toggleProvider = async (id: string, enabled: boolean) => { + await window.codexbar?.toggleProvider(id, enabled); + await loadData(); + }; + + const updateSetting = async (key: string, value: any) => { + await window.codexbar?.setSetting(key, value); + await loadData(); + }; + + return ( +
+
+ +
+
+
+
C
+ CodexBar +
+
+
+ + + +
+
+ +
+ {tab === 'providers' && ( + + )} + + {tab === 'settings' && ( + <> +
+
Sync
+
+
+
Refresh Interval
+
How often to sync usage data
+
+ +
+
+ +
+
Notifications
+
+
+
Usage Alerts
+
Notify when usage exceeds 80%
+
+
+ +
+
System
+
+
+
Start at Login
+
Launch CodexBar on startup
+
+
+ +
+
Actions
+
+
+
Refresh All Data
+
Manually trigger a sync for all providers
+
+
+ {refreshing ? 'Syncing...' : 'Start'} +
+
+
+ + )} + + {tab === 'about' && ( +
+
+

CodexBar

+

Monitor your AI usage across providers

+
v0.1.0 · Windows/Linux
+ +
+ )} +
+
+ ); +} diff --git a/codexbar-electron/src/renderer/components/GeneralSettings.tsx b/codexbar-electron/src/renderer/components/GeneralSettings.tsx new file mode 100644 index 00000000..92628d57 --- /dev/null +++ b/codexbar-electron/src/renderer/components/GeneralSettings.tsx @@ -0,0 +1,96 @@ +import React from 'react'; + +interface Settings { + refreshInterval: number; + showNotifications: boolean; + startAtLogin: boolean; + theme: 'system' | 'light' | 'dark'; +} + +interface Props { + settings: Partial; + onChange: (key: string, value: any) => void; +} + +export function GeneralSettings({ settings, onChange }: Props) { + return ( +
+
+

Data

+ +
+
+
Refresh Interval
+
How often to sync usage data
+
+ +
+
+ +
+

Notifications

+ +
+
+
Usage Alerts
+
Notify when usage exceeds 80%
+
+ +
+
+ +
+

System

+ +
+
+
Launch at Startup
+
Start CodexBar when you log in
+
+ +
+ +
+
+
Appearance
+
Color theme preference
+
+ +
+
+
+ ); +} diff --git a/codexbar-electron/src/renderer/components/ProviderList.tsx b/codexbar-electron/src/renderer/components/ProviderList.tsx new file mode 100644 index 00000000..8c7a29d0 --- /dev/null +++ b/codexbar-electron/src/renderer/components/ProviderList.tsx @@ -0,0 +1,119 @@ +import React from 'react'; + +interface Provider { + id: string; + name: string; + icon: string; + enabled: boolean; + result: { + state: 'idle' | 'loading' | 'success' | 'error'; + usage?: { + session?: { used: number; limit: number; percentage: number; displayString: string }; + weekly?: { used: number; limit: number; percentage: number; displayString: string }; + monthly?: { used: number; limit: number; percentage: number; displayString: string }; + }; + error?: string; + }; +} + +interface Props { + providers: Provider[]; + onToggle: (id: string, enabled: boolean) => void; +} + +export function ProviderList({ providers, onToggle }: Props) { + if (providers.length === 0) { + return ( +
+ Loading providers... +
+ ); + } + + return ( +
+ {providers.map((provider) => ( + + ))} +
+ ); +} + +function ProviderCard({ provider, onToggle }: { provider: Provider; onToggle: Props['onToggle'] }) { + // Usage Ring Logic + const usage = provider.result.usage?.session || + provider.result.usage?.weekly || + provider.result.usage?.monthly; + + const percentage = usage ? Math.min(100, Math.max(0, usage.percentage)) : 0; + const radius = 13; // 32px box, ring needs to fit + const circumference = 2 * Math.PI * radius; + const strokeDashoffset = circumference - (percentage / 100) * circumference; + + const getStatusClass = () => { + if (!provider.enabled) return ''; + if (provider.result.state === 'loading') return 'loading'; + if (provider.result.state === 'error') return 'error'; + if (provider.result.state === 'success') return 'connected'; + return ''; // idle + }; + + const getStatusText = () => { + if (!provider.enabled) return 'Disabled'; + if (provider.result.state === 'loading') return 'Syncing...'; + if (provider.result.state === 'error') return provider.result.error || 'Error'; + if (provider.result.state === 'success' && usage) return usage.displayString; + if (provider.result.state === 'success') return 'Connected'; + return 'Idle'; + }; + + const getUsageColorClass = () => { + if (percentage >= 90) return 'critical'; + if (percentage >= 70) return 'warning'; + return ''; + }; + + return ( +
+
+
{provider.name}
+
+ {provider.enabled &&
} + {getStatusText()} +
+
+ + {provider.enabled && usage && usage.limit > 0 && ( +
+
+ + + + +
{percentage}%
+
+
+ )} + +