diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 59c229b04..8d5791ba3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -102,170 +102,11 @@ jobs: cp "dashboard/AstrBot-${VERSION_TAG}-dashboard.zip" "dashboard/astrbot-webui-${VERSION_TAG}.zip" rclone copy "dashboard/astrbot-webui-${VERSION_TAG}.zip" "r2:${R2_BUCKET_NAME}" --progress - build-desktop: - name: Build ${{ matrix.name }} - runs-on: ${{ matrix.runner }} - strategy: - fail-fast: false - matrix: - include: - - name: linux-x64 - runner: ubuntu-24.04 - os: linux - arch: amd64 - - name: linux-arm64 - runner: ubuntu-24.04-arm - os: linux - arch: arm64 - - name: windows-x64 - runner: windows-2022 - os: win - arch: amd64 - - name: windows-arm64 - runner: windows-11-arm - os: win - arch: arm64 - - name: macos-x64 - runner: macos-15-intel - os: mac - arch: amd64 - - name: macos-arm64 - runner: macos-15 - os: mac - arch: arm64 - env: - CSC_IDENTITY_AUTO_DISCOVERY: "false" - steps: - - name: Checkout repository - uses: actions/checkout@v6 - with: - fetch-depth: 0 - ref: ${{ inputs.ref || github.ref }} - - - name: Resolve tag - id: tag - shell: bash - run: | - if [ "${{ github.event_name }}" = "push" ]; then - tag="${GITHUB_REF_NAME}" - elif [ -n "${{ inputs.tag }}" ]; then - tag="${{ inputs.tag }}" - else - tag="$(git describe --tags --abbrev=0)" - fi - if [ -z "$tag" ]; then - echo "Failed to resolve tag." >&2 - exit 1 - fi - echo "tag=$tag" >> "$GITHUB_OUTPUT" - - - name: Setup uv - uses: astral-sh/setup-uv@v7 - - - name: Setup Python - uses: actions/setup-python@v6 - with: - python-version: "3.12" - - - name: Setup pnpm - uses: pnpm/action-setup@v4 - with: - version: 10.28.2 - - - name: Setup Node.js - uses: actions/setup-node@v6 - with: - node-version: '24.13.0' - cache: "pnpm" - cache-dependency-path: | - dashboard/pnpm-lock.yaml - desktop/pnpm-lock.yaml - - - name: Prepare OpenSSL for Windows ARM64 - if: ${{ matrix.os == 'win' && matrix.arch == 'arm64' }} - shell: pwsh - run: | - git clone https://github.com/microsoft/vcpkg.git C:\vcpkg - & C:\vcpkg\bootstrap-vcpkg.bat -disableMetrics - & C:\vcpkg\vcpkg.exe install openssl:arm64-windows - - "VCPKG_ROOT=C:\vcpkg" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - "VCPKGRS_TRIPLET=arm64-windows" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - "OPENSSL_DIR=C:\vcpkg\installed\arm64-windows" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - "OPENSSL_ROOT_DIR=C:\vcpkg\installed\arm64-windows" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - "OPENSSL_LIB_DIR=C:\vcpkg\installed\arm64-windows\lib" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - "OPENSSL_INCLUDE_DIR=C:\vcpkg\installed\arm64-windows\include" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - - name: Install dependencies - shell: bash - run: | - uv sync - pnpm --dir dashboard install --frozen-lockfile - pnpm --dir desktop install --frozen-lockfile - - - name: Build desktop package - shell: bash - run: | - pnpm --dir dashboard run build - pnpm --dir desktop run build:webui - pnpm --dir desktop run build:backend - pnpm --dir desktop run sync:version - pnpm --dir desktop exec electron-builder --publish never - - - name: Normalize artifact names - shell: bash - env: - NAME_PREFIX: AstrBot-${{ steps.tag.outputs.tag }}-${{ matrix.arch }}-${{ matrix.os }} - run: | - shopt -s nullglob - out_dir="desktop/dist/release" - mkdir -p "$out_dir" - files=( - desktop/dist/*.AppImage - desktop/dist/*.dmg - desktop/dist/*.zip - desktop/dist/*.exe - ) - if [ ${#files[@]} -eq 0 ]; then - echo "No desktop artifacts found to rename." >&2 - exit 1 - fi - for src in "${files[@]}"; do - file="$(basename "$src")" - case "$file" in - *.AppImage) - dest="$out_dir/${NAME_PREFIX}.AppImage" - ;; - *.dmg) - dest="$out_dir/${NAME_PREFIX}.dmg" - ;; - *.exe) - dest="$out_dir/${NAME_PREFIX}.exe" - ;; - *.zip) - dest="$out_dir/${NAME_PREFIX}.zip" - ;; - *) - continue - ;; - esac - cp "$src" "$dest" - done - ls -la "$out_dir" - - - name: Upload desktop artifacts - uses: actions/upload-artifact@v6 - with: - name: AstrBot-${{ steps.tag.outputs.tag }}-${{ matrix.arch }}-${{ matrix.os }} - if-no-files-found: error - path: desktop/dist/release/* - publish-release: name: Publish GitHub Release runs-on: ubuntu-24.04 needs: - build-dashboard - - build-desktop steps: - name: Checkout repository uses: actions/checkout@v6 @@ -296,12 +137,6 @@ jobs: name: Dashboard-${{ steps.tag.outputs.tag }} path: release-assets - - name: Download desktop artifacts - uses: actions/download-artifact@v7 - with: - pattern: AstrBot-${{ steps.tag.outputs.tag }}-* - path: release-assets - merge-multiple: true - name: Resolve release notes id: notes diff --git a/.gitignore b/.gitignore index e060b85a6..e3ffbd473 100644 --- a/.gitignore +++ b/.gitignore @@ -33,13 +33,6 @@ tests/astrbot_plugin_openai dashboard/node_modules/ dashboard/dist/ .pnpm-store/ -desktop/node_modules/ -desktop/dist/ -desktop/out/ -desktop/resources/backend/astrbot-backend* -desktop/resources/backend/*.exe -desktop/resources/webui/* -desktop/resources/.pyinstaller/ package-lock.json yarn.lock diff --git a/README.md b/README.md index 7fbf982fd..4a0bb5338 100644 --- a/README.md +++ b/README.md @@ -146,9 +146,9 @@ yay -S astrbot-git paru -S astrbot-git ``` -#### 桌面端 Electron 打包 +#### 桌面端(Tauri) -桌面端(Electron 打包,`pnpm` 工作流)构建流程请参阅:[`desktop/README.md`](desktop/README.md)。 +桌面端已迁移为独立仓库(Tauri):[https://github.com/AstrBotDevs/AstrBot-desktop](https://github.com/AstrBotDevs/AstrBot-desktop)。 ## 支持的消息平台 diff --git a/README_en.md b/README_en.md index d6950c33b..b20e806c0 100644 --- a/README_en.md +++ b/README_en.md @@ -154,9 +154,9 @@ yay -S astrbot-git paru -S astrbot-git ``` -#### Desktop Electron Build +#### Desktop (Tauri) -For desktop build steps (Electron packaging, `pnpm` workflow), see [`desktop/README.md`](desktop/README.md). +Desktop packaging has moved to a standalone Tauri repository: [https://github.com/AstrBotDevs/AstrBot-desktop](https://github.com/AstrBotDevs/AstrBot-desktop). ## Supported Messaging Platforms diff --git a/astrbot/core/knowledge_base/kb_db_sqlite.py b/astrbot/core/knowledge_base/kb_db_sqlite.py index ba25ed7e5..39fc72ac8 100644 --- a/astrbot/core/knowledge_base/kb_db_sqlite.py +++ b/astrbot/core/knowledge_base/kb_db_sqlite.py @@ -13,16 +13,19 @@ from astrbot.core.knowledge_base.models import ( KBMedia, KnowledgeBase, ) +from astrbot.core.utils.astrbot_path import get_astrbot_knowledge_base_path class KBSQLiteDatabase: - def __init__(self, db_path: str = "data/knowledge_base/kb.db") -> None: + def __init__(self, db_path: str | None = None) -> None: """初始化知识库数据库 Args: - db_path: 数据库文件路径, 默认为 data/knowledge_base/kb.db + db_path: 数据库文件路径, 默认位于 AstrBot 数据目录下的 knowledge_base/kb.db """ + if db_path is None: + db_path = str(Path(get_astrbot_knowledge_base_path()) / "kb.db") self.db_path = db_path self.DATABASE_URL = f"sqlite+aiosqlite:///{db_path}" self.inited = False diff --git a/astrbot/core/knowledge_base/kb_mgr.py b/astrbot/core/knowledge_base/kb_mgr.py index ae5a1b9e7..f26409e56 100644 --- a/astrbot/core/knowledge_base/kb_mgr.py +++ b/astrbot/core/knowledge_base/kb_mgr.py @@ -3,6 +3,7 @@ from pathlib import Path from astrbot.core import logger from astrbot.core.provider.manager import ProviderManager +from astrbot.core.utils.astrbot_path import get_astrbot_knowledge_base_path # from .chunking.fixed_size import FixedSizeChunker from .chunking.recursive import RecursiveCharacterChunker @@ -13,7 +14,7 @@ from .retrieval.manager import RetrievalManager, RetrievalResult from .retrieval.rank_fusion import RankFusion from .retrieval.sparse_retriever import SparseRetriever -FILES_PATH = "data/knowledge_base" +FILES_PATH = get_astrbot_knowledge_base_path() DB_PATH = Path(FILES_PATH) / "kb.db" """Knowledge Base storage root directory""" CHUNKER = RecursiveCharacterChunker() @@ -27,7 +28,7 @@ class KnowledgeBaseManager: self, provider_manager: ProviderManager, ) -> None: - Path(DB_PATH).parent.mkdir(parents=True, exist_ok=True) + DB_PATH.parent.mkdir(parents=True, exist_ok=True) self.provider_manager = provider_manager self._session_deleted_callback_registered = False diff --git a/astrbot/core/provider/sources/sensevoice_selfhosted_source.py b/astrbot/core/provider/sources/sensevoice_selfhosted_source.py index 965b83a5a..af6c0f631 100644 --- a/astrbot/core/provider/sources/sensevoice_selfhosted_source.py +++ b/astrbot/core/provider/sources/sensevoice_selfhosted_source.py @@ -7,12 +7,14 @@ import asyncio import os import re from datetime import datetime +from pathlib import Path from typing import cast from funasr_onnx import SenseVoiceSmall from funasr_onnx.utils.postprocess_utils import rich_transcription_postprocess from astrbot.core import logger +from astrbot.core.utils.astrbot_path import get_astrbot_temp_path from astrbot.core.utils.io import download_file from astrbot.core.utils.tencent_record_helper import tencent_silk_to_wav @@ -50,7 +52,9 @@ class ProviderSenseVoiceSTTSelfHost(STTProvider): async def get_timestamped_path(self) -> str: timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") - return os.path.join("data", "temp", f"{timestamp}") + temp_dir = Path(get_astrbot_temp_path()) + temp_dir.mkdir(parents=True, exist_ok=True) + return str(temp_dir / timestamp) async def _is_silk_file(self, file_path) -> bool: silk_header = b"SILK" diff --git a/astrbot/core/utils/astrbot_path.py b/astrbot/core/utils/astrbot_path.py index 063c8ddfc..987ce110a 100644 --- a/astrbot/core/utils/astrbot_path.py +++ b/astrbot/core/utils/astrbot_path.py @@ -15,7 +15,7 @@ Skills 目录路径:固定为数据目录下的 skills 目录 import os -from astrbot.core.utils.runtime_env import is_packaged_electron_runtime +from astrbot.core.utils.runtime_env import is_packaged_desktop_runtime def get_astrbot_path() -> str: @@ -29,7 +29,7 @@ def get_astrbot_root() -> str: """获取Astrbot根目录路径""" if path := os.environ.get("ASTRBOT_ROOT"): return os.path.realpath(path) - if is_packaged_electron_runtime(): + if is_packaged_desktop_runtime(): return os.path.realpath(os.path.join(os.path.expanduser("~"), ".astrbot")) return os.path.realpath(os.getcwd()) diff --git a/astrbot/core/utils/pip_installer.py b/astrbot/core/utils/pip_installer.py index 1c8da23c1..562a0ed30 100644 --- a/astrbot/core/utils/pip_installer.py +++ b/astrbot/core/utils/pip_installer.py @@ -12,7 +12,7 @@ import threading from collections import deque from astrbot.core.utils.astrbot_path import get_astrbot_site_packages_path -from astrbot.core.utils.runtime_env import is_packaged_electron_runtime +from astrbot.core.utils.runtime_env import is_packaged_desktop_runtime logger = logging.getLogger("astrbot") @@ -35,7 +35,7 @@ def _get_pip_main(): "pip module is unavailable " f"(sys.executable={sys.executable}, " f"frozen={getattr(sys, 'frozen', False)}, " - f"ASTRBOT_ELECTRON_CLIENT={os.environ.get('ASTRBOT_ELECTRON_CLIENT')})" + f"ASTRBOT_DESKTOP_CLIENT={os.environ.get('ASTRBOT_DESKTOP_CLIENT')})" ) from exc return pip_main @@ -556,7 +556,7 @@ class PipInstaller: args.extend(["--trusted-host", "mirrors.aliyun.com", "-i", index_url]) target_site_packages = None - if is_packaged_electron_runtime(): + if is_packaged_desktop_runtime(): target_site_packages = get_astrbot_site_packages_path() os.makedirs(target_site_packages, exist_ok=True) _prepend_sys_path(target_site_packages) @@ -582,7 +582,7 @@ class PipInstaller: def prefer_installed_dependencies(self, requirements_path: str) -> None: """优先使用已安装在插件 site-packages 中的依赖,不执行安装。""" - if not is_packaged_electron_runtime(): + if not is_packaged_desktop_runtime(): return target_site_packages = get_astrbot_site_packages_path() diff --git a/astrbot/core/utils/runtime_env.py b/astrbot/core/utils/runtime_env.py index 2eb1bc7e4..483f5bc0c 100644 --- a/astrbot/core/utils/runtime_env.py +++ b/astrbot/core/utils/runtime_env.py @@ -6,5 +6,5 @@ def is_frozen_runtime() -> bool: return bool(getattr(sys, "frozen", False)) -def is_packaged_electron_runtime() -> bool: - return is_frozen_runtime() and os.environ.get("ASTRBOT_ELECTRON_CLIENT") == "1" +def is_packaged_desktop_runtime() -> bool: + return is_frozen_runtime() and os.environ.get("ASTRBOT_DESKTOP_CLIENT") == "1" diff --git a/astrbot/dashboard/routes/plugin.py b/astrbot/dashboard/routes/plugin.py index bfa4dca39..25fed7d27 100644 --- a/astrbot/dashboard/routes/plugin.py +++ b/astrbot/dashboard/routes/plugin.py @@ -20,7 +20,10 @@ from astrbot.core.star.filter.permission import PermissionTypeFilter from astrbot.core.star.filter.regex import RegexFilter from astrbot.core.star.star_handler import EventType, star_handlers_registry from astrbot.core.star.star_manager import PluginManager -from astrbot.core.utils.astrbot_path import get_astrbot_temp_path +from astrbot.core.utils.astrbot_path import ( + get_astrbot_data_path, + get_astrbot_temp_path, +) from .route import Response, Route, RouteContext @@ -196,10 +199,11 @@ class PluginRoute(Route): def _build_registry_source(self, custom_url: str | None) -> RegistrySource: """构建注册表源信息""" + data_dir = get_astrbot_data_path() if custom_url: # 对自定义URL生成一个安全的文件名 url_hash = hashlib.md5(custom_url.encode()).hexdigest()[:8] - cache_file = f"data/plugins_custom_{url_hash}.json" + cache_file = os.path.join(data_dir, f"plugins_custom_{url_hash}.json") # 更安全的后缀处理方式 if custom_url.endswith(".json"): @@ -209,7 +213,7 @@ class PluginRoute(Route): urls = [custom_url] else: - cache_file = "data/plugins.json" + cache_file = os.path.join(data_dir, "plugins.json") md5_url = "https://api.soulter.top/astrbot/plugins-md5" urls = [ "https://api.soulter.top/astrbot/plugins", diff --git a/astrbot/dashboard/utils.py b/astrbot/dashboard/utils.py index b81faad06..3a0ee5bdc 100644 --- a/astrbot/dashboard/utils.py +++ b/astrbot/dashboard/utils.py @@ -1,5 +1,4 @@ import base64 -import os import traceback from io import BytesIO @@ -51,14 +50,14 @@ async def generate_tsne_visualization( return None kb = kb_helper.kb - index_path = f"data/knowledge_base/{kb.kb_id}/index.faiss" + index_path = kb_helper.kb_dir / "index.faiss" # 读取 FAISS 索引 - if not os.path.exists(index_path): - logger.warning(f"FAISS 索引不存在: {index_path}") + if not index_path.exists(): + logger.warning(f"FAISS 索引不存在: {index_path!s}") return None - index = faiss.read_index(index_path) + index = faiss.read_index(str(index_path)) if index.ntotal == 0: logger.warning("索引为空") diff --git a/dashboard/src/layouts/full/vertical-header/VerticalHeader.vue b/dashboard/src/layouts/full/vertical-header/VerticalHeader.vue index 48cefd3cb..1bcd7f167 100644 --- a/dashboard/src/layouts/full/vertical-header/VerticalHeader.vue +++ b/dashboard/src/layouts/full/vertical-header/VerticalHeader.vue @@ -51,7 +51,8 @@ const isElectronApp = ref( const redirectConfirmDialog = ref(false); const pendingRedirectUrl = ref(''); const resolvingReleaseTarget = ref(false); -const fallbackReleaseUrl = 'https://github.com/AstrBotDevs/AstrBot/releases/latest'; +const desktopReleaseBaseUrl = 'https://github.com/AstrBotDevs/AstrBot-desktop/releases'; +const fallbackReleaseUrl = desktopReleaseBaseUrl; const getSelectedGitHubProxy = () => { if (typeof window === "undefined" || !window.localStorage) return ""; @@ -128,12 +129,15 @@ function confirmExternalRedirect() { const getReleaseUrlForElectron = () => { const firstRelease = (releases.value as any[])?.[0]; - if (firstRelease?.html_url) return firstRelease.html_url as string; + if (firstRelease?.tag_name) { + const tag = firstRelease.tag_name as string; + return `${desktopReleaseBaseUrl}/tag/${tag}`; + } if (hasNewVersion.value) return fallbackReleaseUrl; const tag = botCurrVersion.value?.startsWith('v') ? botCurrVersion.value : 'latest'; return tag === 'latest' ? fallbackReleaseUrl - : `https://github.com/AstrBotDevs/AstrBot/releases/tag/${tag}`; + : `${desktopReleaseBaseUrl}/tag/${tag}`; }; function handleUpdateClick() { diff --git a/desktop/README.md b/desktop/README.md deleted file mode 100644 index 48dcb341a..000000000 --- a/desktop/README.md +++ /dev/null @@ -1,131 +0,0 @@ -# AstrBot Desktop (Electron) - -This document describes how to build the Electron desktop app from source. - -## What This Package Contains - -- Electron desktop shell (`desktop/main.js`) -- Bundled WebUI static files (`desktop/resources/webui`) -- App assets (`desktop/assets`) - -Current behavior: - -- Backend executable is bundled in the installer/package. -- App startup checks backend availability and auto-starts bundled backend when needed. -- Runtime data is stored under `~/.astrbot` by default, not as a full AstrBot source project. - -## Prerequisites - -- Python environment ready in repository root (`uv` available) -- Node.js available -- `pnpm` available - -Desktop dependency management uses `pnpm` with a lockfile: - -- `desktop/pnpm-lock.yaml` -- `pnpm --dir desktop install --frozen-lockfile` - -## Build From Scratch - -Run commands from repository root: - -```bash -uv sync -pnpm --dir dashboard install -pnpm --dir dashboard build -pnpm --dir desktop install --frozen-lockfile -pnpm --dir desktop run dist:full -``` - -Output files are generated under: - -- `desktop/dist/` - -## Local Run (Development) - -Start backend first: - -```bash -uv run main.py -``` - -Start Electron shell: - -```bash -pnpm --dir desktop run dev -``` - -## Notes - -- `dist:full` runs WebUI build + backend build + Electron packaging. -- In packaged app mode, backend data root defaults to `~/.astrbot` (can be overridden by `ASTRBOT_ROOT`). -- Backend build uses `uv run --with pyinstaller ...`, so no manual `PyInstaller` install is required. - -## Runtime Directory Layout - -By default (`ASTRBOT_ROOT` not set), packaged desktop app uses this layout: - -```text -~/.astrbot/ - data/ - config/ # Main configuration - plugins/ # Installed plugins - plugin_data/ # Plugin persistent data - site-packages/ # Plugin dependency installation target in packaged mode - temp/ # Runtime temp files - skills/ # Skill-related runtime data - knowledge_base/ # Knowledge base files - backups/ # Backup data -``` - -The app does not store a full AstrBot source tree in home directory. - -## Troubleshooting - -Startup behavior: - -- Packaged app shows a local startup page first, then switches to dashboard after backend is reachable. -- If startup page never switches, check logs and timeout settings below. - -Runtime logs: - -- Electron shell log: `~/.astrbot/logs/electron.log` -- Backend stdout/stderr log: `~/.astrbot/logs/backend.log` -- Both files rotate by size by default: `20MB` per file, keep `3` backups. -- Electron log rotation envs: - - `ASTRBOT_ELECTRON_LOG_MAX_MB` - - `ASTRBOT_ELECTRON_LOG_BACKUP_COUNT` -- Backend log rotation envs: - - `ASTRBOT_BACKEND_LOG_MAX_MB` - - `ASTRBOT_BACKEND_LOG_BACKUP_COUNT` -- Rotation debug logging: - - `ASTRBOT_LOG_ROTATION_DEBUG=1` (or `NODE_ENV=development`) to print filesystem errors from rotation operations. -- On backend startup failure, the app dialog also shows the backend reason and backend log path. - -Timeout and loading controls: - -- `ASTRBOT_BACKEND_TIMEOUT_MS` controls how long Electron waits for backend reachability. -- In packaged mode, default is `0` (auto mode with a 5-minute safety cap). -- In development mode, default is `20000`. -- If backend startup times out, app shows startup failure dialog and exits. -- `ASTRBOT_DASHBOARD_TIMEOUT_MS` controls dashboard page load wait time after backend is ready (default `20000`). -- If you see `Unable to load the AstrBot dashboard.`, increase `ASTRBOT_DASHBOARD_TIMEOUT_MS`. - -Startup page locale: - -- Startup page language follows cached dashboard locale in `~/.astrbot/data/desktop_state.json`. -- Supported startup locales are `zh-CN` and `en-US`. -- Remove that file to reset locale fallback behavior. - -Backend auto-start: - -- `ASTRBOT_BACKEND_AUTO_START=0` disables Electron-managed backend startup. -- When disabled, backend must already be running at `ASTRBOT_BACKEND_URL` before launching app. - -If Electron download times out on restricted networks, configure mirrors before install: - -```bash -export ELECTRON_MIRROR="https://npmmirror.com/mirrors/electron/" -export ELECTRON_BUILDER_BINARIES_MIRROR="https://npmmirror.com/mirrors/electron-builder-binaries/" -pnpm --dir desktop install --frozen-lockfile -``` diff --git a/desktop/assets/icon-no-shadow.svg b/desktop/assets/icon-no-shadow.svg deleted file mode 100644 index 4268e03e2..000000000 --- a/desktop/assets/icon-no-shadow.svg +++ /dev/null @@ -1 +0,0 @@ -
\ No newline at end of file diff --git a/desktop/assets/icon.png b/desktop/assets/icon.png deleted file mode 100644 index 512d1eaed..000000000 Binary files a/desktop/assets/icon.png and /dev/null differ diff --git a/desktop/assets/tray.png b/desktop/assets/tray.png deleted file mode 100644 index 4fcc92ba6..000000000 Binary files a/desktop/assets/tray.png and /dev/null differ diff --git a/desktop/lib/backend-manager.js b/desktop/lib/backend-manager.js deleted file mode 100644 index eb8958a4c..000000000 --- a/desktop/lib/backend-manager.js +++ /dev/null @@ -1,821 +0,0 @@ -'use strict'; - -const fs = require('fs'); -const os = require('os'); -const path = require('path'); -const { spawn, spawnSync } = require('child_process'); -const { BufferedRotatingLogger } = require('./buffered-rotating-logger'); -const { - delay, - ensureDir, - formatLogTimestamp, - normalizeUrl, - parseLogBackupCount, - parseLogMaxBytes, - waitForProcessExit, -} = require('./common'); - -const PACKAGED_BACKEND_TIMEOUT_FALLBACK_MS = 5 * 60 * 1000; -const GRACEFUL_RESTART_WAIT_FALLBACK_MS = 20 * 1000; -const BACKEND_LOG_FLUSH_INTERVAL_MS = 120; -const BACKEND_LOG_MAX_BUFFER_BYTES = 128 * 1024; - -function parseBackendTimeoutMs(app) { - const defaultTimeoutMs = app.isPackaged ? 0 : 20000; - const parsed = Number.parseInt( - process.env.ASTRBOT_BACKEND_TIMEOUT_MS || `${defaultTimeoutMs}`, - 10, - ); - if (Number.isFinite(parsed) && parsed >= 0) { - return parsed; - } - return defaultTimeoutMs; -} - -class BackendManager { - constructor({ app, baseDir, log, shouldSkipStart }) { - this.app = app; - this.baseDir = baseDir; - this.log = typeof log === 'function' ? log : () => {}; - this.shouldSkipStart = - typeof shouldSkipStart === 'function' ? shouldSkipStart : () => false; - - this.backendUrl = normalizeUrl( - process.env.ASTRBOT_BACKEND_URL || 'http://127.0.0.1:6185/', - ); - this.backendAutoStart = process.env.ASTRBOT_BACKEND_AUTO_START !== '0'; - this.backendTimeoutMs = parseBackendTimeoutMs(app); - this.backendLogMaxBytes = parseLogMaxBytes( - process.env.ASTRBOT_BACKEND_LOG_MAX_MB, - ); - this.backendLogBackupCount = parseLogBackupCount( - process.env.ASTRBOT_BACKEND_LOG_BACKUP_COUNT, - ); - - this.backendProcess = null; - this.backendConfig = null; - this.backendLogger = new BufferedRotatingLogger({ - logPath: null, - maxBytes: this.backendLogMaxBytes, - backupCount: this.backendLogBackupCount, - flushIntervalMs: BACKEND_LOG_FLUSH_INTERVAL_MS, - maxBufferBytes: BACKEND_LOG_MAX_BUFFER_BYTES, - }); - this.backendLastExitReason = null; - this.backendStartupFailureReason = null; - this.backendSpawning = false; - this.backendRestarting = false; - } - - getBackendUrl() { - return this.backendUrl; - } - - getBackendTimeoutMs() { - return this.backendTimeoutMs; - } - - getRootDir() { - return ( - process.env.ASTRBOT_ROOT || - this.backendConfig?.rootDir || - this.resolveBackendRoot() - ); - } - - getBackendLogPath() { - const rootDir = this.getRootDir(); - if (!rootDir) { - return null; - } - return path.join(rootDir, 'logs', 'backend.log'); - } - - getStartupFailureReason() { - return this.backendStartupFailureReason; - } - - isSpawning() { - return this.backendSpawning; - } - - isRestarting() { - return this.backendRestarting; - } - - resolveBackendRoot() { - if (!this.app.isPackaged) { - return null; - } - return path.join(os.homedir(), '.astrbot'); - } - - resolveBackendCwd() { - if (!this.app.isPackaged) { - return path.resolve(this.baseDir, '..'); - } - return this.resolveBackendRoot(); - } - - resolveWebuiDir() { - if (process.env.ASTRBOT_WEBUI_DIR) { - return process.env.ASTRBOT_WEBUI_DIR; - } - if (!this.app.isPackaged) { - return null; - } - const candidate = path.join(process.resourcesPath, 'webui'); - const indexPath = path.join(candidate, 'index.html'); - return fs.existsSync(indexPath) ? candidate : null; - } - - getPackagedBackendPath() { - if (!this.app.isPackaged) { - return null; - } - const filename = - process.platform === 'win32' ? 'astrbot-backend.exe' : 'astrbot-backend'; - const candidate = path.join(process.resourcesPath, 'backend', filename); - return fs.existsSync(candidate) ? candidate : null; - } - - buildDefaultBackendLaunch(webuiDir) { - if (this.app.isPackaged) { - const packagedBackend = this.getPackagedBackendPath(); - if (!packagedBackend) { - return null; - } - const args = []; - if (webuiDir) { - args.push('--webui-dir', webuiDir); - } - return { - cmd: packagedBackend, - args, - shell: false, - }; - } - - const args = ['run', 'main.py']; - if (webuiDir) { - args.push('--webui-dir', webuiDir); - } - return { - cmd: 'uv', - args, - shell: process.platform === 'win32', - }; - } - - resolveBackendConfig() { - const webuiDir = this.resolveWebuiDir(); - const customCmd = process.env.ASTRBOT_BACKEND_CMD; - const launch = customCmd - ? { - cmd: customCmd, - args: [], - shell: true, - } - : this.buildDefaultBackendLaunch(webuiDir); - const cwd = process.env.ASTRBOT_BACKEND_CWD || this.resolveBackendCwd(); - const rootDir = process.env.ASTRBOT_ROOT || this.resolveBackendRoot(); - ensureDir(cwd); - if (rootDir) { - ensureDir(rootDir); - } - this.backendConfig = { - cmd: launch ? launch.cmd : null, - args: launch ? launch.args : [], - shell: launch ? launch.shell : true, - cwd, - webuiDir, - rootDir, - }; - return this.backendConfig; - } - - getBackendConfig() { - if (!this.backendConfig) { - return this.resolveBackendConfig(); - } - return this.backendConfig; - } - - getBackendPort() { - try { - const parsed = new URL(this.backendUrl); - if (parsed.port) { - const port = Number.parseInt(parsed.port, 10); - return Number.isFinite(port) ? port : null; - } - return parsed.protocol === 'https:' ? 443 : 80; - } catch { - return null; - } - } - - canManageBackend() { - return Boolean(this.getBackendConfig().cmd); - } - - async flushLogs() { - await this.backendLogger.flush(); - } - - async pingBackend(timeoutMs = 800) { - const controller = new AbortController(); - const timeout = setTimeout(() => controller.abort(), timeoutMs); - try { - await fetch(this.backendUrl, { - signal: controller.signal, - redirect: 'manual', - }); - return true; - } catch { - return false; - } finally { - clearTimeout(timeout); - } - } - - getEffectiveWaitMs(maxWaitMs = 0) { - if (maxWaitMs > 0) { - return maxWaitMs; - } - if (this.app.isPackaged) { - return PACKAGED_BACKEND_TIMEOUT_FALLBACK_MS; - } - return 0; - } - - async requestBackendJson(pathname, options = {}) { - const timeoutMs = options.timeoutMs || 2000; - const method = options.method || 'GET'; - const controller = new AbortController(); - const timeout = setTimeout(() => controller.abort(), timeoutMs); - const requestUrl = new URL(pathname, this.backendUrl); - requestUrl.searchParams.set('_ts', `${Date.now()}`); - - const authToken = - typeof options.authToken === 'string' && options.authToken - ? options.authToken - : null; - - try { - const response = await fetch(requestUrl.toString(), { - method, - signal: controller.signal, - redirect: 'manual', - headers: { - Accept: 'application/json', - ...(authToken ? { Authorization: `Bearer ${authToken}` } : {}), - ...(options.headers || {}), - }, - }); - if (!response.ok) { - return { ok: false, data: null }; - } - const data = await response.json(); - return { ok: true, data }; - } catch { - return { ok: false, data: null }; - } finally { - clearTimeout(timeout); - } - } - - async getBackendStartTime() { - const result = await this.requestBackendJson('/api/stat/start-time', { - timeoutMs: 1800, - method: 'GET', - }); - if (!result.ok || !result.data) { - return null; - } - const rawStartTime = result.data?.data?.start_time; - const numericStartTime = Number(rawStartTime); - return Number.isFinite(numericStartTime) ? numericStartTime : null; - } - - async requestGracefulRestart(authToken = null) { - const result = await this.requestBackendJson('/api/stat/restart-core', { - timeoutMs: 2500, - method: 'POST', - authToken, - headers: { - 'Content-Type': 'application/json', - }, - }); - return result.ok; - } - - async waitForGracefulRestart(previousStartTime, maxWaitMs = 0) { - const effectiveMaxWaitMs = this.getEffectiveWaitMs(maxWaitMs); - const gracefulWaitMs = - effectiveMaxWaitMs > 0 - ? effectiveMaxWaitMs - : GRACEFUL_RESTART_WAIT_FALLBACK_MS; - const start = Date.now(); - let sawBackendDown = false; - - while (true) { - const reachable = await this.pingBackend(700); - if (!reachable) { - sawBackendDown = true; - } else { - const currentStartTime = await this.getBackendStartTime(); - if ( - previousStartTime !== null && - currentStartTime !== null && - currentStartTime !== previousStartTime - ) { - return { ok: true, reason: null }; - } - if (sawBackendDown && previousStartTime === null) { - return { ok: true, reason: null }; - } - } - - if (Date.now() - start >= gracefulWaitMs) { - return { - ok: false, - reason: `Timed out after ${gracefulWaitMs}ms waiting for graceful restart.`, - }; - } - - await delay(350); - } - } - - async waitForBackend(maxWaitMs = 0, failOnProcessExit = false) { - const effectiveMaxWaitMs = this.getEffectiveWaitMs(maxWaitMs); - const start = Date.now(); - while (true) { - if (await this.pingBackend()) { - return { ok: true, reason: null }; - } - if (failOnProcessExit && !this.backendProcess) { - return { - ok: false, - reason: - this.backendLastExitReason || - 'Backend process exited before becoming reachable.', - }; - } - if (effectiveMaxWaitMs > 0 && Date.now() - start >= effectiveMaxWaitMs) { - return { - ok: false, - reason: `Timed out after ${effectiveMaxWaitMs}ms waiting for backend startup.`, - }; - } - await delay(600); - } - } - - async startBackend() { - if (this.shouldSkipStart()) { - this.log('Skip backend start because app is quitting.'); - return; - } - if (this.backendProcess) { - return; - } - const backendConfig = this.getBackendConfig(); - if (!backendConfig.cmd) { - return; - } - - this.backendLastExitReason = null; - const env = { - ...process.env, - PYTHONUNBUFFERED: '1', - }; - if (this.app.isPackaged) { - env.ASTRBOT_ELECTRON_CLIENT = '1'; - const hasExplicitDashboardHost = Boolean( - process.env.DASHBOARD_HOST || process.env.ASTRBOT_DASHBOARD_HOST, - ); - const hasExplicitDashboardPort = Boolean( - process.env.DASHBOARD_PORT || process.env.ASTRBOT_DASHBOARD_PORT, - ); - if (!hasExplicitDashboardHost) { - env.DASHBOARD_HOST = '127.0.0.1'; - } - if (!hasExplicitDashboardPort) { - env.DASHBOARD_PORT = '6185'; - } - } - if (backendConfig.webuiDir) { - env.ASTRBOT_WEBUI_DIR = backendConfig.webuiDir; - } - let backendLogPath = null; - if (backendConfig.rootDir) { - env.ASTRBOT_ROOT = backendConfig.rootDir; - const logsDir = path.join(backendConfig.rootDir, 'logs'); - ensureDir(logsDir); - backendLogPath = path.join(logsDir, 'backend.log'); - } - await this.backendLogger.setLogPath(backendLogPath); - const usePipedLogging = Boolean(backendLogPath); - - this.backendProcess = spawn(backendConfig.cmd, backendConfig.args || [], { - cwd: backendConfig.cwd, - env, - shell: backendConfig.shell, - stdio: usePipedLogging ? ['ignore', 'pipe', 'pipe'] : 'ignore', - windowsHide: true, - }); - - if (usePipedLogging) { - if (this.backendProcess.stdout) { - this.backendProcess.stdout.on('data', (chunk) => { - this.backendLogger.log(chunk); - }); - } - if (this.backendProcess.stderr) { - this.backendProcess.stderr.on('data', (chunk) => { - this.backendLogger.log(chunk); - }); - } - } - - if (usePipedLogging) { - const launchLine = [backendConfig.cmd, ...(backendConfig.args || [])] - .map((item) => JSON.stringify(item)) - .join(' '); - this.backendLogger.log( - `[${formatLogTimestamp()}] [Electron] Start backend ${launchLine}\n`, - ); - } - - this.backendProcess.on('error', (error) => { - this.backendLastExitReason = - error instanceof Error ? error.message : String(error); - this.backendLogger.log( - `[${formatLogTimestamp()}] [Electron] Backend spawn error: ${ - error instanceof Error ? error.message : String(error) - }\n`, - ); - void this.backendLogger.flush(); - this.backendProcess = null; - }); - - this.backendProcess.on('exit', (code, signal) => { - this.backendLastExitReason = `Backend process exited (code=${code ?? 'null'}, signal=${signal ?? 'null'}).`; - void this.backendLogger.flush(); - this.backendProcess = null; - }); - } - - async startBackendAndWait(maxWaitMs = this.backendTimeoutMs) { - if (!this.canManageBackend()) { - return { - ok: false, - reason: 'Backend command is not configured.', - }; - } - this.backendSpawning = true; - try { - await this.startBackend(); - return await this.waitForBackend(maxWaitMs, true); - } finally { - this.backendSpawning = false; - } - } - - async stopManagedBackend() { - if (!this.backendProcess) { - return; - } - const processToStop = this.backendProcess; - const pid = processToStop.pid; - this.backendProcess = null; - this.log(`Stop backend requested pid=${pid ?? 'unknown'}`); - - if (process.platform === 'win32' && pid) { - try { - // Synchronous taskkill is acceptable here because stop/restart is - // already a control-path operation and not latency-sensitive. - const result = spawnSync('taskkill', ['/pid', `${pid}`, '/t', '/f'], { - stdio: 'ignore', - windowsHide: true, - }); - if (result.status !== 0) { - this.log( - `taskkill failed pid=${pid} status=${result.status} signal=${result.signal ?? 'null'}`, - ); - } else { - this.log(`taskkill completed pid=${pid}`); - } - } catch (error) { - this.log( - `taskkill threw for pid=${pid}: ${ - error instanceof Error ? error.message : String(error) - }`, - ); - } - await waitForProcessExit(processToStop, 5000); - } else { - if (!processToStop.killed) { - try { - processToStop.kill('SIGTERM'); - } catch (error) { - this.log( - `SIGTERM failed for pid=${pid ?? 'unknown'}: ${ - error instanceof Error ? error.message : String(error) - }`, - ); - } - } - const exitResult = await waitForProcessExit(processToStop, 5000); - if (exitResult === 'timeout' && !processToStop.killed) { - try { - processToStop.kill('SIGKILL'); - } catch {} - await waitForProcessExit(processToStop, 1500); - } - } - await this.backendLogger.flush(); - } - - findListeningPidsOnWindows(port) { - // Synchronous netstat parsing is acceptable here because this helper is - // used only during shutdown/restart cleanup paths. - const result = spawnSync('netstat', ['-ano', '-p', 'tcp'], { - stdio: ['ignore', 'pipe', 'ignore'], - encoding: 'utf8', - windowsHide: true, - }); - - if (result.status !== 0 || !result.stdout) { - return []; - } - - const pids = new Set(); - const lines = result.stdout.split(/\r?\n/); - - for (const line of lines) { - const trimmed = line.trim(); - if (!trimmed || !trimmed.toUpperCase().startsWith('TCP')) { - continue; - } - - const parts = trimmed.split(/\s+/); - if (parts.length < 5) { - continue; - } - - const localAddress = parts[1] || ''; - const state = (parts[3] || '').toUpperCase(); - const pid = parts[parts.length - 1]; - if (!/^\d+$/.test(pid)) { - continue; - } - - if (state !== 'LISTENING') { - continue; - } - - const cleanedLocalAddress = localAddress.replace(/\]$/, ''); - const segments = cleanedLocalAddress.split(':'); - const portStr = segments[segments.length - 1]; - const portNum = Number(portStr); - if (Number.isInteger(portNum) && portNum === Number(port)) { - pids.add(pid); - } - } - - return Array.from(pids); - } - - getWindowsProcessInfo(pid) { - const result = spawnSync( - 'tasklist', - ['/FI', `PID eq ${pid}`, '/FO', 'CSV', '/NH'], - { - stdio: ['ignore', 'pipe', 'ignore'], - encoding: 'utf8', - windowsHide: true, - }, - ); - if (result.status !== 0 || !result.stdout) { - return null; - } - - const firstLine = result.stdout - .split(/\r?\n/) - .map((line) => line.trim()) - .find((line) => line.length > 0); - if (!firstLine || firstLine.startsWith('INFO:')) { - return null; - } - - const fields = firstLine - .replace(/^"/, '') - .replace(/"$/, '') - .split('","'); - const imageName = fields[0] || ''; - const parsedPid = Number.parseInt(fields[1] || '', 10); - if (!imageName || !Number.isInteger(parsedPid) || parsedPid !== Number(pid)) { - return null; - } - return { imageName, pid: parsedPid }; - } - - async stopUnmanagedBackendByPort() { - if (!this.app.isPackaged || process.platform !== 'win32') { - return false; - } - - const port = this.getBackendPort(); - if (!port) { - return false; - } - - const pids = this.findListeningPidsOnWindows(port); - if (!pids.length) { - return false; - } - - this.log( - `Attempting unmanaged backend cleanup by port=${port} pids=${pids.join(',')}`, - ); - - const expectedImageName = ( - path.basename(this.getPackagedBackendPath() || '') || 'astrbot-backend.exe' - ).toLowerCase(); - - for (const pid of pids) { - const processInfo = this.getWindowsProcessInfo(pid); - if (!processInfo) { - this.log(`Skip unmanaged cleanup for pid=${pid}: unable to resolve process info.`); - continue; - } - - const actualImageName = processInfo.imageName.toLowerCase(); - if (actualImageName !== expectedImageName) { - this.log( - `Skip unmanaged cleanup for pid=${pid}: unexpected process image ${processInfo.imageName}.`, - ); - continue; - } - - try { - // Synchronous taskkill is acceptable here because unmanaged cleanup - // is performed only during shutdown/restart control flows. - spawnSync('taskkill', ['/pid', `${pid}`, '/t', '/f'], { - stdio: 'ignore', - windowsHide: true, - }); - } catch {} - } - - await delay(500); - return !(await this.pingBackend(1200)); - } - - async stopAnyBackend() { - if (this.backendProcess) { - await this.stopManagedBackend(); - const running = await this.pingBackend(); - if (!running) { - return { ok: true, reason: null }; - } - } else { - const running = await this.pingBackend(); - if (!running) { - return { ok: true, reason: null }; - } - } - - const cleaned = await this.stopUnmanagedBackendByPort(); - if (cleaned) { - return { ok: true, reason: null }; - } - - return { - ok: false, - reason: 'Backend is running but not managed by Electron.', - }; - } - - async ensureBackend() { - this.backendStartupFailureReason = null; - - const running = await this.pingBackend(); - if (running) { - return true; - } - if (!this.backendAutoStart || !this.canManageBackend()) { - this.backendStartupFailureReason = - 'Backend auto-start is disabled or backend command is not configured.'; - return false; - } - const waitResult = await this.startBackendAndWait(this.backendTimeoutMs); - if (!waitResult.ok) { - this.backendStartupFailureReason = waitResult.reason; - return false; - } - return true; - } - - async getState() { - return { - running: await this.pingBackend(), - spawning: this.backendSpawning, - restarting: this.backendRestarting, - canManage: this.canManageBackend(), - }; - } - - async restartBackend(authToken = null) { - if (!this.canManageBackend()) { - return { - ok: false, - reason: 'Backend command is not configured.', - }; - } - if (this.backendSpawning || this.backendRestarting) { - return { - ok: false, - reason: 'Backend action already in progress.', - }; - } - - this.backendRestarting = true; - try { - const backendRunning = await this.pingBackend(900); - if (backendRunning) { - const previousStartTime = await this.getBackendStartTime(); - const gracefulRequested = await this.requestGracefulRestart(authToken); - if (gracefulRequested) { - const gracefulResult = await this.waitForGracefulRestart( - previousStartTime, - this.backendTimeoutMs, - ); - if (gracefulResult.ok) { - return { - ok: true, - reason: null, - }; - } - this.log( - `Graceful restart did not complete: ${gracefulResult.reason || 'unknown reason'}`, - ); - } else { - this.log( - 'Graceful restart request failed; falling back to managed restart.', - ); - } - } - - await this.stopManagedBackend(); - const startResult = await this.startBackendAndWait(this.backendTimeoutMs); - if (!startResult.ok) { - return { - ok: false, - reason: startResult.reason || 'Failed to restart backend.', - }; - } - return { - ok: true, - reason: null, - }; - } catch (error) { - return { - ok: false, - reason: error instanceof Error ? error.message : String(error), - }; - } finally { - this.backendRestarting = false; - } - } - - async stopBackendForIpc() { - if (!this.canManageBackend()) { - return { - ok: false, - reason: 'Backend command is not configured.', - }; - } - if (this.backendSpawning || this.backendRestarting) { - return { - ok: false, - reason: 'Backend action already in progress.', - }; - } - - try { - return await this.stopAnyBackend(); - } catch (error) { - return { - ok: false, - reason: error instanceof Error ? error.message : String(error), - }; - } - } -} - -module.exports = { - BackendManager, -}; diff --git a/desktop/lib/buffered-rotating-logger.js b/desktop/lib/buffered-rotating-logger.js deleted file mode 100644 index 7a443a97d..000000000 --- a/desktop/lib/buffered-rotating-logger.js +++ /dev/null @@ -1,162 +0,0 @@ -'use strict'; - -const { RotatingLogWriter } = require('./rotating-log-writer'); -const { parseEnvInt } = require('./common'); - -const DEFAULT_FLUSH_INTERVAL_MS = 120; -const DEFAULT_MAX_BUFFER_BYTES = 128 * 1024; -const MIN_FLUSH_INTERVAL_MS = 10; -const MIN_MAX_BUFFER_BYTES = 4 * 1024; -const MAX_MAX_BUFFER_BYTES = 16 * 1024 * 1024; - -function clampIntOption(raw, { defaultValue, min, max }) { - const value = parseEnvInt(raw, defaultValue); - return Math.min(Math.max(value, min), max); -} - -class BufferedRotatingLogger { - constructor({ - logPath = null, - maxBytes, - backupCount, - flushIntervalMs, - maxBufferBytes, - label = 'buffered-log', - }) { - this.logPath = logPath || null; - this.flushIntervalMs = clampIntOption(flushIntervalMs, { - defaultValue: DEFAULT_FLUSH_INTERVAL_MS, - min: MIN_FLUSH_INTERVAL_MS, - max: 60 * 1000, - }); - this.maxBufferBytes = clampIntOption(maxBufferBytes, { - defaultValue: DEFAULT_MAX_BUFFER_BYTES, - min: MIN_MAX_BUFFER_BYTES, - max: MAX_MAX_BUFFER_BYTES, - }); - this.buffer = []; - this.bufferBytes = 0; - this.flushTimer = null; - this.pathSwitch = Promise.resolve(); - this.writer = new RotatingLogWriter({ - logPath: this.logPath, - maxBytes, - backupCount, - label, - }); - } - - setLogPath(logPath) { - const nextLogPath = logPath || null; - this.pathSwitch = this.pathSwitch.then(async () => { - if (nextLogPath === this.logPath) { - await this.flush(); - return; - } - - const previousLogPath = this.logPath; - if (previousLogPath) { - await this.flush(); - } - - this.logPath = null; - await this.writer.setLogPath(nextLogPath); - this.logPath = nextLogPath; - await this.flush(); - }); - return this.pathSwitch; - } - - log(payload) { - if (payload === undefined || payload === null) { - return; - } - const chunk = Buffer.isBuffer(payload) - ? payload - : Buffer.from(String(payload), 'utf8'); - if (!chunk.length) { - return; - } - - if (!this.logPath) { - const boundedChunk = this.clipChunkToBufferLimit(chunk); - this.dropOldestUntilWithinLimit(boundedChunk.length); - this.buffer.push(boundedChunk); - this.bufferBytes += boundedChunk.length; - return; - } - - this.buffer.push(chunk); - this.bufferBytes += chunk.length; - - if (this.bufferBytes >= this.maxBufferBytes) { - void this.flush(); - return; - } - this.scheduleFlush(); - } - - flush() { - this.clearFlushTimer(); - if (!this.buffer.length) { - return this.writer.flush(); - } - if (!this.logPath) { - // Path is switching or temporarily unavailable; keep buffered data. - this.dropOldestUntilWithinLimit(0); - return this.writer.flush(); - } - - const chunks = this.buffer; - this.buffer = []; - this.bufferBytes = 0; - const payload = chunks.length === 1 ? chunks[0] : Buffer.concat(chunks); - this.writer.append(payload); - return this.writer.flush(); - } - - dropOldestUntilWithinLimit(incomingBytes = 0) { - while ( - this.buffer.length && - this.bufferBytes + Math.max(0, incomingBytes) > this.maxBufferBytes - ) { - const removed = this.buffer.shift(); - if (removed) { - this.bufferBytes -= removed.length; - } - } - if (this.bufferBytes < 0) { - this.bufferBytes = 0; - } - } - - clipChunkToBufferLimit(chunk) { - if (chunk.length <= this.maxBufferBytes) { - return chunk; - } - return chunk.subarray(chunk.length - this.maxBufferBytes); - } - - scheduleFlush() { - if (this.flushTimer !== null) { - return; - } - this.flushTimer = setTimeout(() => { - this.flushTimer = null; - void this.flush(); - }, this.flushIntervalMs); - this.flushTimer.unref?.(); - } - - clearFlushTimer() { - if (this.flushTimer === null) { - return; - } - clearTimeout(this.flushTimer); - this.flushTimer = null; - } -} - -module.exports = { - BufferedRotatingLogger, -}; diff --git a/desktop/lib/common.js b/desktop/lib/common.js deleted file mode 100644 index 9f39358dc..000000000 --- a/desktop/lib/common.js +++ /dev/null @@ -1,115 +0,0 @@ -'use strict'; - -const fs = require('fs'); - -const LOG_ROTATION_DEFAULT_MAX_MB = 20; -const LOG_ROTATION_DEFAULT_BACKUP_COUNT = 3; - -function normalizeUrl(value) { - try { - const url = new URL(value); - if (!url.pathname.endsWith('/')) { - url.pathname += '/'; - } - return url.toString(); - } catch { - return 'http://127.0.0.1:6185/'; - } -} - -function ensureDir(value) { - if (!value) { - return; - } - if (fs.existsSync(value)) { - return; - } - fs.mkdirSync(value, { recursive: true }); -} - -function parseEnvInt(raw, defaultValue) { - const parsed = Number.parseInt(`${raw ?? ''}`, 10); - return Number.isFinite(parsed) ? parsed : defaultValue; -} - -function isLogRotationDebugEnabled() { - return ( - process.env.ASTRBOT_LOG_ROTATION_DEBUG === '1' || - process.env.NODE_ENV === 'development' - ); -} - -function parseLogMaxBytes(envValue) { - const mb = parseEnvInt(envValue, LOG_ROTATION_DEFAULT_MAX_MB); - const maxMb = mb > 0 ? mb : LOG_ROTATION_DEFAULT_MAX_MB; - return maxMb * 1024 * 1024; -} - -function parseLogBackupCount(envValue) { - const count = parseEnvInt(envValue, LOG_ROTATION_DEFAULT_BACKUP_COUNT); - return count >= 0 ? count : LOG_ROTATION_DEFAULT_BACKUP_COUNT; -} - -function isIgnorableFsError(error) { - return Boolean(error && typeof error === 'object' && error.code === 'ENOENT'); -} - -function delay(ms) { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -function waitForProcessExit(child, timeoutMs = 5000) { - if (!child) { - return Promise.resolve('missing'); - } - if (child.exitCode !== null || child.signalCode !== null) { - return Promise.resolve('exited'); - } - return new Promise((resolve) => { - let settled = false; - const finish = (reason) => { - if (settled) { - return; - } - settled = true; - clearTimeout(timeout); - resolve(reason); - }; - const timeout = setTimeout(() => finish('timeout'), timeoutMs); - child.once('exit', () => finish('exit')); - child.once('error', () => finish('error')); - }); -} - -function formatLogTimestamp(date = new Date()) { - const year = date.getFullYear(); - const month = `${date.getMonth() + 1}`.padStart(2, '0'); - const day = `${date.getDate()}`.padStart(2, '0'); - const hour = `${date.getHours()}`.padStart(2, '0'); - const minute = `${date.getMinutes()}`.padStart(2, '0'); - const second = `${date.getSeconds()}`.padStart(2, '0'); - const millisecond = `${date.getMilliseconds()}`.padStart(3, '0'); - - const offsetMinutes = -date.getTimezoneOffset(); - const offsetSign = offsetMinutes >= 0 ? '+' : '-'; - const absOffsetMinutes = Math.abs(offsetMinutes); - const offsetHour = `${Math.floor(absOffsetMinutes / 60)}`.padStart(2, '0'); - const offsetMinute = `${absOffsetMinutes % 60}`.padStart(2, '0'); - - return `${year}-${month}-${day} ${hour}:${minute}:${second}.${millisecond} ${offsetSign}${offsetHour}${offsetMinute}`; -} - -module.exports = { - LOG_ROTATION_DEFAULT_BACKUP_COUNT, - LOG_ROTATION_DEFAULT_MAX_MB, - delay, - ensureDir, - formatLogTimestamp, - isIgnorableFsError, - isLogRotationDebugEnabled, - normalizeUrl, - parseEnvInt, - parseLogBackupCount, - parseLogMaxBytes, - waitForProcessExit, -}; diff --git a/desktop/lib/dashboard-loader.js b/desktop/lib/dashboard-loader.js deleted file mode 100644 index 6e858843f..000000000 --- a/desktop/lib/dashboard-loader.js +++ /dev/null @@ -1,30 +0,0 @@ -'use strict'; - -const { delay } = require('./common'); - -async function loadDashboard(mainWindow, backendUrl, maxWaitMs = 20000) { - if (!mainWindow) { - return false; - } - const loadUrl = new URL(backendUrl); - loadUrl.searchParams.set('_electron_ts', `${Date.now()}`); - const start = Date.now(); - let lastError = null; - while (maxWaitMs <= 0 || Date.now() - start < maxWaitMs) { - try { - await mainWindow.loadURL(loadUrl.toString()); - return true; - } catch (error) { - lastError = error; - await delay(600); - } - } - if (lastError) { - throw lastError; - } - throw new Error(`Timed out loading ${backendUrl}`); -} - -module.exports = { - loadDashboard, -}; diff --git a/desktop/lib/electron-logger.js b/desktop/lib/electron-logger.js deleted file mode 100644 index 6a52d1c76..000000000 --- a/desktop/lib/electron-logger.js +++ /dev/null @@ -1,53 +0,0 @@ -'use strict'; - -const path = require('path'); -const { RotatingLogWriter } = require('./rotating-log-writer'); -const { - formatLogTimestamp, - parseLogBackupCount, - parseLogMaxBytes, -} = require('./common'); - -function createElectronLogger({ app, getRootDir }) { - const electronLogMaxBytes = parseLogMaxBytes( - process.env.ASTRBOT_ELECTRON_LOG_MAX_MB, - ); - const electronLogBackupCount = parseLogBackupCount( - process.env.ASTRBOT_ELECTRON_LOG_BACKUP_COUNT, - ); - const writer = new RotatingLogWriter({ - logPath: null, - maxBytes: electronLogMaxBytes, - backupCount: electronLogBackupCount, - label: 'electron-log', - }); - - function getElectronLogPath() { - const rootDir = - process.env.ASTRBOT_ROOT || - (typeof getRootDir === 'function' ? getRootDir() : null) || - app.getPath('userData'); - return path.join(rootDir, 'logs', 'electron.log'); - } - - function logElectron(message) { - const logPath = getElectronLogPath(); - const line = `[${formatLogTimestamp()}] ${message}\n`; - void writer.setLogPath(logPath); - void writer.append(line); - } - - async function flushElectron() { - await writer.flush(); - } - - return { - getElectronLogPath, - logElectron, - flushElectron, - }; -} - -module.exports = { - createElectronLogger, -}; diff --git a/desktop/lib/locale-service.js b/desktop/lib/locale-service.js deleted file mode 100644 index d68039e7d..000000000 --- a/desktop/lib/locale-service.js +++ /dev/null @@ -1,174 +0,0 @@ -'use strict'; - -const fs = require('fs'); -const path = require('path'); -const { delay, ensureDir } = require('./common'); - -const LOCALE_STORAGE_KEY = 'astrbot-locale'; -const SUPPORTED_STARTUP_LOCALES = new Set(['zh-CN', 'en-US']); - -function normalizeLocale(value) { - if (!value) { - return null; - } - const raw = String(value).trim(); - if (!raw) { - return null; - } - if (SUPPORTED_STARTUP_LOCALES.has(raw)) { - return raw; - } - const lower = raw.toLowerCase(); - if (lower.startsWith('zh')) { - return 'zh-CN'; - } - if (lower.startsWith('en')) { - return 'en-US'; - } - return null; -} - -function getStartupTexts(locale) { - if (locale === 'zh-CN') { - return { - title: 'AstrBot 正在启动', - message: '界面很快就会加载完成。', - }; - } - return { - title: 'AstrBot is starting', - message: 'The dashboard will be ready in a moment.', - }; -} - -function getShellTexts(locale) { - if (locale === 'zh-CN') { - return { - trayHide: '隐藏 AstrBot', - trayShow: '显示 AstrBot', - trayReload: '重新加载', - trayRestartBackend: '重启后端', - trayQuit: '退出', - startupFailTitle: 'AstrBot 启动失败', - startupFailMessage: 'AstrBot 后端不可达。', - startupFailReasonPrefix: '原因', - startupFailAction: - '请先启动 http://127.0.0.1:6185 的后端服务,然后重新打开 AstrBot。', - startupFailLogPrefix: '后端日志', - dashboardFailTitle: 'AstrBot 加载失败', - dashboardFailMessage: '无法加载 AstrBot 控制台页面。', - }; - } - return { - trayHide: 'Hide AstrBot', - trayShow: 'Show AstrBot', - trayReload: 'Reload', - trayRestartBackend: 'Restart Backend', - trayQuit: 'Quit', - startupFailTitle: 'AstrBot startup failed', - startupFailMessage: 'AstrBot backend is not reachable.', - startupFailReasonPrefix: 'Reason', - startupFailAction: - 'Please start the backend at http://127.0.0.1:6185 and relaunch AstrBot.', - startupFailLogPrefix: 'Backend log', - dashboardFailTitle: 'Failed to load AstrBot', - dashboardFailMessage: 'Unable to load the AstrBot dashboard.', - }; -} - -function createLocaleService({ app, getRootDir }) { - function resolveStateRoot() { - const callbackRoot = (() => { - try { - return getRootDir ? getRootDir() : null; - } catch { - return null; - } - })(); - return process.env.ASTRBOT_ROOT || callbackRoot || app.getPath('userData'); - } - - function getDesktopStatePath() { - return path.join(resolveStateRoot(), 'data', 'desktop_state.json'); - } - - function readCachedLocale() { - const statePath = getDesktopStatePath(); - try { - const raw = fs.readFileSync(statePath, 'utf8'); - const parsed = JSON.parse(raw); - return normalizeLocale(parsed?.locale); - } catch { - return null; - } - } - - function writeCachedLocale(locale) { - const normalized = normalizeLocale(locale); - if (!normalized) { - return; - } - const statePath = getDesktopStatePath(); - ensureDir(path.dirname(statePath)); - try { - fs.writeFileSync( - statePath, - `${JSON.stringify({ locale: normalized }, null, 2)}\n`, - 'utf8', - ); - } catch {} - } - - function resolveStartupLocale() { - const cached = readCachedLocale(); - if (cached) { - return cached; - } - return normalizeLocale(app.getLocale()) || 'zh-CN'; - } - - async function persistLocaleFromDashboard( - mainWindow, - backendUrl, - timeoutMs = 1200, - ) { - if (!mainWindow || mainWindow.isDestroyed()) { - return; - } - const currentUrl = mainWindow.webContents.getURL(); - if (!currentUrl || !currentUrl.startsWith(backendUrl)) { - return; - } - try { - const localeRaw = await Promise.race([ - mainWindow.webContents.executeJavaScript( - `(() => { - try { - return window.localStorage.getItem('${LOCALE_STORAGE_KEY}') || ''; - } catch { - return ''; - } - })();`, - true, - ), - delay(timeoutMs).then(() => null), - ]); - const locale = normalizeLocale(localeRaw); - if (locale) { - writeCachedLocale(locale); - } - } catch {} - } - - return { - getShellTexts, - getStartupTexts, - persistLocaleFromDashboard, - resolveStartupLocale, - }; -} - -module.exports = { - createLocaleService, - normalizeLocale, -}; diff --git a/desktop/lib/rotating-log-writer.js b/desktop/lib/rotating-log-writer.js deleted file mode 100644 index c6c8f8fb1..000000000 --- a/desktop/lib/rotating-log-writer.js +++ /dev/null @@ -1,178 +0,0 @@ -'use strict'; - -const fs = require('fs/promises'); -const path = require('path'); -const { isIgnorableFsError, isLogRotationDebugEnabled } = require('./common'); - -class RotatingLogWriter { - constructor({ logPath = null, maxBytes = 0, backupCount = 0, label = 'log' }) { - this.logPath = logPath || null; - this.maxBytes = Number.isFinite(maxBytes) && maxBytes > 0 ? maxBytes : 0; - this.backupCount = Number.isFinite(backupCount) && backupCount >= 0 ? backupCount : 0; - this.label = label; - this.cachedSize = null; - this.dirReadyForPath = null; - this.queue = Promise.resolve(); - } - - setLogPath(logPath) { - const nextPath = logPath || null; - if (nextPath === this.logPath) { - return this.queue; - } - return this.enqueue(async () => { - this.logPath = nextPath; - this.cachedSize = null; - this.dirReadyForPath = null; - }); - } - - append(payload) { - if (payload === undefined || payload === null) { - return this.queue; - } - const content = Buffer.isBuffer(payload) - ? payload - : Buffer.from(String(payload), 'utf8'); - if (!content.length) { - return this.queue; - } - return this.enqueue(async () => { - if (!this.logPath) { - return; - } - await this.ensureDirReady(); - await this.ensureSizeLoaded(); - await this.rotateIfNeeded(content.length); - await fs.appendFile(this.logPath, content); - if (!Number.isFinite(this.cachedSize)) { - this.cachedSize = await this.readSize(); - } else { - this.cachedSize += content.length; - } - }); - } - - flush() { - return this.queue; - } - - enqueue(task) { - const run = async () => { - try { - await task(); - } catch (error) { - this.reportError('write', this.logPath || 'unknown', error); - } - }; - this.queue = this.queue.then(run, run); - return this.queue; - } - - async ensureSizeLoaded() { - if (Number.isFinite(this.cachedSize)) { - return; - } - this.cachedSize = await this.readSize(); - } - - async ensureDirReady() { - if (!this.logPath) { - return; - } - if (this.dirReadyForPath === this.logPath) { - return; - } - const dirPath = path.dirname(this.logPath); - try { - await fs.mkdir(dirPath, { recursive: true }); - this.dirReadyForPath = this.logPath; - } catch (error) { - this.reportError('mkdir', dirPath, error); - } - } - - async readSize() { - if (!this.logPath) { - return 0; - } - try { - const stat = await fs.stat(this.logPath); - return stat.size; - } catch (error) { - if (isIgnorableFsError(error)) { - return 0; - } - this.reportError('stat', this.logPath, error); - return 0; - } - } - - async rotateIfNeeded(incomingBytes) { - if (!this.logPath || this.maxBytes <= 0) { - return; - } - - const currentSize = Number.isFinite(this.cachedSize) ? this.cachedSize : 0; - if (currentSize + Math.max(0, incomingBytes) <= this.maxBytes) { - return; - } - - if (this.backupCount <= 0) { - try { - await fs.truncate(this.logPath, 0); - } catch (error) { - if (!isIgnorableFsError(error)) { - this.reportError('truncate', this.logPath, error); - } - } - this.cachedSize = await this.readSize(); - return; - } - - const oldestPath = `${this.logPath}.${this.backupCount}`; - try { - await fs.unlink(oldestPath); - } catch (error) { - if (!isIgnorableFsError(error)) { - this.reportError('unlink', oldestPath, error); - } - } - - for (let index = this.backupCount - 1; index >= 1; index -= 1) { - const sourcePath = `${this.logPath}.${index}`; - const targetPath = `${this.logPath}.${index + 1}`; - try { - await fs.rename(sourcePath, targetPath); - } catch (error) { - if (!isIgnorableFsError(error)) { - this.reportError('rename', `${sourcePath} -> ${targetPath}`, error); - } - } - } - - try { - await fs.rename(this.logPath, `${this.logPath}.1`); - } catch (error) { - if (!isIgnorableFsError(error)) { - this.reportError('rename', `${this.logPath} -> ${this.logPath}.1`, error); - } - } - - this.cachedSize = await this.readSize(); - } - - reportError(action, targetPath, error) { - if (!isLogRotationDebugEnabled()) { - return; - } - const details = error instanceof Error ? error.message : String(error); - console.error( - `[astrbot][${this.label}] ${action} failed for ${targetPath}: ${details}`, - ); - } -} - -module.exports = { - RotatingLogWriter, -}; diff --git a/desktop/lib/startup-screen.js b/desktop/lib/startup-screen.js deleted file mode 100644 index 93a342b81..000000000 --- a/desktop/lib/startup-screen.js +++ /dev/null @@ -1,116 +0,0 @@ -'use strict'; - -const fs = require('fs'); - -async function loadStartupScreen(mainWindow, { getAssetPath, startupTexts }) { - if (!mainWindow) { - return false; - } - let iconUrl = ''; - try { - const iconBuffer = fs.readFileSync(getAssetPath('icon-no-shadow.svg')); - iconUrl = `data:image/svg+xml;base64,${iconBuffer.toString('base64')}`; - } catch {} - - const html = ` - - - - - AstrBot - - - -
- ${ - iconUrl - ? `` - : '' - } - -

${startupTexts.title}

-

${startupTexts.message}

-
- -`; - const startupUrl = `data:text/html;charset=utf-8,${encodeURIComponent(html)}`; - await mainWindow.loadURL(startupUrl); - return true; -} - -module.exports = { - loadStartupScreen, -}; diff --git a/desktop/main.js b/desktop/main.js deleted file mode 100644 index 5adff38b3..000000000 --- a/desktop/main.js +++ /dev/null @@ -1,420 +0,0 @@ -'use strict'; - -const fs = require('fs'); -const path = require('path'); -const { - app, - BrowserWindow, - Menu, - Tray, - nativeImage, - shell, - dialog, - ipcMain, -} = require('electron'); - -const { BackendManager } = require('./lib/backend-manager'); -const { loadDashboard } = require('./lib/dashboard-loader'); -const { createElectronLogger } = require('./lib/electron-logger'); -const { createLocaleService } = require('./lib/locale-service'); -const { loadStartupScreen } = require('./lib/startup-screen'); - -const isMac = process.platform === 'darwin'; -const dashboardTimeoutMsParsed = Number.parseInt( - process.env.ASTRBOT_DASHBOARD_TIMEOUT_MS || '20000', - 10, -); -const dashboardTimeoutMs = Number.isFinite(dashboardTimeoutMsParsed) - ? dashboardTimeoutMsParsed - : 20000; - -let mainWindow = null; -let tray = null; -let isQuitting = false; -let quitInProgress = false; -let backendManager = null; - -app.commandLine.appendSwitch('disable-http-cache'); - -const { logElectron, flushElectron } = createElectronLogger({ - app, - getRootDir: () => (backendManager ? backendManager.getRootDir() : null), -}); - -backendManager = new BackendManager({ - app, - baseDir: __dirname, - log: logElectron, - shouldSkipStart: () => isQuitting || quitInProgress, -}); - -const localeService = createLocaleService({ - app, - getRootDir: () => backendManager.getRootDir(), -}); - -function getAssetPath(filename) { - if (app.isPackaged) { - const packaged = path.join(process.resourcesPath, 'assets', filename); - if (fs.existsSync(packaged)) { - return packaged; - } - } - return path.join(__dirname, 'assets', filename); -} - -function loadImageSafe(imagePath) { - try { - const image = nativeImage.createFromPath(imagePath); - if (!image.isEmpty()) { - return image; - } - } catch {} - return nativeImage.createEmpty(); -} - -function showWindow() { - if (!mainWindow) { - return; - } - mainWindow.show(); - mainWindow.focus(); - updateTrayMenu(); -} - -function toggleWindow() { - if (!mainWindow) { - return; - } - if (mainWindow.isVisible()) { - mainWindow.hide(); - } else { - mainWindow.show(); - mainWindow.focus(); - } - updateTrayMenu(); -} - -function updateTrayMenu() { - if (!tray || !mainWindow) { - return; - } - const shellTexts = localeService.getShellTexts( - localeService.resolveStartupLocale(), - ); - const isVisible = mainWindow.isVisible(); - const contextMenu = Menu.buildFromTemplate([ - { - label: isVisible ? shellTexts.trayHide : shellTexts.trayShow, - click: () => toggleWindow(), - }, - { - label: shellTexts.trayReload, - click: () => { - if (mainWindow) { - mainWindow.reload(); - } - }, - }, - { - label: shellTexts.trayRestartBackend, - click: async () => { - if (!backendManager) { - return; - } - if (mainWindow && !mainWindow.isDestroyed()) { - showWindow(); - const currentUrl = mainWindow.webContents.getURL(); - if (currentUrl.startsWith(backendManager.getBackendUrl())) { - mainWindow.webContents.send('astrbot-desktop:tray-restart-backend'); - return; - } - } - - const result = await backendManager.restartBackend(); - if (!result.ok) { - logElectron( - `Tray restart backend fallback failed: ${result.reason || 'unknown reason'}`, - ); - } - }, - }, - { type: 'separator' }, - { - label: shellTexts.trayQuit, - click: () => app.quit(), - }, - ]); - tray.setContextMenu(contextMenu); -} - -function createTray() { - const traySize = isMac ? 18 : 16; - const trayPath = getAssetPath('tray.png'); - let trayImage = loadImageSafe(trayPath); - if (trayImage.isEmpty()) { - trayImage = loadImageSafe(getAssetPath('icon.png')); - } - if (!trayImage.isEmpty()) { - trayImage = trayImage.resize({ width: traySize, height: traySize }); - if (isMac) { - trayImage.setTemplateImage(true); - } - tray = new Tray(trayImage); - } else { - tray = new Tray(nativeImage.createEmpty()); - } - tray.setToolTip('AstrBot'); - tray.on('click', () => toggleWindow()); - updateTrayMenu(); -} - -function createWindow() { - mainWindow = new BrowserWindow({ - width: 1280, - height: 800, - minWidth: 980, - minHeight: 680, - show: false, - backgroundColor: '#f9fafc', - autoHideMenuBar: !isMac, - icon: getAssetPath('icon.png'), - webPreferences: { - contextIsolation: true, - nodeIntegration: false, - sandbox: true, - preload: path.join(__dirname, 'preload.js'), - ...(isMac - ? { - defaultFontFamily: { - standard: 'PingFang SC', - sansSerif: 'PingFang SC', - serif: 'Songti SC', - monospace: 'SF Mono', - }, - } - : {}), - }, - }); - - mainWindow.on('close', (event) => { - if (isQuitting) { - return; - } - event.preventDefault(); - mainWindow.hide(); - }); - - mainWindow.on('minimize', (event) => { - event.preventDefault(); - mainWindow.hide(); - }); - - mainWindow.on('show', () => updateTrayMenu()); - mainWindow.on('hide', () => updateTrayMenu()); - - mainWindow.webContents.setWindowOpenHandler(({ url }) => { - shell.openExternal(url); - return { action: 'deny' }; - }); - - mainWindow.webContents.on( - 'did-fail-load', - (_event, errorCode, errorDescription, validatedURL, isMainFrame) => { - if (!isMainFrame) { - return; - } - logElectron( - `did-fail-load main-frame code=${errorCode} desc=${errorDescription} url=${validatedURL}`, - ); - }, - ); - - mainWindow.webContents.on('did-finish-load', () => { - const currentUrl = mainWindow.webContents.getURL(); - logElectron(`did-finish-load url=${currentUrl}`); - if (currentUrl.startsWith(backendManager.getBackendUrl())) { - void localeService.persistLocaleFromDashboard( - mainWindow, - backendManager.getBackendUrl(), - ); - } - }); - - mainWindow.webContents.on('render-process-gone', (_event, details) => { - logElectron( - `render-process-gone reason=${details.reason} exitCode=${details.exitCode}`, - ); - }); - - mainWindow.webContents.on( - 'console-message', - (_event, level, message, line, sourceId) => { - if (level >= 2) { - logElectron( - `renderer-console level=${level} source=${sourceId}:${line} message=${message}`, - ); - } - }, - ); - - return mainWindow; -} - -function registerIpcHandlers() { - ipcMain.handle('astrbot-desktop:is-electron-runtime', async () => true); - - ipcMain.handle('astrbot-desktop:get-backend-state', async () => { - return backendManager.getState(); - }); - - ipcMain.handle('astrbot-desktop:restart-backend', async (_event, authToken) => { - return backendManager.restartBackend(authToken); - }); - - ipcMain.handle('astrbot-desktop:stop-backend', async () => { - return backendManager.stopBackendForIpc(); - }); -} - -async function startDesktopFlow() { - createWindow(); - createTray(); - - try { - const startupTexts = localeService.getStartupTexts( - localeService.resolveStartupLocale(), - ); - await loadStartupScreen(mainWindow, { - getAssetPath, - startupTexts, - }); - } catch (error) { - logElectron( - `failed to load startup screen: ${ - error instanceof Error ? error.message : String(error) - }`, - ); - } - - showWindow(); - - const ready = await backendManager.ensureBackend(); - if (isQuitting) { - return; - } - - if (!ready) { - const shellTexts = localeService.getShellTexts( - localeService.resolveStartupLocale(), - ); - const backendLogPath = backendManager.getBackendLogPath(); - const detailLines = []; - const startupFailureReason = backendManager.getStartupFailureReason(); - if (startupFailureReason) { - detailLines.push( - `${shellTexts.startupFailReasonPrefix}: ${startupFailureReason}`, - ); - } - detailLines.push(shellTexts.startupFailAction); - if (backendLogPath) { - detailLines.push(`${shellTexts.startupFailLogPrefix}: ${backendLogPath}`); - } - - await dialog.showMessageBox({ - type: 'error', - title: shellTexts.startupFailTitle, - message: shellTexts.startupFailMessage, - detail: detailLines.join('\n'), - }); - isQuitting = true; - app.quit(); - return; - } - - try { - await loadDashboard( - mainWindow, - backendManager.getBackendUrl(), - dashboardTimeoutMs, - ); - showWindow(); - } catch (error) { - const shellTexts = localeService.getShellTexts( - localeService.resolveStartupLocale(), - ); - await dialog.showMessageBox({ - type: 'error', - title: shellTexts.dashboardFailTitle, - message: shellTexts.dashboardFailMessage, - detail: error instanceof Error ? error.message : String(error), - }); - isQuitting = true; - app.quit(); - } -} - -registerIpcHandlers(); - -app.setAppUserModelId('com.astrbot.desktop'); - -const gotLock = app.requestSingleInstanceLock(); -if (!gotLock) { - app.quit(); -} else { - app.on('second-instance', () => { - showWindow(); - }); -} - -app.on('before-quit', (event) => { - if (quitInProgress) { - event.preventDefault(); - return; - } - event.preventDefault(); - quitInProgress = true; - isQuitting = true; - logElectron('before-quit received, stopping backend.'); - - localeService - .persistLocaleFromDashboard(mainWindow, backendManager.getBackendUrl()) - .catch(() => {}) - .then(() => - backendManager.stopAnyBackend().then((result) => { - if (!result.ok) { - logElectron(`stopBackend failed: ${result.reason || 'unknown reason'}`); - } - }), - ) - .finally(async () => { - logElectron('Backend stop finished, exiting app.'); - await Promise.allSettled([ - flushElectron(), - backendManager ? backendManager.flushLogs() : Promise.resolve(), - ]); - app.exit(0); - }); -}); - -app.whenReady().then(async () => { - if (isMac && app.dock) { - const dockIcon = getAssetPath('icon.png'); - if (fs.existsSync(dockIcon)) { - app.dock.setIcon(dockIcon); - } - } - await startDesktopFlow(); -}); - -app.on('activate', () => { - if (mainWindow) { - showWindow(); - } -}); - -app.on('window-all-closed', () => { - if (!isMac) { - app.quit(); - } -}); diff --git a/desktop/package.json b/desktop/package.json deleted file mode 100644 index 2fb2349d3..000000000 --- a/desktop/package.json +++ /dev/null @@ -1,97 +0,0 @@ -{ - "name": "astrbot-desktop", - "version": "4.17.5", - "description": "AstrBot desktop wrapper", - "private": true, - "main": "main.js", - "author": "AstrBot", - "packageManager": "pnpm@10.28.2", - "pnpm": { - "onlyBuiltDependencies": [ - "electron" - ] - }, - "scripts": { - "dev": "electron .", - "start": "electron .", - "sync:version": "node scripts/sync-version.mjs", - "build:webui": "node scripts/prepare-webui.mjs", - "build:backend": "node scripts/build-backend.mjs", - "dist:full": "pnpm run build:webui && pnpm run build:backend && pnpm run dist", - "pack": "pnpm run sync:version && electron-builder --dir", - "dist": "pnpm run sync:version && electron-builder" - }, - "devDependencies": { - "electron": "^40.3.0", - "electron-builder": "^24.13.0" - }, - "build": { - "appId": "com.astrbot.desktop", - "productName": "AstrBot", - "icon": "assets/icon.png", - "extraResources": [ - { - "from": "resources/backend", - "to": "backend", - "filter": [ - "**/*", - "!**/*.map" - ] - }, - { - "from": "resources/webui", - "to": "webui", - "filter": [ - "**/*", - "!**/*.map" - ] - }, - { - "from": "assets", - "to": "assets", - "filter": [ - "**/*", - "!**/*.map" - ] - } - ], - "files": [ - "**/*", - "!**/*.map", - "!**/*.d.ts", - "!**/{test,__tests__,tests,powered-test,example,examples}/**" - ], - "compression": "maximum", - "electronLanguages": [ - "en-US", - "zh-CN" - ], - "asar": true, - "directories": { - "buildResources": "assets" - }, - "linux": { - "target": [ - "AppImage" - ], - "category": "Utility" - }, - "mac": { - "target": [ - "dmg", - "zip" - ], - "category": "public.app-category.productivity" - }, - "win": { - "target": [ - "nsis", - "zip" - ] - }, - "nsis": { - "oneClick": false, - "allowToChangeInstallationDirectory": true - } - } -} diff --git a/desktop/pnpm-lock.yaml b/desktop/pnpm-lock.yaml deleted file mode 100644 index 98411a90e..000000000 --- a/desktop/pnpm-lock.yaml +++ /dev/null @@ -1,2277 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - devDependencies: - electron: - specifier: ^40.3.0 - version: 40.3.0 - electron-builder: - specifier: ^24.13.0 - version: 24.13.3(electron-builder-squirrel-windows@24.13.3) - -packages: - - 7zip-bin@5.2.0: - resolution: {integrity: sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==} - - '@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'} - - '@isaacs/cliui@8.0.2': - resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} - engines: {node: '>=12'} - - '@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'} - - '@pkgjs/parseargs@0.11.0': - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: '>=14'} - - '@sindresorhus/is@4.6.0': - resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} - engines: {node: '>=10'} - - '@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/cacheable-request@6.0.3': - resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} - - '@types/debug@4.1.12': - resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} - - '@types/fs-extra@9.0.13': - resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} - - '@types/http-cache-semantics@4.2.0': - resolution: {integrity: sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==} - - '@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@24.10.13': - resolution: {integrity: sha512-oH72nZRfDv9lADUBSo104Aq7gPHpQZc4BTx38r9xf9pg5LfP6EzSyH2n7qFmmxRQXh7YlUXODcYsg6PuTDSxGg==} - - '@types/node@25.2.2': - resolution: {integrity: sha512-BkmoP5/FhRYek5izySdkOneRyXYN35I860MFAGupTdebyE66uZaR+bXLHq8k4DirE5DwQi3NuhvRU1jqTVwUrQ==} - - '@types/plist@3.0.5': - resolution: {integrity: sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==} - - '@types/responselike@1.0.3': - resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} - - '@types/verror@1.10.11': - resolution: {integrity: sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==} - - '@types/yauzl@2.10.3': - resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} - - '@xmldom/xmldom@0.8.11': - resolution: {integrity: sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==} - engines: {node: '>=10.0.0'} - - agent-base@6.0.2: - resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} - engines: {node: '>= 6.0.0'} - - 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==} - - 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@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==} - - assert-plus@1.0.0: - resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} - engines: {node: '>=0.8'} - - 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'} - - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - - base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - - 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==} - - 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@24.13.1: - resolution: {integrity: sha512-NhbCSIntruNDTOVI9fdXz0dihaqX2YuE1D6zZMrwiErzH4ELZHE6mdiB40wEgZNprDia+FghRFgKoAqMZRRjSA==} - - 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'} - - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - - 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-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - - 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==} - - config-file-ts@0.2.6: - resolution: {integrity: sha512-6boGVaglwblBgJqGyxm4+xCmEGcWgnWHSWHY5jad58awQhB6gftq0G8HbzU39YqCIYHMLAiL1yjwiZ36m/CL8w==} - - 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'} - - 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'} - - 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-node@2.1.0: - resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} - - dir-compare@3.3.0: - resolution: {integrity: sha512-J7/et3WlGUCxjdnD3HAAzQ6nsnc0WL6DD7WcwJb7c39iH1+AWfg+9OqzJNaI6PkBwBvm1mhZNL9iY/nRiZXlPg==} - - 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 - - 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@40.3.0: - resolution: {integrity: sha512-ZaDkTZpNHr863tyZHieoqbaiLI0e3RVCXoEC5y1Ld70/Q5H1mPV9d5TK0h1dWtaSFVOW0w8iDvtdLwAXtasXpg==} - 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==} - - 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==} - - 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'} - - 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-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - - fd-slicer@1.1.0: - resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} - - filelist@1.0.4: - resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} - - 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'} - - 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==} - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - - 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'} - - glob@10.5.0: - resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - hasBin: true - - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - - global-agent@3.0.0: - resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==} - engines: {node: '>=10.0'} - - globalthis@1.0.4: - resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} - engines: {node: '>= 0.4'} - - 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==} - - 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'} - - 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==} - - 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==} - - is-ci@3.0.1: - resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} - hasBin: true - - is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - - 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-yaml@4.1.1: - resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} - 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-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==} - - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - - 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'} - - 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.flatten@4.4.0: - resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==} - - lodash.isplainobject@4.0.6: - resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} - - lodash.union@4.6.0: - resolution: {integrity: sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==} - - lodash@4.17.23: - resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==} - - lowercase-keys@2.0.0: - resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} - engines: {node: '>=8'} - - lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - - lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} - - 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'} - - 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-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.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@1.0.4: - resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} - engines: {node: '>=10'} - hasBin: true - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - node-addon-api@1.7.2: - resolution: {integrity: sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==} - - 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'} - - 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==} - - p-cancelable@2.1.1: - resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} - engines: {node: '>=8'} - - package-json-from-dist@1.0.1: - resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - - 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-scurry@1.11.1: - resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} - engines: {node: '>=16 || 14 >=14.18'} - - pend@1.2.0: - resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - plist@3.1.0: - resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==} - engines: {node: '>=10.4.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'} - - 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'} - - quick-lru@5.1.1: - resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} - engines: {node: '>=10'} - - 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'} - - resolve-alpn@1.2.1: - resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} - - responselike@2.0.1: - resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} - - retry@0.12.0: - resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} - engines: {node: '>= 4'} - - roarr@2.15.4: - resolution: {integrity: sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==} - engines: {node: '>=8.0'} - - safe-buffer@5.1.2: - resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - - safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - - 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'} - - 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.4: - resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} - 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'} - - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - - simple-update-notifier@2.0.0: - resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} - engines: {node: '>=10'} - - 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-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'} - - sprintf-js@1.1.3: - resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} - - stat-mode@1.0.0: - resolution: {integrity: sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==} - engines: {node: '>= 6'} - - 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'} - - 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'} - - 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'} - deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - - temp-file@3.4.0: - resolution: {integrity: sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==} - - 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'} - - truncate-utf8-bytes@1.0.2: - resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==} - - type-fest@0.13.1: - resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} - engines: {node: '>=10'} - - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} - engines: {node: '>=14.17'} - hasBin: true - - undici-types@7.16.0: - resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - - universalify@0.1.2: - resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} - engines: {node: '>= 4.0.0'} - - universalify@2.0.1: - resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} - engines: {node: '>= 10.0.0'} - - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - - 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'} - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - 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@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==} - - zip-stream@4.1.1: - resolution: {integrity: sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==} - engines: {node: '>= 10'} - -snapshots: - - 7zip-bin@5.2.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 - - '@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 - - '@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.23 - tmp-promise: 3.0.3 - transitivePeerDependencies: - - supports-color - - '@pkgjs/parseargs@0.11.0': - optional: true - - '@sindresorhus/is@4.6.0': {} - - '@szmarczak/http-timer@4.0.6': - dependencies: - defer-to-connect: 2.0.1 - - '@tootallnate/once@2.0.0': {} - - '@types/cacheable-request@6.0.3': - dependencies: - '@types/http-cache-semantics': 4.2.0 - '@types/keyv': 3.1.4 - '@types/node': 25.2.2 - '@types/responselike': 1.0.3 - - '@types/debug@4.1.12': - dependencies: - '@types/ms': 2.1.0 - - '@types/fs-extra@9.0.13': - dependencies: - '@types/node': 25.2.2 - - '@types/http-cache-semantics@4.2.0': {} - - '@types/keyv@3.1.4': - dependencies: - '@types/node': 25.2.2 - - '@types/ms@2.1.0': {} - - '@types/node@24.10.13': - dependencies: - undici-types: 7.16.0 - - '@types/node@25.2.2': - dependencies: - undici-types: 7.16.0 - - '@types/plist@3.0.5': - dependencies: - '@types/node': 25.2.2 - xmlbuilder: 15.1.1 - optional: true - - '@types/responselike@1.0.3': - dependencies: - '@types/node': 25.2.2 - - '@types/verror@1.10.11': - optional: true - - '@types/yauzl@2.10.3': - dependencies: - '@types/node': 25.2.2 - optional: true - - '@xmldom/xmldom@0.8.11': {} - - agent-base@6.0.2: - dependencies: - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - 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 - - ansi-regex@5.0.1: {} - - ansi-regex@6.2.2: {} - - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - - 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.4 - 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: {} - - assert-plus@1.0.0: - optional: true - - 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: {} - - balanced-match@1.0.2: {} - - base64-js@1.5.1: {} - - 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 - - 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@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 - - 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 - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - - 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-name@1.1.4: {} - - combined-stream@1.0.8: - dependencies: - delayed-stream: 1.0.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: {} - - config-file-ts@0.2.6: - dependencies: - glob: 10.5.0 - typescript: 5.9.3 - - 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 - - debug@4.4.3: - dependencies: - ms: 2.1.3 - - decompress-response@6.0.0: - dependencies: - mimic-response: 3.1.0 - - 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-node@2.1.0: - optional: true - - dir-compare@3.3.0: - dependencies: - buffer-equal: 1.0.1 - minimatch: 3.1.2 - - 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 - - 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@40.3.0: - dependencies: - '@electron/get': 2.0.3 - '@types/node': 24.10.13 - extract-zip: 2.0.1 - transitivePeerDependencies: - - supports-color - - emoji-regex@8.0.0: {} - - emoji-regex@9.2.2: {} - - 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 - - escalade@3.2.0: {} - - escape-string-regexp@4.0.0: - optional: true - - 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-json-stable-stringify@2.1.0: {} - - fd-slicer@1.1.0: - dependencies: - pend: 1.2.0 - - filelist@1.0.4: - dependencies: - minimatch: 5.1.6 - - 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 - - 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: {} - - function-bind@1.1.2: {} - - get-caller-file@2.0.5: {} - - 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 - - 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.4 - serialize-error: 7.0.1 - optional: true - - globalthis@1.0.4: - dependencies: - define-properties: 1.2.1 - gopd: 1.2.0 - optional: true - - 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: {} - - 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 - - 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: {} - - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - - inherits@2.0.4: {} - - is-ci@3.0.1: - dependencies: - ci-info: 3.9.0 - - is-fullwidth-code-point@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-yaml@4.1.1: - dependencies: - argparse: 2.0.1 - - json-buffer@3.0.1: {} - - json-schema-traverse@0.4.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 - - keyv@4.5.4: - dependencies: - json-buffer: 3.0.1 - - lazy-val@1.0.5: {} - - lazystream@1.0.1: - dependencies: - readable-stream: 2.3.8 - - 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: {} - - lodash@4.17.23: {} - - lowercase-keys@2.0.0: {} - - lru-cache@10.4.3: {} - - lru-cache@6.0.0: - dependencies: - yallist: 4.0.0 - - matcher@3.0.0: - dependencies: - escape-string-regexp: 4.0.0 - optional: true - - math-intrinsics@1.1.0: {} - - mime-db@1.52.0: {} - - mime-types@2.1.35: - dependencies: - mime-db: 1.52.0 - - mime@2.6.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.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@1.0.4: {} - - ms@2.1.3: {} - - node-addon-api@1.7.2: - optional: true - - normalize-path@3.0.0: {} - - normalize-url@6.1.0: {} - - object-keys@1.1.1: - optional: true - - once@1.4.0: - dependencies: - wrappy: 1.0.2 - - p-cancelable@2.1.1: {} - - package-json-from-dist@1.0.1: {} - - path-is-absolute@1.0.1: {} - - path-key@3.1.1: {} - - path-scurry@1.11.1: - dependencies: - lru-cache: 10.4.3 - minipass: 7.1.2 - - pend@1.2.0: {} - - picocolors@1.1.1: {} - - plist@3.1.0: - dependencies: - '@xmldom/xmldom': 0.8.11 - base64-js: 1.5.1 - xmlbuilder: 15.1.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 - - pump@3.0.3: - dependencies: - end-of-stream: 1.4.5 - once: 1.4.0 - - punycode@2.3.1: {} - - quick-lru@5.1.1: {} - - 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: {} - - resolve-alpn@1.2.1: {} - - responselike@2.0.1: - dependencies: - lowercase-keys: 2.0.0 - - retry@0.12.0: {} - - 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 - - safe-buffer@5.1.2: {} - - safe-buffer@5.2.1: {} - - safer-buffer@2.1.2: {} - - sanitize-filename@1.6.3: - dependencies: - truncate-utf8-bytes: 1.0.2 - - sax@1.4.4: {} - - semver-compare@1.0.0: - optional: true - - semver@6.3.1: {} - - semver@7.7.4: {} - - 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: {} - - signal-exit@4.1.0: {} - - simple-update-notifier@2.0.0: - dependencies: - semver: 7.7.4 - - 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-support@0.5.21: - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - - source-map@0.6.1: {} - - sprintf-js@1.1.3: - optional: true - - stat-mode@1.0.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 - - sumchecker@3.0.1: - dependencies: - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - supports-color@7.2.0: - dependencies: - has-flag: 4.0.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 - - tmp-promise@3.0.3: - dependencies: - tmp: 0.2.5 - - tmp@0.2.5: {} - - truncate-utf8-bytes@1.0.2: - dependencies: - utf8-byte-length: 1.0.5 - - type-fest@0.13.1: - optional: true - - typescript@5.9.3: {} - - undici-types@7.16.0: {} - - universalify@0.1.2: {} - - universalify@2.0.1: {} - - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - - 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 - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - 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@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 - - zip-stream@4.1.1: - dependencies: - archiver-utils: 3.0.4 - compress-commons: 4.1.2 - readable-stream: 3.6.2 diff --git a/desktop/preload.js b/desktop/preload.js deleted file mode 100644 index 7d699a21f..000000000 --- a/desktop/preload.js +++ /dev/null @@ -1,22 +0,0 @@ -'use strict'; - -const { contextBridge, ipcRenderer } = require('electron'); - -contextBridge.exposeInMainWorld('astrbotDesktop', { - isElectron: true, - isElectronRuntime: () => ipcRenderer.invoke('astrbot-desktop:is-electron-runtime'), - getBackendState: () => ipcRenderer.invoke('astrbot-desktop:get-backend-state'), - restartBackend: (authToken) => - ipcRenderer.invoke('astrbot-desktop:restart-backend', authToken), - stopBackend: () => ipcRenderer.invoke('astrbot-desktop:stop-backend'), - onTrayRestartBackend: (callback) => { - const listener = () => { - if (typeof callback === 'function') { - callback(); - } - }; - ipcRenderer.on('astrbot-desktop:tray-restart-backend', listener); - return () => - ipcRenderer.removeListener('astrbot-desktop:tray-restart-backend', listener); - }, -}); diff --git a/desktop/scripts/build-backend.mjs b/desktop/scripts/build-backend.mjs deleted file mode 100644 index 921cf19cb..000000000 --- a/desktop/scripts/build-backend.mjs +++ /dev/null @@ -1,86 +0,0 @@ -import { spawnSync } from 'node:child_process'; -import path from 'node:path'; -import { fileURLToPath } from 'node:url'; - -const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const rootDir = path.resolve(__dirname, '..', '..'); -const outputDir = path.join(rootDir, 'desktop', 'resources', 'backend'); -const workDir = path.join(rootDir, 'desktop', 'resources', '.pyinstaller'); -const dataSeparator = process.platform === 'win32' ? ';' : ':'; -const kbStopwordsSrc = path.join( - rootDir, - 'astrbot', - 'core', - 'knowledge_base', - 'retrieval', - 'hit_stopwords.txt', -); -const kbStopwordsDest = 'astrbot/core/knowledge_base/retrieval'; -const builtinStarsSrc = path.join(rootDir, 'astrbot', 'builtin_stars'); -const builtinStarsDest = 'astrbot/builtin_stars'; - -const args = [ - 'run', - '--with', - 'pyinstaller', - 'python', - '-m', - 'PyInstaller', - '--noconfirm', - '--clean', - '--onefile', - '--name', - 'astrbot-backend', - '--collect-all', - 'aiosqlite', - '--collect-all', - 'pip', - '--collect-all', - 'bs4', - '--collect-all', - 'readability', - '--collect-all', - 'lxml', - '--collect-all', - 'lxml_html_clean', - '--collect-all', - 'rfc3987_syntax', - '--collect-submodules', - 'astrbot.api', - '--collect-submodules', - 'astrbot.builtin_stars', - '--collect-data', - 'certifi', - '--add-data', - `${builtinStarsSrc}${dataSeparator}${builtinStarsDest}`, - '--add-data', - `${kbStopwordsSrc}${dataSeparator}${kbStopwordsDest}`, - '--distpath', - outputDir, - '--workpath', - workDir, - '--specpath', - workDir, - path.join(rootDir, 'main.py'), -]; - -const result = spawnSync('uv', args, { - cwd: rootDir, - stdio: 'inherit', - shell: process.platform === 'win32', -}); - -if (result.error) { - console.error(`Failed to run 'uv': ${result.error.message}`); - process.exit(typeof result.status === 'number' ? result.status : 1); -} - -if (result.status !== 0) { - console.error( - `'uv' exited with status ${result.status} while running PyInstaller. ` + - 'Verify that uv and pyinstaller are installed and that arguments are valid.', - ); - process.exit(result.status ?? 1); -} - -process.exit(0); diff --git a/desktop/scripts/prepare-webui.mjs b/desktop/scripts/prepare-webui.mjs deleted file mode 100644 index 404ae7ef9..000000000 --- a/desktop/scripts/prepare-webui.mjs +++ /dev/null @@ -1,20 +0,0 @@ -import { cp, mkdir, rm } from 'node:fs/promises'; -import { existsSync } from 'node:fs'; -import path from 'node:path'; -import { fileURLToPath } from 'node:url'; - -const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const rootDir = path.resolve(__dirname, '..', '..'); -const distDir = path.join(rootDir, 'dashboard', 'dist'); -const targetDir = path.join(rootDir, 'desktop', 'resources', 'webui'); - -if (!existsSync(distDir)) { - console.error('dashboard/dist is missing. Run `pnpm --dir dashboard build` first.'); - process.exit(1); -} - -await rm(targetDir, { recursive: true, force: true }); -await mkdir(targetDir, { recursive: true }); -await cp(distDir, targetDir, { recursive: true }); - -console.log(`Copied WebUI to ${targetDir}`); diff --git a/desktop/scripts/sync-version.mjs b/desktop/scripts/sync-version.mjs deleted file mode 100644 index 08651d75a..000000000 --- a/desktop/scripts/sync-version.mjs +++ /dev/null @@ -1,66 +0,0 @@ -import { readFile, writeFile } from 'node:fs/promises'; -import { spawnSync } from 'node:child_process'; -import path from 'node:path'; -import { fileURLToPath } from 'node:url'; - -const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const rootDir = path.resolve(__dirname, '..', '..'); -const desktopPackagePath = path.join(rootDir, 'desktop', 'package.json'); -const pyprojectPath = path.join(rootDir, 'pyproject.toml'); - -function getGitTag() { - const result = spawnSync('git', ['describe', '--tags', '--abbrev=0'], { - cwd: rootDir, - encoding: 'utf8', - }); - if (result.status === 0) { - const tag = result.stdout.trim(); - return tag.length ? tag : null; - } - return null; -} - -function normalizeTag(tag) { - return tag.replace(/^v/i, ''); -} - -async function getPyprojectVersion() { - try { - const data = await readFile(pyprojectPath, 'utf8'); - const match = data.match(/^\s*version\s*=\s*"([^"]+)"/m); - return match ? match[1] : null; - } catch { - return null; - } -} - -const pkgRaw = await readFile(desktopPackagePath, 'utf8'); -const pkg = JSON.parse(pkgRaw); -const tag = getGitTag(); -const versionFromTag = tag ? normalizeTag(tag) : null; -const versionFromPyproject = await getPyprojectVersion(); -const version = versionFromPyproject || versionFromTag || pkg.version; - -if ( - versionFromPyproject && - versionFromTag && - versionFromPyproject !== versionFromTag -) { - console.log( - `Using pyproject version ${versionFromPyproject} (ignoring git tag ${versionFromTag}).`, - ); -} - -if (!version) { - console.warn('No version found to sync.'); - process.exit(0); -} - -if (pkg.version === version) { - console.log(`Desktop version already ${version}`); - process.exit(0); -} - -pkg.version = version; -await writeFile(desktopPackagePath, `${JSON.stringify(pkg, null, 2)}\n`, 'utf8'); -console.log(`Updated desktop version to ${version}`); diff --git a/main.py b/main.py index be188140c..36c46fca3 100644 --- a/main.py +++ b/main.py @@ -15,6 +15,7 @@ from astrbot.core.initial_loader import InitialLoader # noqa: E402 from astrbot.core.utils.astrbot_path import ( # noqa: E402 get_astrbot_config_path, get_astrbot_data_path, + get_astrbot_knowledge_base_path, get_astrbot_plugin_path, get_astrbot_root, get_astrbot_site_packages_path, @@ -55,6 +56,7 @@ def check_env() -> None: os.makedirs(get_astrbot_config_path(), exist_ok=True) os.makedirs(get_astrbot_plugin_path(), exist_ok=True) os.makedirs(get_astrbot_temp_path(), exist_ok=True) + os.makedirs(get_astrbot_knowledge_base_path(), exist_ok=True) os.makedirs(site_packages_path, exist_ok=True) # 针对问题 #181 的临时解决方案