From 62cca4f2c21e7c975d8866b43ae9162c4a0b1e4b Mon Sep 17 00:00:00 2001 From: abraxas914 Date: Fri, 21 Aug 2026 12:19:36 +0800 Subject: [PATCH 1/9] feat(desktop): introduce React Desktop 2.0 and runtime integration --- .github/workflows/desktop-release-package.yml | 13 + frontends/conductor.py | 168 +- frontends/cost_tracker.py | 249 +- frontends/desktop/.gitignore | 3 +- frontends/desktop/.npmrc | 1 + frontends/desktop/index.html | 31 + frontends/desktop/loading.html | 21 + frontends/desktop/package-lock.json | 13787 ++++++++++++++++ frontends/desktop/package.json | 68 +- .../public/assets/fonts/azonix-wordmark.woff2 | Bin 0 -> 6848 bytes .../desktop/public/assets/fonts/fonts.css | 21 + .../assets/fonts/jetbrains-mono-latin.woff2 | Bin 0 -> 31340 bytes .../public/assets/fonts/lexend-latin.woff2 | Bin 0 -> 39692 bytes .../public/assets/fonts/noto-sans-latin.woff2 | Bin 0 -> 35856 bytes frontends/desktop/public/assets/ga-logo.svg | 58 + frontends/desktop/public/fallback.html | 267 + frontends/desktop/public/i18n.js | 496 + frontends/desktop/public/phosphor-icons.js | 101 + frontends/desktop/public/styles.css | 2668 +++ frontends/desktop/public/vendor/marked.min.js | 6 + frontends/desktop/scripts/gen_ds_store.py | 68 + frontends/desktop/scripts/post-dmg.sh | 153 + frontends/desktop/src-tauri/Cargo.lock | 506 +- frontends/desktop/src-tauri/Cargo.toml | 11 +- .../src-tauri/capabilities/default.json | 8 +- .../permissions/bridge-commands.toml | 10 + frontends/desktop/src-tauri/src/lib.rs | 2405 ++- frontends/desktop/src-tauri/tauri.conf.json | 35 +- frontends/desktop/src/App.tsx | 27 + .../desktop/src/assets/channels/dingtalk.svg | 1 + .../desktop/src/assets/channels/discord.svg | 1 + .../desktop/src/assets/channels/feishu.svg | 12 + frontends/desktop/src/assets/channels/qq.svg | 1 + .../desktop/src/assets/channels/telegram.svg | 1 + .../desktop/src/assets/channels/wechat.svg | 1 + .../desktop/src/assets/channels/wecom.svg | 1 + .../src/assets/generic-agent-black.svg | 1 + .../src/assets/generic-agent-white.svg | 1 + .../desktop/src/components/chat/ChatView.tsx | 55 + .../components/chat/Composer/AtRefPopover.tsx | 110 + .../chat/Composer/AttachmentStrip.tsx | 125 + .../chat/Composer/CompletionDrawer.tsx | 90 + .../components/chat/Composer/ContextMenu.tsx | 120 + .../chat/Composer/ModelSelector.tsx | 415 + .../components/chat/Composer/PrimaryCTA.tsx | 87 + .../chat/Composer/RichEditorInput.tsx | 172 + .../components/chat/Composer/SkillPanel.tsx | 134 + .../components/chat/Composer/StatusStack.tsx | 40 + .../src/components/chat/Composer/composer.css | 1056 ++ .../src/components/chat/Composer/index.tsx | 308 + .../components/chat/Composer/rich-editor.ts | 191 + .../src/components/chat/Composer/skills.ts | 55 + .../chat/Composer/usePlaceholder.ts | 40 + .../src/components/chat/EmptyState.tsx | 45 + .../chat/Thread/AssistantActionBar.css | 37 + .../chat/Thread/AssistantActionBar.tsx | 44 + .../chat/Thread/AssistantMessage.tsx | 45 + .../components/chat/Thread/InlineError.tsx | 19 + .../components/chat/Thread/MessageList.tsx | 113 + .../chat/Thread/StreamIndicators.tsx | 68 + .../components/chat/Thread/ThreadContent.tsx | 13 + .../src/components/chat/Thread/TurnPair.tsx | 19 + .../components/chat/Thread/UserMessage.tsx | 140 + .../components/chat/Thread/UserTurnRail.css | 144 + .../components/chat/Thread/UserTurnRail.tsx | 189 + .../src/components/chat/Thread/index.tsx | 95 + .../chat/Thread/parts/ApprovalPart.tsx | 238 + .../chat/Thread/parts/CodeBlock.css | 220 + .../chat/Thread/parts/CodeBlock.tsx | 87 + .../chat/Thread/parts/DiffLines.tsx | 31 + .../chat/Thread/parts/HugeTextFallback.tsx | 45 + .../chat/Thread/parts/MarkdownPart.tsx | 100 + .../chat/Thread/parts/ResultPart.tsx | 30 + .../components/chat/Thread/parts/SafeMath.tsx | 18 + .../chat/Thread/parts/SummaryPart.tsx | 28 + .../chat/Thread/parts/ThinkingPart.tsx | 47 + .../components/chat/Thread/parts/ToolPart.tsx | 37 + .../chat/Thread/parts/approvalPart.css | 221 + .../chat/Thread/parts/diffLines.css | 83 + .../components/chat/Thread/parts/index.tsx | 60 + .../src/components/chat/Thread/thread.css | 711 + .../src/components/chat/agentProtocol.ts | 289 + .../desktop/src/components/chat/chatView.css | 17 + .../src/components/chat/emptyState.css | 108 + .../src/components/collab/CollabComposer.tsx | 51 + .../components/collab/CollabMessageList.tsx | 160 + .../src/components/collab/CollabPage.tsx | 56 + .../src/components/collab/CollabWelcome.tsx | 61 + .../src/components/collab/WorkerCard.tsx | 63 + .../src/components/collab/WorkerDrawer.tsx | 32 + .../src/components/collab/WorkerPanel.tsx | 62 + .../src/components/collab/WorkerRail.tsx | 34 + .../desktop/src/components/collab/collab.css | 762 + .../src/components/layout/AppLayout.tsx | 64 + .../src/components/layout/BridgeMenuPanel.tsx | 207 + .../components/layout/ConductorMenuPanel.tsx | 129 + .../components/layout/ConnectingOverlay.tsx | 58 + .../src/components/layout/LeftSidebar.tsx | 136 + .../src/components/layout/LiveDuration.tsx | 24 + .../src/components/layout/MainArea.tsx | 43 + .../components/layout/NotificationStack.tsx | 74 + .../src/components/layout/SessionRow.tsx | 170 + .../layout/SessionSectionHeader.tsx | 48 + .../src/components/layout/ShortcutPrompt.tsx | 34 + .../src/components/layout/Statusbar.tsx | 145 + .../components/layout/TitlebarControls.tsx | 36 + .../src/components/layout/WindowControls.tsx | 39 + .../src/components/layout/WindowsTitlebar.tsx | 23 + .../components/layout/connectingOverlay.css | 69 + .../desktop/src/components/layout/layout.css | 983 ++ .../src/components/layout/notifications.css | 104 + .../src/components/layout/windowChrome.css | 42 + .../desktop/src/components/log/LogTail.tsx | 70 + .../desktop/src/components/log/LogView.tsx | 12 + frontends/desktop/src/components/log/index.ts | 2 + frontends/desktop/src/components/log/log.css | 95 + .../src/components/services/ChannelList.tsx | 223 + .../components/services/ChannelLogModal.tsx | 60 + .../components/services/MykeyConfigModal.tsx | 77 + .../src/components/services/ServicesPage.tsx | 32 + .../src/components/services/StatusPanel.tsx | 308 + .../desktop/src/components/services/index.ts | 1 + .../src/components/services/services.css | 124 + .../src/components/settings/AddModelModal.tsx | 355 + .../src/components/settings/AddModelView.tsx | 363 + .../components/settings/AppearanceSection.tsx | 21 + .../src/components/settings/DataSection.tsx | 152 + .../components/settings/FeatureSection.tsx | 22 + .../components/settings/FontSizeSection.tsx | 24 + .../src/components/settings/GaSourceBlock.tsx | 117 + .../components/settings/LanguageSection.tsx | 21 + .../src/components/settings/ModelSection.tsx | 255 + .../src/components/settings/ProviderCard.tsx | 40 + .../src/components/settings/SettingsModal.tsx | 86 + .../src/components/settings/settings.css | 534 + .../src/components/token/ConductorTab.tsx | 65 + .../src/components/token/TokenFilter.tsx | 41 + .../src/components/token/TokenPage.tsx | 40 + .../src/components/token/TokenStats.tsx | 90 + .../src/components/token/TokenTable.tsx | 185 + .../desktop/src/components/token/index.ts | 1 + .../desktop/src/components/token/token.css | 63 + frontends/desktop/src/data/model-presets.ts | 106 + frontends/desktop/src/data/provider-icons.ts | 76 + frontends/desktop/src/global.css | 129 + .../src/hooks/useBridgeEverConnected.ts | 12 + .../desktop/src/hooks/useBridgeFailCount.ts | 10 + .../desktop/src/hooks/useBridgeStatus.ts | 15 + .../desktop/src/hooks/useEnterAnimation.ts | 28 + .../desktop/src/hooks/useSmoothReveal.ts | 78 + .../desktop/src/hooks/useStickToBottom.ts | 113 + frontends/desktop/src/hooks/useToolTimer.ts | 64 + frontends/desktop/src/i18n/en.ts | 422 + frontends/desktop/src/i18n/index.ts | 28 + frontends/desktop/src/i18n/zh.ts | 422 + frontends/desktop/src/lib/error-summary.ts | 27 + frontends/desktop/src/lib/icons.tsx | 45 + frontends/desktop/src/lib/katex-memo.ts | 118 + .../desktop/src/lib/markdown-preprocess.ts | 330 + frontends/desktop/src/lib/parse-diff.ts | 53 + frontends/desktop/src/lib/prism-setup.ts | 97 + frontends/desktop/src/lib/thread-grouping.ts | 58 + frontends/desktop/src/loading.tsx | 14 + frontends/desktop/src/loading/App.tsx | 41 + frontends/desktop/src/loading/Loading.tsx | 11 + frontends/desktop/src/loading/Progress.tsx | 33 + frontends/desktop/src/loading/Ready.tsx | 11 + frontends/desktop/src/loading/bootstrap.css | 165 + frontends/desktop/src/loading/events.ts | 78 + frontends/desktop/src/loading/i18n.ts | 34 + frontends/desktop/src/loading/store.ts | 96 + frontends/desktop/src/loading/types.ts | 45 + frontends/desktop/src/main.tsx | 71 + frontends/desktop/src/platform.ts | 20 + frontends/desktop/src/services/bridge.ts | 239 + frontends/desktop/src/services/chat.ts | 251 + frontends/desktop/src/services/constants.ts | 41 + frontends/desktop/src/services/legacy.ts | 40 + .../desktop/src/services/services-api.ts | 113 + frontends/desktop/src/services/token-api.ts | 104 + frontends/desktop/src/services/ws.ts | 122 + frontends/desktop/src/stores/app.ts | 29 + .../desktop/src/stores/bridgeActivity.ts | 61 + frontends/desktop/src/stores/chat.ts | 371 + frontends/desktop/src/stores/conductor.ts | 278 + frontends/desktop/src/stores/notifications.ts | 54 + frontends/desktop/src/stores/services.ts | 145 + frontends/desktop/src/stores/settings.ts | 143 + frontends/desktop/src/stores/token.ts | 170 + frontends/desktop/src/utils/format.ts | 11 + frontends/desktop/src/utils/tauri.ts | 9 + frontends/desktop/src/utils/toast.ts | 21 + frontends/desktop/src/vite-env.d.ts | 6 + frontends/desktop/tsconfig.json | 21 + frontends/desktop/vite.config.ts | 105 + frontends/desktop_bridge.py | 496 +- 196 files changed, 39623 insertions(+), 785 deletions(-) create mode 100644 frontends/desktop/.npmrc create mode 100644 frontends/desktop/index.html create mode 100644 frontends/desktop/loading.html create mode 100644 frontends/desktop/package-lock.json create mode 100644 frontends/desktop/public/assets/fonts/azonix-wordmark.woff2 create mode 100644 frontends/desktop/public/assets/fonts/fonts.css create mode 100644 frontends/desktop/public/assets/fonts/jetbrains-mono-latin.woff2 create mode 100644 frontends/desktop/public/assets/fonts/lexend-latin.woff2 create mode 100644 frontends/desktop/public/assets/fonts/noto-sans-latin.woff2 create mode 100644 frontends/desktop/public/assets/ga-logo.svg create mode 100644 frontends/desktop/public/fallback.html create mode 100644 frontends/desktop/public/i18n.js create mode 100644 frontends/desktop/public/phosphor-icons.js create mode 100644 frontends/desktop/public/styles.css create mode 100644 frontends/desktop/public/vendor/marked.min.js create mode 100644 frontends/desktop/scripts/gen_ds_store.py create mode 100644 frontends/desktop/scripts/post-dmg.sh create mode 100644 frontends/desktop/src/App.tsx create mode 100644 frontends/desktop/src/assets/channels/dingtalk.svg create mode 100644 frontends/desktop/src/assets/channels/discord.svg create mode 100644 frontends/desktop/src/assets/channels/feishu.svg create mode 100644 frontends/desktop/src/assets/channels/qq.svg create mode 100644 frontends/desktop/src/assets/channels/telegram.svg create mode 100644 frontends/desktop/src/assets/channels/wechat.svg create mode 100644 frontends/desktop/src/assets/channels/wecom.svg create mode 100644 frontends/desktop/src/assets/generic-agent-black.svg create mode 100644 frontends/desktop/src/assets/generic-agent-white.svg create mode 100644 frontends/desktop/src/components/chat/ChatView.tsx create mode 100644 frontends/desktop/src/components/chat/Composer/AtRefPopover.tsx create mode 100644 frontends/desktop/src/components/chat/Composer/AttachmentStrip.tsx create mode 100644 frontends/desktop/src/components/chat/Composer/CompletionDrawer.tsx create mode 100644 frontends/desktop/src/components/chat/Composer/ContextMenu.tsx create mode 100644 frontends/desktop/src/components/chat/Composer/ModelSelector.tsx create mode 100644 frontends/desktop/src/components/chat/Composer/PrimaryCTA.tsx create mode 100644 frontends/desktop/src/components/chat/Composer/RichEditorInput.tsx create mode 100644 frontends/desktop/src/components/chat/Composer/SkillPanel.tsx create mode 100644 frontends/desktop/src/components/chat/Composer/StatusStack.tsx create mode 100644 frontends/desktop/src/components/chat/Composer/composer.css create mode 100644 frontends/desktop/src/components/chat/Composer/index.tsx create mode 100644 frontends/desktop/src/components/chat/Composer/rich-editor.ts create mode 100644 frontends/desktop/src/components/chat/Composer/skills.ts create mode 100644 frontends/desktop/src/components/chat/Composer/usePlaceholder.ts create mode 100644 frontends/desktop/src/components/chat/EmptyState.tsx create mode 100644 frontends/desktop/src/components/chat/Thread/AssistantActionBar.css create mode 100644 frontends/desktop/src/components/chat/Thread/AssistantActionBar.tsx create mode 100644 frontends/desktop/src/components/chat/Thread/AssistantMessage.tsx create mode 100644 frontends/desktop/src/components/chat/Thread/InlineError.tsx create mode 100644 frontends/desktop/src/components/chat/Thread/MessageList.tsx create mode 100644 frontends/desktop/src/components/chat/Thread/StreamIndicators.tsx create mode 100644 frontends/desktop/src/components/chat/Thread/ThreadContent.tsx create mode 100644 frontends/desktop/src/components/chat/Thread/TurnPair.tsx create mode 100644 frontends/desktop/src/components/chat/Thread/UserMessage.tsx create mode 100644 frontends/desktop/src/components/chat/Thread/UserTurnRail.css create mode 100644 frontends/desktop/src/components/chat/Thread/UserTurnRail.tsx create mode 100644 frontends/desktop/src/components/chat/Thread/index.tsx create mode 100644 frontends/desktop/src/components/chat/Thread/parts/ApprovalPart.tsx create mode 100644 frontends/desktop/src/components/chat/Thread/parts/CodeBlock.css create mode 100644 frontends/desktop/src/components/chat/Thread/parts/CodeBlock.tsx create mode 100644 frontends/desktop/src/components/chat/Thread/parts/DiffLines.tsx create mode 100644 frontends/desktop/src/components/chat/Thread/parts/HugeTextFallback.tsx create mode 100644 frontends/desktop/src/components/chat/Thread/parts/MarkdownPart.tsx create mode 100644 frontends/desktop/src/components/chat/Thread/parts/ResultPart.tsx create mode 100644 frontends/desktop/src/components/chat/Thread/parts/SafeMath.tsx create mode 100644 frontends/desktop/src/components/chat/Thread/parts/SummaryPart.tsx create mode 100644 frontends/desktop/src/components/chat/Thread/parts/ThinkingPart.tsx create mode 100644 frontends/desktop/src/components/chat/Thread/parts/ToolPart.tsx create mode 100644 frontends/desktop/src/components/chat/Thread/parts/approvalPart.css create mode 100644 frontends/desktop/src/components/chat/Thread/parts/diffLines.css create mode 100644 frontends/desktop/src/components/chat/Thread/parts/index.tsx create mode 100644 frontends/desktop/src/components/chat/Thread/thread.css create mode 100644 frontends/desktop/src/components/chat/agentProtocol.ts create mode 100644 frontends/desktop/src/components/chat/chatView.css create mode 100644 frontends/desktop/src/components/chat/emptyState.css create mode 100644 frontends/desktop/src/components/collab/CollabComposer.tsx create mode 100644 frontends/desktop/src/components/collab/CollabMessageList.tsx create mode 100644 frontends/desktop/src/components/collab/CollabPage.tsx create mode 100644 frontends/desktop/src/components/collab/CollabWelcome.tsx create mode 100644 frontends/desktop/src/components/collab/WorkerCard.tsx create mode 100644 frontends/desktop/src/components/collab/WorkerDrawer.tsx create mode 100644 frontends/desktop/src/components/collab/WorkerPanel.tsx create mode 100644 frontends/desktop/src/components/collab/WorkerRail.tsx create mode 100644 frontends/desktop/src/components/collab/collab.css create mode 100644 frontends/desktop/src/components/layout/AppLayout.tsx create mode 100644 frontends/desktop/src/components/layout/BridgeMenuPanel.tsx create mode 100644 frontends/desktop/src/components/layout/ConductorMenuPanel.tsx create mode 100644 frontends/desktop/src/components/layout/ConnectingOverlay.tsx create mode 100644 frontends/desktop/src/components/layout/LeftSidebar.tsx create mode 100644 frontends/desktop/src/components/layout/LiveDuration.tsx create mode 100644 frontends/desktop/src/components/layout/MainArea.tsx create mode 100644 frontends/desktop/src/components/layout/NotificationStack.tsx create mode 100644 frontends/desktop/src/components/layout/SessionRow.tsx create mode 100644 frontends/desktop/src/components/layout/SessionSectionHeader.tsx create mode 100644 frontends/desktop/src/components/layout/ShortcutPrompt.tsx create mode 100644 frontends/desktop/src/components/layout/Statusbar.tsx create mode 100644 frontends/desktop/src/components/layout/TitlebarControls.tsx create mode 100644 frontends/desktop/src/components/layout/WindowControls.tsx create mode 100644 frontends/desktop/src/components/layout/WindowsTitlebar.tsx create mode 100644 frontends/desktop/src/components/layout/connectingOverlay.css create mode 100644 frontends/desktop/src/components/layout/layout.css create mode 100644 frontends/desktop/src/components/layout/notifications.css create mode 100644 frontends/desktop/src/components/layout/windowChrome.css create mode 100644 frontends/desktop/src/components/log/LogTail.tsx create mode 100644 frontends/desktop/src/components/log/LogView.tsx create mode 100644 frontends/desktop/src/components/log/index.ts create mode 100644 frontends/desktop/src/components/log/log.css create mode 100644 frontends/desktop/src/components/services/ChannelList.tsx create mode 100644 frontends/desktop/src/components/services/ChannelLogModal.tsx create mode 100644 frontends/desktop/src/components/services/MykeyConfigModal.tsx create mode 100644 frontends/desktop/src/components/services/ServicesPage.tsx create mode 100644 frontends/desktop/src/components/services/StatusPanel.tsx create mode 100644 frontends/desktop/src/components/services/index.ts create mode 100644 frontends/desktop/src/components/services/services.css create mode 100644 frontends/desktop/src/components/settings/AddModelModal.tsx create mode 100644 frontends/desktop/src/components/settings/AddModelView.tsx create mode 100644 frontends/desktop/src/components/settings/AppearanceSection.tsx create mode 100644 frontends/desktop/src/components/settings/DataSection.tsx create mode 100644 frontends/desktop/src/components/settings/FeatureSection.tsx create mode 100644 frontends/desktop/src/components/settings/FontSizeSection.tsx create mode 100644 frontends/desktop/src/components/settings/GaSourceBlock.tsx create mode 100644 frontends/desktop/src/components/settings/LanguageSection.tsx create mode 100644 frontends/desktop/src/components/settings/ModelSection.tsx create mode 100644 frontends/desktop/src/components/settings/ProviderCard.tsx create mode 100644 frontends/desktop/src/components/settings/SettingsModal.tsx create mode 100644 frontends/desktop/src/components/settings/settings.css create mode 100644 frontends/desktop/src/components/token/ConductorTab.tsx create mode 100644 frontends/desktop/src/components/token/TokenFilter.tsx create mode 100644 frontends/desktop/src/components/token/TokenPage.tsx create mode 100644 frontends/desktop/src/components/token/TokenStats.tsx create mode 100644 frontends/desktop/src/components/token/TokenTable.tsx create mode 100644 frontends/desktop/src/components/token/index.ts create mode 100644 frontends/desktop/src/components/token/token.css create mode 100644 frontends/desktop/src/data/model-presets.ts create mode 100644 frontends/desktop/src/data/provider-icons.ts create mode 100644 frontends/desktop/src/global.css create mode 100644 frontends/desktop/src/hooks/useBridgeEverConnected.ts create mode 100644 frontends/desktop/src/hooks/useBridgeFailCount.ts create mode 100644 frontends/desktop/src/hooks/useBridgeStatus.ts create mode 100644 frontends/desktop/src/hooks/useEnterAnimation.ts create mode 100644 frontends/desktop/src/hooks/useSmoothReveal.ts create mode 100644 frontends/desktop/src/hooks/useStickToBottom.ts create mode 100644 frontends/desktop/src/hooks/useToolTimer.ts create mode 100644 frontends/desktop/src/i18n/en.ts create mode 100644 frontends/desktop/src/i18n/index.ts create mode 100644 frontends/desktop/src/i18n/zh.ts create mode 100644 frontends/desktop/src/lib/error-summary.ts create mode 100644 frontends/desktop/src/lib/icons.tsx create mode 100644 frontends/desktop/src/lib/katex-memo.ts create mode 100644 frontends/desktop/src/lib/markdown-preprocess.ts create mode 100644 frontends/desktop/src/lib/parse-diff.ts create mode 100644 frontends/desktop/src/lib/prism-setup.ts create mode 100644 frontends/desktop/src/lib/thread-grouping.ts create mode 100644 frontends/desktop/src/loading.tsx create mode 100644 frontends/desktop/src/loading/App.tsx create mode 100644 frontends/desktop/src/loading/Loading.tsx create mode 100644 frontends/desktop/src/loading/Progress.tsx create mode 100644 frontends/desktop/src/loading/Ready.tsx create mode 100644 frontends/desktop/src/loading/bootstrap.css create mode 100644 frontends/desktop/src/loading/events.ts create mode 100644 frontends/desktop/src/loading/i18n.ts create mode 100644 frontends/desktop/src/loading/store.ts create mode 100644 frontends/desktop/src/loading/types.ts create mode 100644 frontends/desktop/src/main.tsx create mode 100644 frontends/desktop/src/platform.ts create mode 100644 frontends/desktop/src/services/bridge.ts create mode 100644 frontends/desktop/src/services/chat.ts create mode 100644 frontends/desktop/src/services/constants.ts create mode 100644 frontends/desktop/src/services/legacy.ts create mode 100644 frontends/desktop/src/services/services-api.ts create mode 100644 frontends/desktop/src/services/token-api.ts create mode 100644 frontends/desktop/src/services/ws.ts create mode 100644 frontends/desktop/src/stores/app.ts create mode 100644 frontends/desktop/src/stores/bridgeActivity.ts create mode 100644 frontends/desktop/src/stores/chat.ts create mode 100644 frontends/desktop/src/stores/conductor.ts create mode 100644 frontends/desktop/src/stores/notifications.ts create mode 100644 frontends/desktop/src/stores/services.ts create mode 100644 frontends/desktop/src/stores/settings.ts create mode 100644 frontends/desktop/src/stores/token.ts create mode 100644 frontends/desktop/src/utils/format.ts create mode 100644 frontends/desktop/src/utils/tauri.ts create mode 100644 frontends/desktop/src/utils/toast.ts create mode 100644 frontends/desktop/src/vite-env.d.ts create mode 100644 frontends/desktop/tsconfig.json create mode 100644 frontends/desktop/vite.config.ts diff --git a/.github/workflows/desktop-release-package.yml b/.github/workflows/desktop-release-package.yml index 4c320ddb1..a5270fba8 100644 --- a/.github/workflows/desktop-release-package.yml +++ b/.github/workflows/desktop-release-package.yml @@ -533,6 +533,15 @@ jobs: "requests>=2.28" "beautifulsoup4>=4.12" "bottle>=0.12" "simple-websocket-server>=0.4" "aiohttp>=3.9" psutil \ fastapi uvicorn websockets pydantic setuptools wheel + # macOS applications must be immutable at first launch. Install from the downloaded + # wheelhouse before the runtime enters the signed .app, then carry a durable marker. + "$PY" -m pip install --no-index --find-links "$RUNTIME_SRC/wheels" \ + "requests>=2.28" "beautifulsoup4>=4.12" "bottle>=0.12" "simple-websocket-server>=0.4" "aiohttp>=3.9" psutil \ + fastapi uvicorn websockets pydantic setuptools wheel + "$PY" -c 'import aiohttp, fastapi, pydantic, uvicorn, websockets' + printf 'ok\n' > "$RUNTIME_SRC/.prepared" + test -s "$RUNTIME_SRC/.prepared" + # Runtime source (project root minus heavy/dev/build dirs) — bsdtar exclude syntax. mkdir -p "$RUNTIME_SRC/app" tar \ @@ -559,6 +568,7 @@ jobs: # Portable zip: keep the existing release shape and helper scripts. ditto "$APP_SRC" "$PORTABLE/GenericAgent.app" ditto "$RUNTIME_SRC" "$PORTABLE/runtime" + test -s "$PORTABLE/runtime/.prepared" cp frontends/desktop/packaging/scripts/macos/uninstall.command "$PORTABLE/uninstall.command" chmod +x "$PORTABLE/uninstall.command" cat > "$PORTABLE/Start GenericAgent.command" <<'EOF' @@ -603,6 +613,9 @@ jobs: ditto "$APP_SRC" "$DMG_APP" mkdir -p "$DMG_APP/Contents/Resources" ditto "$RUNTIME_SRC" "$DMG_APP/Contents/Resources/runtime" + test -s "$DMG_APP/Contents/Resources/runtime/.prepared" + "$DMG_APP/Contents/Resources/runtime/python/bin/python3" \ + -c 'import aiohttp, fastapi, pydantic, uvicorn, websockets' codesign --force --deep --sign - "$DMG_APP" codesign --verify --deep --strict "$DMG_APP" || true ln -s /Applications "$DMG_STAGE/Applications" diff --git a/frontends/conductor.py b/frontends/conductor.py index 9202ce7dc..ffa6edb65 100644 --- a/frontends/conductor.py +++ b/frontends/conductor.py @@ -9,15 +9,15 @@ from pydantic import BaseModel def _resolve_ga_root() -> str: - """External core dir when launched as the bundle's conductor (design 三). - Prefer GA_ROOT env (set by the desktop bridge), else derive from own location.""" - val = (os.environ.get("GA_ROOT", "") or "").strip() - if val: - root = os.path.abspath(os.path.expanduser(val)) + """Use the external core selected by the package-owned desktop bridge when valid.""" + value = (os.environ.get("GA_ROOT", "") or "").strip() + if value: + root = os.path.abspath(os.path.expanduser(value)) if os.path.exists(os.path.join(root, "agentmain.py")): return root return os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + ROOT = _resolve_ga_root() if ROOT not in sys.path: sys.path.insert(0, ROOT) @@ -63,47 +63,109 @@ def _client_usable(agent: "GenericAgent") -> bool: return hasattr(getattr(agent, "llmclient", None), "backend") -def _fallback_usable_model(agent: "GenericAgent") -> None: - for i, client in enumerate(getattr(agent, "llmclients", []) or []): - if not hasattr(client, "backend"): - continue - agent.llm_no = i - agent.llmclient = client +def _parse_model_no(value: Any) -> Optional[int]: + if value is None or isinstance(value, bool): + return None + try: + return int(value) + except (TypeError, ValueError): + return None + + +def _usable_model(agent: "GenericAgent", no: Optional[int]) -> bool: + clients = getattr(agent, "llmclients", []) or [] + return no is not None and 0 <= no < len(clients) and hasattr(clients[no], "backend") + + +def _activate_model(agent: "GenericAgent", no: int) -> None: + if not _usable_model(agent, no): + raise ValueError(f"llm index out of range or unavailable: {no}") + agent.next_llm(no) + + +def _runtime_model_state(agent: "GenericAgent", configured: Optional[int], reason: Optional[str]) -> dict: + effective = getattr(agent, "llm_no", None) if _client_usable(agent) else None + current = None + if _client_usable(agent): with suppress(Exception): - agent.llmclient.last_tools = '' - return + current = str(agent.llmclient.backend.name) + return {"configured": configured, "effective": effective, + "fallbackReason": reason, "current": current} -def _apply_desktop_model(agent: "GenericAgent") -> None: +def _apply_desktop_model(agent: "GenericAgent") -> dict: """Make the conductor's session reflect the current desktop config before a task: switch to its bound model if one is set, otherwise still refresh sessions from mykey so live key/model edits (e.g. importing keys) take effect without a restart. next_llm() already reloads internally; the no-bound-model branch must reload too, or a conductor started on an empty/stale mykey would never pick up imported keys.""" - no = _conductor_llm_no() - if no is not None: + doc = _settings_doc() + conductor_cfg = doc.get("conductor") if isinstance(doc.get("conductor"), dict) else {} + ui_cfg = doc.get("ui") if isinstance(doc.get("ui"), dict) else {} + raw_configured = conductor_cfg.get("llmNo") + configured = _parse_model_no(raw_configured) + ui_default = _parse_model_no(ui_cfg.get("llmNo")) + + try: + agent.load_llm_sessions() # mtime-guarded; rebuilds only when mykey changed + except Exception as e: + print(f"[conductor] failed to refresh model sessions: {e}", file=sys.stderr) + + clients = getattr(agent, "llmclients", []) or [] + + configured_failed = False + if _usable_model(agent, configured): try: - agent.next_llm(int(no)) + _activate_model(agent, configured) + return _runtime_model_state(agent, configured, None) except Exception as e: - print(f"[conductor] failed to apply conductor model #{no}: {e}", file=sys.stderr) - else: - agent.load_llm_sessions() # mtime-guarded; rebuilds only when mykey changed - if not _client_usable(agent): - print("[conductor] selected model is unavailable; falling back to first usable model", file=sys.stderr) - _fallback_usable_model(agent) + configured_failed = True + print(f"[conductor] configured model #{configured} is unavailable: {e}", file=sys.stderr) + + if _usable_model(agent, ui_default): + if raw_configured is None: + reason = "ui_default" + elif configured_failed: + reason = "configured_unavailable" + elif configured is not None: + reason = "configured_unavailable" if 0 <= configured < len(clients) else "invalid_configured" + else: + reason = "invalid_configured" + try: + _activate_model(agent, ui_default) + return _runtime_model_state(agent, configured, reason) + except Exception as e: + print(f"[conductor] UI default model #{ui_default} is unavailable: {e}", file=sys.stderr) + + for i, client in enumerate(clients): + if hasattr(client, "backend"): + try: + _activate_model(agent, i) + return _runtime_model_state(agent, configured, "first_available") + except Exception: + continue + + print("[conductor] no usable model is available", file=sys.stderr) + return {"configured": configured, "effective": None, + "fallbackReason": "no_models", "current": None} def _select_llm(agent: "GenericAgent", llm: Any) -> bool: if llm is None or str(llm).strip() == "": return False q = str(llm).strip() - if isinstance(llm, int) or q.isdigit(): agent.next_llm(int(q)); return True + if isinstance(llm, int) or q.isdigit(): + agent.load_llm_sessions() + _activate_model(agent, int(q)) + return True q = q.lower(); agent.load_llm_sessions() for i, c in enumerate(agent.llmclients): + if not hasattr(c, "backend"): + continue vals = [] for fn in (lambda: agent.get_llm_name(c), lambda: agent.get_llm_name(c, model=True), lambda: c.backend.name, lambda: c.backend.model): try: vals.append(str(fn()).lower()) except Exception: pass - if any(q in v for v in vals): agent.next_llm(i); return True + if any(q in v for v in vals): _activate_model(agent, i); return True raise ValueError(f"llm not found: {llm}") @@ -362,8 +424,8 @@ def keyinfo_subagent(self, sid: str, msg: str) -> dict: GET /file?path=...\t下载文件 POST /file?name=...\t上传到temp/uploads POST /subagent/{{id}}\tbody: {{"action": "keyinfo", "msg": "..."}}\t注入key_info(agent下轮可见) -POST /subagent/{{id}}\tbody: {{"action": "input", "msg": "..."}}\t对subagent输入下一条指令;指定模型加参数llm(数字/名称) -POST /subagent/{{id}}\tbody: {{"action": "stop"}}\t中断执行但保留(可继续input) +POST /subagent/{{id}}\tbody: {{"action": "input", "msg": "..."}}\t开新一轮任务;指定模型加参数llm(数字/名称) +POST /subagent/{{id}}\tbody: {{"action": "stop"}}\t中断执行但保留(可继续input/reply) GET /chat?last=N\t返回最近N条对话(默认20) GET /subagent\t返回 {{"items": [...]}}\t查看所有subagent状态 GET /subagent/{{id}}?max_len=N\t返回单个subagent详情,reply经清洗后截取尾部max_len字(默认5000)。仅在摘要不够判断时使用 @@ -402,6 +464,24 @@ def __init__(self): self.agent: Optional[GenericAgent] = None self.started = False self.log: list = [] + self._model_lock = threading.RLock() + self._model_state = { + "configured": None, + "effective": None, + "fallbackReason": "no_models", + "current": None, + "running": False, + } + + def model_snapshot(self) -> dict: + with self._model_lock: + return dict(self._model_state) + + def _publish_model_state(self, state: dict, running: bool) -> None: + snapshot = {**state, "running": bool(running)} + with self._model_lock: + self._model_state = snapshot + schedule_broadcast({"type": "model", "model": snapshot}) def notify(self, event: dict): self.inbox.put(event) @@ -475,18 +555,25 @@ def _run(self): self.inbox.task_done() except Exception: break - kind = first.get("type"); others = [e for e in events if e.get("type") != kind]; events = [e for e in events if e.get("type") == kind] or [first] - for e in others: self.inbox.put(e) + kind = first.get("type") + other_events = [event for event in events if event.get("type") != kind] + events = [event for event in events if event.get("type") == kind] + for event in other_events: + self.inbox.put(event) try: prompt = self._build_prompt(events) - dq = self.agent.put_task(prompt, source="conductor") - self._drain(dq, events) - except Exception as e: - print(f"Conductor error: {e}") - add_chat(f"⚠ 回复失败:{e}", role="error") + model_state = self.model_snapshot() + self._publish_model_state(model_state, running=True) + try: + dq = self.agent.put_task(prompt, source="conductor") + self._drain(dq, events) + finally: + self._publish_model_state(model_state, running=False) + except Exception as e: print(f"Conductor error: {e}") def start(self): - self.agent = GenericAgent(); _apply_desktop_model(self.agent) + self.agent = GenericAgent() + self._publish_model_state(_apply_desktop_model(self.agent), running=False) threading.Thread(target=self._run, name="conductor-loop", daemon=True).start() @@ -494,9 +581,6 @@ def start(self): # ---- IM poller: 探测conductor_im_plugins/下各插件,信号变化→唤醒总管 ---- def _resolve_im_dir() -> str: - # 方案三: conductor.py itself is bundle-owned, but IM plugins are user/environment - # integrations. Prefer the external core's plugins when GA_ROOT points at one; fall back - # to the bundle templates/examples when the external core has no plugin directory. external = os.path.join(ROOT, "frontends", "conductor_im_plugins") if os.path.isdir(external): return external @@ -640,12 +724,12 @@ async def websocket(ws: WebSocket): ws_clients.add(ws) try: running = any(s.status == "running" for s in pool.subagents.values()) - await ws.send_json({"type": "hello", "subagents": pool.snapshot(), "chat": chat_messages, "log": conductor.log, "running": running, "llms": conductor.agent.list_llms(), "llm": conductor.agent.llm_no}) + await ws.send_json({"type": "hello", "subagents": pool.snapshot(), "chat": chat_messages, + "log": conductor.log, "running": running, + "model": conductor.model_snapshot(), + "llms": conductor.agent.list_llms(), "llm": conductor.agent.llm_no}) while True: data = await ws.receive_json() - if "llm" in data: - if type(n := data["llm"]) is int and 0 <= n < len(conductor.agent.list_llms()): conductor.agent.next_llm(n) - continue msg = (data.get("msg") or "").strip() if not msg: continue add_chat(msg, role="user", files=data.get("files") or [], images=data.get("images") or []) diff --git a/frontends/cost_tracker.py b/frontends/cost_tracker.py index 744258982..0471129fb 100644 --- a/frontends/cost_tracker.py +++ b/frontends/cost_tracker.py @@ -9,8 +9,9 @@ same `[Cache]` / `[Output]` print lines from `temp/*/stdout.log`. """ from __future__ import annotations -import glob, os, re, threading, time +import glob, json, os, re, threading, time from dataclasses import dataclass, field +from pathlib import Path @dataclass @@ -70,6 +71,242 @@ def current_input_chars(backend) -> int: _INSTALLED = False _SUBAGENT_GLOB = os.path.join("temp", "*", "stdout.log") +# ── Per-call ledger ────────────────────────────────────────────────────────── + +_ledger_path: Path | None = None +_ledger_fd = None +_ledger_lock = threading.RLock() +_ledger_uncompacted_bytes = 0 +_LEDGER_FILENAME = "token_ledger.jsonl" +_LEGACY_HISTORY_FILENAME = "desktop_token_history.json" +_COMPACT_THRESHOLD = 10 * 1024 * 1024 # 10MB + + +def _migrate_legacy_history_unlocked() -> None: + """Seed an empty ledger from the previous aggregate JSON format once.""" + global _ledger_uncompacted_bytes + if _ledger_path is None or _ledger_fd is None: + return + legacy_path = _ledger_path.with_name(_LEGACY_HISTORY_FILENAME) + try: + if _ledger_path.stat().st_size or not legacy_path.is_file(): + return + doc = json.loads(legacy_path.read_text(encoding="utf-8")) + if not isinstance(doc, dict) or not isinstance(doc.get("snap"), dict): + return + metadata: dict[str, dict] = {} + for entry in doc.get("history", []): + if not isinstance(entry, dict): + continue + sid = entry.get("sessionId") or entry.get("id") + if not isinstance(sid, str) or not sid: + continue + key = sid if sid.startswith("GA-") else f"GA-{sid}" + try: + ts = float(entry.get("ts", 0) or 0) + except (TypeError, ValueError): + ts = 0 + if key not in metadata or ts >= metadata[key]["ts"]: + metadata[key] = { + "ts": ts, + "model": entry.get("model") if isinstance(entry.get("model"), str) else "", + "title": entry.get("title") if isinstance(entry.get("title"), str) else "", + } + fallback_ts = legacy_path.stat().st_mtime + for key, totals in doc["snap"].items(): + if not isinstance(key, str) or not key or not isinstance(totals, dict): + continue + try: + values = { + "i": int(totals.get("input", 0) or 0), + "o": int(totals.get("output", 0) or 0), + "cc": int(totals.get("cacheCreate", totals.get("cacheWrite", 0)) or 0), + "cr": int(totals.get("cacheRead", 0) or 0), + } + except (TypeError, ValueError): + continue + meta = metadata.get(key, {}) + line = json.dumps( + {"t": meta.get("ts") or fallback_ts, "k": key, **values, + "m": meta.get("model", ""), "n": meta.get("title", ""), "_migrated": True}, + separators=(",", ":"), + ) + "\n" + _ledger_fd.write(line) + _ledger_uncompacted_bytes += len(line.encode("utf-8")) + _ledger_fd.flush() + except Exception: + return + + +def init_ledger(root: str) -> None: + """Call once at bridge startup to set the ledger file path.""" + global _ledger_path, _ledger_fd, _ledger_uncompacted_bytes + with _ledger_lock: + if _ledger_fd is not None: + try: + _ledger_fd.close() + except Exception: + pass + _ledger_path = Path(root) / "temp" / _LEDGER_FILENAME + _ledger_path.parent.mkdir(parents=True, exist_ok=True) + _ledger_fd = open(_ledger_path, "a", encoding="utf-8") + try: + _ledger_uncompacted_bytes = _ledger_path.stat().st_size + if _ledger_uncompacted_bytes == 0: + _migrate_legacy_history_unlocked() + if _ledger_uncompacted_bytes >= _COMPACT_THRESHOLD: + _compact_ledger() + except OSError: + _ledger_uncompacted_bytes = 0 + + +def _append_ledger(thread_key: str, inp: int, out: int, cc: int, cr: int) -> None: + global _ledger_uncompacted_bytes + line = json.dumps( + {"t": time.time(), "k": thread_key, "i": inp, "o": out, "cc": cc, "cr": cr}, + separators=(",", ":"), + ) + "\n" + with _ledger_lock: + if _ledger_fd is None: + return + try: + _ledger_fd.write(line) + _ledger_fd.flush() + _ledger_uncompacted_bytes += len(line.encode("utf-8")) + if _ledger_uncompacted_bytes >= _COMPACT_THRESHOLD: + _compact_ledger() + except Exception: + pass + + +def _iter_ledger_unlocked(): + if _ledger_path is None or not _ledger_path.is_file(): + return + try: + with open(_ledger_path, "r", encoding="utf-8") as f: + for line in f: + line = line.strip() + if not line: + continue + try: + entry = json.loads(line) + if isinstance(entry, dict): + yield entry + except (json.JSONDecodeError, ValueError): + continue + except OSError: + return + + +def read_ledger() -> list[dict]: + """Read all valid lines from the ledger. Skips corrupted lines.""" + with _ledger_lock: + return list(_iter_ledger_unlocked()) + + +def _aggregate_sessions(entries) -> dict[str, dict]: + sessions: dict[str, dict] = {} + for e in entries: + k = e.get("k", "") + if not isinstance(k, str) or not k: + continue + try: + ts = float(e.get("t", 0) or 0) + inp = int(e.get("i", 0) or 0) + out = int(e.get("o", 0) or 0) + cc = int(e.get("cc", 0) or 0) + cr = int(e.get("cr", 0) or 0) + except (TypeError, ValueError): + continue + if k not in sessions: + sessions[k] = {"input": 0, "output": 0, "cacheCreate": 0, "cacheRead": 0, + "model": "", "title": "", "first_ts": ts, "last_ts": ts} + s = sessions[k] + s["input"] += inp + s["output"] += out + s["cacheCreate"] += cc + s["cacheRead"] += cr + s["first_ts"] = min(s["first_ts"], ts) + s["last_ts"] = max(s["last_ts"], ts) + if isinstance(e.get("m"), str) and e["m"]: + s["model"] = e["m"] + if isinstance(e.get("n"), str) and e["n"]: + s["title"] = e["n"] + return sessions + + +def _format_aggregate(sessions: dict[str, dict]) -> dict: + history = [] + snap = {} + for k, s in sessions.items(): + sid = k.removeprefix("GA-") + history.append({ + "sessionId": sid, + "title": s["title"] or sid, + "input": s["input"], + "output": s["output"], + "cacheCreate": s["cacheCreate"], + "cacheRead": s["cacheRead"], + "model": s["model"], + "ts": s["last_ts"], + }) + snap[k] = { + "input": s["input"], + "output": s["output"], + "cacheCreate": s["cacheCreate"], + "cacheRead": s["cacheRead"], + } + return {"history": history, "snap": snap} + + +def aggregate_ledger() -> dict: + """Aggregate ledger into {history: [...], snap: {...}} for /token-history.""" + with _ledger_lock: + return _format_aggregate(_aggregate_sessions(_iter_ledger_unlocked())) + + +def _compact_ledger() -> None: + """Compact ledger by aggregating into per-session totals and rewriting.""" + if _ledger_path is None: + return + global _ledger_fd, _ledger_uncompacted_bytes + with _ledger_lock: + temp_path = _ledger_path.with_suffix(".jsonl.tmp") + try: + if _ledger_fd is not None: + _ledger_fd.flush() + sessions = _aggregate_sessions(_iter_ledger_unlocked()) + with open(temp_path, "w", encoding="utf-8") as f: + for k, s in sessions.items(): + line = json.dumps( + {"t": s["last_ts"], "k": k, "i": s["input"], "o": s["output"], + "cc": s["cacheCreate"], "cr": s["cacheRead"], "m": s["model"], + "n": s["title"], + "_compacted": True}, + separators=(",", ":"), + ) + f.write(line + "\n") + f.flush() + os.fsync(f.fileno()) + if _ledger_fd is not None: + _ledger_fd.close() + _ledger_fd = None + os.replace(temp_path, _ledger_path) + _ledger_fd = open(_ledger_path, "a", encoding="utf-8") + _ledger_uncompacted_bytes = 0 + except Exception: + try: + temp_path.unlink(missing_ok=True) + except Exception: + pass + if _ledger_fd is None: + try: + _ledger_fd = open(_ledger_path, "a", encoding="utf-8") + except Exception: + pass + + +# ── Core API ───────────────────────────────────────────────────────────────── def scan_subagent_logs(since: float = 0.0, root: str | None = None) -> TokenStats: """Aggregate subagent tokens from `temp//stdout.log` files; pass @@ -135,6 +372,7 @@ def record_patched(usage, api_mode): if usage: t = get(threading.current_thread().name) t.requests += 1 + inp = cc = cr = 0 if api_mode == 'messages': inp = int(usage.get('input_tokens', 0) or 0) cc = int(usage.get('cache_creation_input_tokens', 0) or 0) @@ -144,18 +382,24 @@ def record_patched(usage, api_mode): # output_tokens here; SSE message_start carries a 1-token # placeholder to skip. out = int(usage.get('output_tokens', 0) or 0) - if out > 1: t.output += out; t.last_output = out + if out > 1: + t.output += out; t.last_output = out + _append_ledger(threading.current_thread().name, inp, out, cc, cr) + else: + _append_ledger(threading.current_thread().name, inp, 0, cc, cr) t.last_input = inp + cc + cr elif api_mode == 'chat_completions': cached = int((usage.get('prompt_tokens_details') or {}).get('cached_tokens', 0) or 0) inp = int(usage.get('prompt_tokens', 0) or 0) - cached t.input += inp; t.cache_read += cached t.last_input = inp + cached + _append_ledger(threading.current_thread().name, inp, 0, 0, cached) elif api_mode == 'responses': cached = int((usage.get('input_tokens_details') or {}).get('cached_tokens', 0) or 0) inp = int(usage.get('input_tokens', 0) or 0) - cached t.input += inp; t.cache_read += cached t.last_input = inp + cached + _append_ledger(threading.current_thread().name, inp, 0, 0, cached) except Exception: pass return orig_record(usage, api_mode) llmcore._record_usage = record_patched @@ -168,6 +412,7 @@ def print_patched(*args, **kwargs): t = get(threading.current_thread().name) n = int(m.group(1)) t.output += n; t.last_output = n + _append_ledger(threading.current_thread().name, 0, n, 0, 0) except Exception: pass return orig_print(*args, **kwargs) llmcore.print = print_patched diff --git a/frontends/desktop/.gitignore b/frontends/desktop/.gitignore index b051b24a6..748ad2fe8 100644 --- a/frontends/desktop/.gitignore +++ b/frontends/desktop/.gitignore @@ -4,4 +4,5 @@ src-tauri/gen/ # Node node_modules/ -package-lock.json +dist/ +e2e-results/ diff --git a/frontends/desktop/.npmrc b/frontends/desktop/.npmrc new file mode 100644 index 000000000..521a9f7c0 --- /dev/null +++ b/frontends/desktop/.npmrc @@ -0,0 +1 @@ +legacy-peer-deps=true diff --git a/frontends/desktop/index.html b/frontends/desktop/index.html new file mode 100644 index 000000000..d5b5155e2 --- /dev/null +++ b/frontends/desktop/index.html @@ -0,0 +1,31 @@ + + + + + + +GenericAgent + + + +
+ + + diff --git a/frontends/desktop/loading.html b/frontends/desktop/loading.html new file mode 100644 index 000000000..97d524d31 --- /dev/null +++ b/frontends/desktop/loading.html @@ -0,0 +1,21 @@ + + + + +GenericAgent + + + +
+
+
+ + + diff --git a/frontends/desktop/package-lock.json b/frontends/desktop/package-lock.json new file mode 100644 index 000000000..3a20e4645 --- /dev/null +++ b/frontends/desktop/package-lock.json @@ -0,0 +1,13787 @@ +{ + "name": "genericagent-desktop", + "version": "0.2.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "genericagent-desktop", + "version": "0.2.0", + "dependencies": { + "@douyinfe/semi-icons": "^2.71.1", + "@douyinfe/semi-ui": "^2.71.1", + "@lobehub/icons": "^5.10.1", + "@types/prismjs": "^1.26.6", + "@vscode/codicons": "^0.0.45", + "katex": "^0.17.0", + "prismjs": "^1.30.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-markdown": "^10.1.0", + "rehype-katex": "^7.0.1", + "remark-gfm": "^4.0.1", + "remark-math": "^6.0.0", + "zustand": "^5.0.14" + }, + "devDependencies": { + "@tauri-apps/cli": "^2", + "@testing-library/dom": "^10.4.1", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.2", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "@vitejs/plugin-react": "^4.3.4", + "@wdio/cli": "^9.29.1", + "@wdio/local-runner": "^9.29.1", + "@wdio/mocha-framework": "^9.29.1", + "@wdio/spec-reporter": "^9.29.1", + "@wdio/tauri-plugin": "^1.2.0", + "@wdio/tauri-service": "^1.2.0", + "happy-dom": "^20.10.6", + "tsx": "^4.23.1", + "typescript": "^5.6.3", + "vite": "^6.0.5", + "vitest": "^4.1.9", + "webdriverio": "^9.29.1" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.5.0.tgz", + "integrity": "sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@ant-design/cssinjs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@ant-design/cssinjs/-/cssinjs-2.1.2.tgz", + "integrity": "sha512-2Hy8BnCEH31xPeSLbhhB2ctCPXE2ZnASdi+KbSeS79BNbUhL9hAEe20SkUk+BR8aKTmqb6+FKFruk7w8z0VoRQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.11.1", + "@emotion/hash": "^0.8.0", + "@emotion/unitless": "^0.7.5", + "@rc-component/util": "^1.4.0", + "clsx": "^2.1.1", + "csstype": "^3.1.3", + "stylis": "^4.3.4" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz", + "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz", + "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@dnd-kit/accessibility": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz", + "integrity": "sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@dnd-kit/core": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz", + "integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==", + "license": "MIT", + "dependencies": { + "@dnd-kit/accessibility": "^3.1.1", + "@dnd-kit/utilities": "^3.2.2", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@dnd-kit/sortable": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@dnd-kit/sortable/-/sortable-7.0.2.tgz", + "integrity": "sha512-wDkBHHf9iCi1veM834Gbk1429bd4lHX4RpAwT0y2cHLf246GAvU2sVw/oxWNpPKQNQRQaeGXhAVgrOl1IT+iyA==", + "license": "MIT", + "dependencies": { + "@dnd-kit/utilities": "^3.2.0", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@dnd-kit/core": "^6.0.7", + "react": ">=16.8.0" + } + }, + "node_modules/@dnd-kit/utilities": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@dnd-kit/utilities/-/utilities-3.2.2.tgz", + "integrity": "sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@douyinfe/semi-animation": { + "version": "2.101.0", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation/-/semi-animation-2.101.0.tgz", + "integrity": "sha512-dcESvnz0vHdxc2v0NnxCRFVedT88r250x0xPJ1x9BMnUn/PCSN9BtAUl2hktoLVyhp/+So41ThPvn/2tTAvqVA==", + "license": "MIT", + "dependencies": { + "bezier-easing": "^2.1.0" + } + }, + "node_modules/@douyinfe/semi-animation-react": { + "version": "2.101.0", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation-react/-/semi-animation-react-2.101.0.tgz", + "integrity": "sha512-TTUvFBYpeABxt2ZYFXmz908c23ZwDXuQJGZlBXxTb2yLFfFtSpXyctKzG94cxGcT0ZCliOlE3xQ2FhVT0mej0g==", + "license": "MIT", + "dependencies": { + "@douyinfe/semi-animation": "2.101.0", + "@douyinfe/semi-animation-styled": "2.101.0", + "classnames": "^2.2.6" + } + }, + "node_modules/@douyinfe/semi-animation-styled": { + "version": "2.101.0", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation-styled/-/semi-animation-styled-2.101.0.tgz", + "integrity": "sha512-FM3xOP+t2kqcHT7x7XSTkYf6sIgsd3KXfE5K2uIUxaRm42aBgRS1xP/5PT35U3IBOlP8pi9st7GZiYESHfHfYw==", + "license": "MIT" + }, + "node_modules/@douyinfe/semi-foundation": { + "version": "2.101.0", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-foundation/-/semi-foundation-2.101.0.tgz", + "integrity": "sha512-ESEH7aCX3IETSmp952Lq2f4lxApYn2uH72YJ4WUJ5YoOMxtWZCFVf85R02+zBlEP/dTED9PBl3aOazkgdH/USA==", + "license": "MIT", + "dependencies": { + "@douyinfe/semi-animation": "2.101.0", + "@douyinfe/semi-json-viewer-core": "2.101.0", + "@mdx-js/mdx": "^3.0.1", + "async-validator": "^3.5.0", + "classnames": "^2.2.6", + "date-fns": "^2.29.3", + "date-fns-tz": "^1.3.8", + "fast-copy": "^3.0.1 ", + "lodash": "^4.17.21", + "lottie-web": "^5.13.0", + "memoize-one": "^5.2.1", + "prismjs": "^1.29.0", + "remark-gfm": "^4.0.0", + "scroll-into-view-if-needed": "^2.2.24" + } + }, + "node_modules/@douyinfe/semi-icons": { + "version": "2.101.0", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-icons/-/semi-icons-2.101.0.tgz", + "integrity": "sha512-BFDALkxYbjZmFdpcTYgE031uWJnWC/s7olR8j8F21RM1W2LIVCnpGFXLAppUj+y+5xeG2wcL57MA9AxBvPa0aw==", + "license": "MIT", + "dependencies": { + "classnames": "^2.2.6" + }, + "peerDependencies": { + "react": ">=16.0.0" + } + }, + "node_modules/@douyinfe/semi-illustrations": { + "version": "2.101.0", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-illustrations/-/semi-illustrations-2.101.0.tgz", + "integrity": "sha512-iVFqwaftoMRpnAeeYoAOD7+06plRLW4HqyufVPpTwPBkdalANoX5NtdGPwc4w9E4+O+pu8vMp1snojhVrxYIMw==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.0.0" + } + }, + "node_modules/@douyinfe/semi-json-viewer-core": { + "version": "2.101.0", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-json-viewer-core/-/semi-json-viewer-core-2.101.0.tgz", + "integrity": "sha512-0Jp4/3Go0kQnlYIi+NzM3Dh1/YJjMjXGPQV9WfjlZXAE47FIM+KTNWL8wyGQz5x91HKV0ZABd7pGw76abODT3g==", + "license": "MIT", + "dependencies": { + "jsonc-parser": "^3.3.1" + } + }, + "node_modules/@douyinfe/semi-theme-default": { + "version": "2.101.0", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-theme-default/-/semi-theme-default-2.101.0.tgz", + "integrity": "sha512-TZHhGapKNtd06eGb+RDpntmTo1iKsh/2KQgH4YDzrEnuCs59EGEj4Uh+RkhlMLGWkxR/qrP6weMnl8K3k/E69g==", + "license": "MIT" + }, + "node_modules/@douyinfe/semi-ui": { + "version": "2.101.0", + "resolved": "https://registry.npmjs.org/@douyinfe/semi-ui/-/semi-ui-2.101.0.tgz", + "integrity": "sha512-oTIE9Hrc++8zv4MSanbkMlFpqoQeT/Gn7fPv+B1b1HJZIO0Dzj7pAimv2BBoZ4mB8QcsJ2BXFALg/Lp3ienbqA==", + "license": "MIT", + "dependencies": { + "@dnd-kit/core": "^6.0.8", + "@dnd-kit/sortable": "^7.0.2", + "@dnd-kit/utilities": "^3.2.1", + "@douyinfe/semi-animation": "2.101.0", + "@douyinfe/semi-animation-react": "2.101.0", + "@douyinfe/semi-foundation": "2.101.0", + "@douyinfe/semi-icons": "2.101.0", + "@douyinfe/semi-illustrations": "2.101.0", + "@douyinfe/semi-theme-default": "2.101.0", + "@tiptap/core": "^3.10.7", + "@tiptap/extension-document": "^3.10.7", + "@tiptap/extension-hard-break": "^3.10.7", + "@tiptap/extension-image": "^3.10.7", + "@tiptap/extension-mention": "^3.10.7", + "@tiptap/extension-paragraph": "^3.10.7", + "@tiptap/extension-text": "^3.10.7", + "@tiptap/extension-text-align": "^3.10.7", + "@tiptap/extension-text-style": "^3.10.7", + "@tiptap/extensions": "^3.10.7", + "@tiptap/pm": "^3.10.7", + "@tiptap/react": "^3.10.7", + "@tiptap/starter-kit": "^3.10.7", + "async-validator": "^3.5.0", + "classnames": "^2.2.6", + "copy-text-to-clipboard": "^2.1.1", + "date-fns": "^2.29.3", + "date-fns-tz": "^1.3.8", + "fast-copy": "^3.0.1 ", + "jsonc-parser": "^3.3.1", + "lodash": "^4.17.21", + "prop-types": "^15.7.2", + "prosemirror-state": "^1.4.3", + "react-resizable": "^3.0.5", + "react-window": "^1.8.2", + "scroll-into-view-if-needed": "^2.2.24", + "utility-types": "^3.10.0" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.3.3", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", + "license": "MIT" + }, + "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "license": "MIT" + }, + "node_modules/@emotion/babel-plugin/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", + "license": "MIT" + }, + "node_modules/@emotion/cache": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", + "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/cache/node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", + "license": "MIT" + }, + "node_modules/@emotion/css": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/css/-/css-11.13.5.tgz", + "integrity": "sha512-wQdD0Xhkn3Qy2VNcIzbLP9MR8TafI0MJb7BEAXKp+w4+XqErksWR4OXomuDzPsN4InLdGhVe6EYcn2ZIUCpB8w==", + "license": "MIT", + "dependencies": { + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.13.5", + "@emotion/serialize": "^1.3.3", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2" + } + }, + "node_modules/@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==", + "license": "MIT" + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, + "node_modules/@emotion/react": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", + "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", + "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", + "license": "MIT", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.2", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/serialize/node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", + "license": "MIT" + }, + "node_modules/@emotion/serialize/node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", + "license": "MIT" + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", + "license": "MIT" + }, + "node_modules/@emotion/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==", + "license": "MIT" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", + "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", + "license": "MIT" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", + "license": "MIT" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz", + "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.8.0.tgz", + "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@floating-ui/core": "^1.8.0", + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.12.tgz", + "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==", + "license": "MIT", + "optional": true + }, + "node_modules/@inquirer/ansi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz", + "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/checkbox": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz", + "integrity": "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/confirm": { + "version": "5.1.21", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz", + "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core": { + "version": "10.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz", + "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/editor": { + "version": "4.2.23", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz", + "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/external-editor": "^1.0.3", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/expand": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz", + "integrity": "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/external-editor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", + "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^2.1.1", + "iconv-lite": "^0.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/figures": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz", + "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/input": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz", + "integrity": "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/number": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz", + "integrity": "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/password": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz", + "integrity": "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/prompts": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.10.1.tgz", + "integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/checkbox": "^4.3.2", + "@inquirer/confirm": "^5.1.21", + "@inquirer/editor": "^4.2.23", + "@inquirer/expand": "^4.0.23", + "@inquirer/input": "^4.3.1", + "@inquirer/number": "^3.0.23", + "@inquirer/password": "^4.0.23", + "@inquirer/rawlist": "^4.1.11", + "@inquirer/search": "^3.2.2", + "@inquirer/select": "^4.4.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/rawlist": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.11.tgz", + "integrity": "sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/search": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.2.tgz", + "integrity": "sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/select": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.2.tgz", + "integrity": "sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/type": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz", + "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@jest/diff-sequences": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.4.0.tgz", + "integrity": "sha512-zOpzlfUs45l6u7jm39qr87JCHUDsaeCtvL+kQe/Vn9jSnRB4/5IPXISm0h9I1vZW/o00Kn4UTJ2MOlhnUGwv3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.4.1.tgz", + "integrity": "sha512-ZBn5CglH8fBsQsvs4VWNzD4aWfUYks+IdOOQU3MEK71ol/BcVm+P+rtb1KpiFBpSWSCE27uOahyyf1vfqOVbcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/pattern": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.4.0.tgz", + "integrity": "sha512-RAWn3+f9u8BsHijKJ71uHcFp6vmyEt6VvoWXkl6hKF3qVIuWNmudVjg12DlBPGup/frIl5UcUlH5HfEuvHpEXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-regex-util": "30.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/schemas": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.4.1.tgz", + "integrity": "sha512-i6b4qw5qnP8c5FEeBJg/uZQ4ddrkN6Ca8qISJh0pr7a5hfn3h3v5x60BEbOC7OYAGZNMs1LfFLwnW2CuK8F57Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/types": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.4.1.tgz", + "integrity": "sha512-f1x/vJXIfjOlEmejYpbkbgw1gOqpPECwMvMEtBqe47j7H2Hg8h8w3o3ikhSXq3MI15kg+oQ0exWO0uCtTNJLoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/pattern": "30.4.0", + "@jest/schemas": "30.4.1", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/types/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@lobehub/icons": { + "version": "5.13.0", + "resolved": "https://registry.npmjs.org/@lobehub/icons/-/icons-5.13.0.tgz", + "integrity": "sha512-iXQF8GFvlwNJMR+PaU3jCgVAn5B8F7P48Fm6aodSXP+b+HJiR266rvlMSYvCULRAB/6/rtS1WZH3npc3p3viFw==", + "license": "MIT", + "workspaces": [ + "packages/*" + ], + "dependencies": { + "antd-style": "^4.1.0", + "es-toolkit": "^1.49.0", + "lucide-react": "^0.469.0", + "polished": "^4.3.1" + }, + "peerDependencies": { + "@lobehub/ui": "^5.0.0", + "antd": "^6.1.1", + "react": "^19.0.0", + "react-dom": "^19.0.0" + } + }, + "node_modules/@mdx-js/mdx": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.1.1.tgz", + "integrity": "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdx": "^2.0.0", + "acorn": "^8.0.0", + "collapse-white-space": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-util-scope": "^1.0.0", + "estree-walker": "^3.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "markdown-extensions": "^2.0.0", + "recma-build-jsx": "^1.0.0", + "recma-jsx": "^1.0.0", + "recma-stringify": "^1.0.0", + "rehype-recma": "^1.0.0", + "remark-mdx": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "source-map": "^0.7.0", + "unified": "^11.0.0", + "unist-util-position-from-estree": "^2.0.0", + "unist-util-stringify-position": "^4.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@nodable/entities": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-3.0.0.tgz", + "integrity": "sha512-8L9xFeTYKhm49xfIypoe2W5wV1m/3Z58kT+7kR9A8OyFxcPduI4VmxaUMQyKYrRjUoLLSXv6EKKID5Tvj9cUVw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/nodable" + } + ], + "license": "MIT" + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@promptbook/utils": { + "version": "0.69.5", + "resolved": "https://registry.npmjs.org/@promptbook/utils/-/utils-0.69.5.tgz", + "integrity": "sha512-xm5Ti/Hp3o4xHrsK9Yy3MS6KbDxYbq485hDsFvxqaNA7equHLPdo8H8faTitTeb14QCDfLW4iwCxdVYu5sn6YQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://buymeacoffee.com/hejny" + }, + { + "type": "github", + "url": "https://github.com/webgptorg/promptbook/blob/main/README.md#%EF%B8%8F-contributing" + } + ], + "license": "CC-BY-4.0", + "dependencies": { + "spacetrim": "0.11.59" + } + }, + "node_modules/@puppeteer/browsers": { + "version": "2.13.2", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.13.2.tgz", + "integrity": "sha512-5EUZSUIc37H6aIXyWO0Z4y8NlF8NnjgmqeQgOGiswAU7pY0HOo16ho4+alIWmSfdZnjqBRawMsP3I5YqLSn6kw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.4.3", + "extract-zip": "^2.0.1", + "progress": "^2.0.3", + "proxy-agent": "^6.5.0", + "semver": "^7.7.4", + "tar-fs": "^3.1.1", + "yargs": "^17.7.2" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@puppeteer/browsers/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@rc-component/util": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@rc-component/util/-/util-1.12.0.tgz", + "integrity": "sha512-AEjPL8JVdohIITaiXokyjL9WQ6tKWWjAYK9QU16tGNE9JaQABBQy+hA4H2Lup5MgXy9yY3iLrbZJheuU13hTdQ==", + "license": "MIT", + "dependencies": { + "is-mobile": "^5.0.0", + "react-is": "^19.2.7" + }, + "peerDependencies": { + "react": ">=18.0.0", + "react-dom": ">=18.0.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz", + "integrity": "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.2.tgz", + "integrity": "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.2.tgz", + "integrity": "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.2.tgz", + "integrity": "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.2.tgz", + "integrity": "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.2.tgz", + "integrity": "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.2.tgz", + "integrity": "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.2.tgz", + "integrity": "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.2.tgz", + "integrity": "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.2.tgz", + "integrity": "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.2.tgz", + "integrity": "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.2.tgz", + "integrity": "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.2.tgz", + "integrity": "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.2.tgz", + "integrity": "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.2.tgz", + "integrity": "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.2.tgz", + "integrity": "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.2.tgz", + "integrity": "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz", + "integrity": "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.2.tgz", + "integrity": "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.2.tgz", + "integrity": "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.2.tgz", + "integrity": "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.2.tgz", + "integrity": "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.2.tgz", + "integrity": "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.2.tgz", + "integrity": "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz", + "integrity": "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sec-ant/readable-stream": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", + "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinclair/typebox": { + "version": "0.34.52", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.52.tgz", + "integrity": "sha512-XiMQh7qqVlxZzcVD+kkGMNGMzcTrDMLWI7S4x7z1MkCkbDPrekpZXEUK0eZqZFMuHQg2a2DZOcDIh9o5v3Gonw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tauri-apps/api": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.11.0.tgz", + "integrity": "sha512-7CinYODhky9lmO23xHnUFv0Xt43fbtWMyxZcLcRBlFkcgXKuEirBvHpmtJ89YMhyeGcq20Wuc47Fa4XjyniywA==", + "dev": true, + "license": "Apache-2.0 OR MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/tauri" + } + }, + "node_modules/@tauri-apps/cli": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.11.4.tgz", + "integrity": "sha512-R8xGtMpwyetawSqm9kYOuMmEqkhUbvcUy8n0aNXIxollKBLESUu5f4Fx+64hgASYm1H+jSWq6jCW6zqTnH6hqQ==", + "dev": true, + "license": "Apache-2.0 OR MIT", + "bin": { + "tauri": "tauri.js" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/tauri" + }, + "optionalDependencies": { + "@tauri-apps/cli-darwin-arm64": "2.11.4", + "@tauri-apps/cli-darwin-x64": "2.11.4", + "@tauri-apps/cli-linux-arm-gnueabihf": "2.11.4", + "@tauri-apps/cli-linux-arm64-gnu": "2.11.4", + "@tauri-apps/cli-linux-arm64-musl": "2.11.4", + "@tauri-apps/cli-linux-riscv64-gnu": "2.11.4", + "@tauri-apps/cli-linux-x64-gnu": "2.11.4", + "@tauri-apps/cli-linux-x64-musl": "2.11.4", + "@tauri-apps/cli-win32-arm64-msvc": "2.11.4", + "@tauri-apps/cli-win32-ia32-msvc": "2.11.4", + "@tauri-apps/cli-win32-x64-msvc": "2.11.4" + } + }, + "node_modules/@tauri-apps/cli-darwin-arm64": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.11.4.tgz", + "integrity": "sha512-1ryOF3ZhpZ/nemHV5zVwBQBz9jDGKmKPvWPADOhc83ig0P4bMc2iER4NbC6r9sjeIZ6RVQ4g3RZIYvezhcl4TQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-darwin-x64": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.11.4.tgz", + "integrity": "sha512-uFsGQAAfuyz1k/yGLmkWfkBlgKAqZfxqlHmLWx81QU27RJWfmbNHCIq8T8w1e+VClleIuZUjpHWfoE4E3DLo3A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.11.4.tgz", + "integrity": "sha512-IaHZn5CdBL21oUmjiVOS1ctw6Ip1O0pjp70FwOWmYz1myWe0SY96ZIj2FYf7pT0m8bI2h/hrs5ZbEXXh44/MkQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-gnu": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.11.4.tgz", + "integrity": "sha512-N41/ukTRVe6XSuUTESuFdGeOW2i7k62tK+6gHK5Kd5/q5RPvvi19GaWAVPPb9u95HSGmTChSolBfzynUsssFaA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-musl": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.11.4.tgz", + "integrity": "sha512-v277UnT/fB64xAfSroL5N3Km3tLmvATWqJJw/wRI+g6o+HkeD0slyE7gOhNs1MbjE41R7bQOTxMVoL3aomUJmw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-riscv64-gnu": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.11.4.tgz", + "integrity": "sha512-qqgNkQ2u1yZHxjhxsZaxUtRDW8dIqIYm33rx/mzwQv0SfY9x1B+iraj8vWeFiXjjSVVhEMepXSOts1TqPzvXNQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-gnu": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.11.4.tgz", + "integrity": "sha512-2VRNWl84FOH0m2giiDkO2h0QXlcMJeX+zJDpI5kDIQAx6s+geF3v48F4DXfJez4GS/FdoDGnPnw1C2iYGbQ7bQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-musl": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.11.4.tgz", + "integrity": "sha512-o9GyhYor/nc7xarmwDE3ka2szuW3uuZzXjHWh64Q8YX5AtSgxdQkFWzrY4O8KiGtVNvFBI14H3Q49Qj5TOIP/A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-arm64-msvc": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.11.4.tgz", + "integrity": "sha512-ld5Ehb598m0VkYyylRPNeCFsBe/km0jxis6KgMpl3IGY6I/i1RwQXO05I1AsXUXO2WC6AvB/Lw4qTf/asiuEiQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-ia32-msvc": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.11.4.tgz", + "integrity": "sha512-12Hxi0XX/H5VFxO/bGgHkFWhml9VMgEOu9CidjeCeTNQ1l6fpUlbiGgSP7CLI3PFtW9/FfbeHieZ+kyWK5H7CA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-x64-msvc": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.11.4.tgz", + "integrity": "sha512-+vDiqBIU5dMISg/wNvX3sF+ZHfgJGJ5T0AcO+EHNXV9GGAG+P5fzodlDXD3QdKCRgZxMoCm5PPvj3BqLNjBthw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/plugin-log": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-log/-/plugin-log-2.8.0.tgz", + "integrity": "sha512-a+7rOq3MJwpTOLLKbL8d0qGZ85hgHw5pNOWusA9o3cf7cEgtYHiGY/+O8fj8MvywQIGqFv0da2bYQDlrqLE7rw==", + "dev": true, + "license": "MIT OR Apache-2.0", + "dependencies": { + "@tauri-apps/api": "^2.8.0" + } + }, + "node_modules/@testing-library/dom": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", + "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", + "integrity": "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "picocolors": "^1.1.1", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/react": { + "version": "16.3.2", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.2.tgz", + "integrity": "sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0 || ^19.0.0", + "@types/react-dom": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@tiptap/core": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.28.0.tgz", + "integrity": "sha512-gUuD5WAYfbDxNSSJya/emh2KSzXZXLUYKW4fEnc1AQ5FE2twzh4LJ9UlKFIawigrUCAksWI5Fy1hRbv+5m4ZdQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/pm": "3.28.0" + } + }, + "node_modules/@tiptap/extension-blockquote": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-3.28.0.tgz", + "integrity": "sha512-y8Xi6Z3AQLXedz0J8Z3kDsu7SKBmL50gKVXx3RK1Oo1cuCGhNChm3syChkAz3PLAbrPUM5rvJDSZdF2jUrDnng==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.28.0", + "@tiptap/pm": "3.28.0" + } + }, + "node_modules/@tiptap/extension-bold": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-3.28.0.tgz", + "integrity": "sha512-JhZQmr0AU741bOwjVMfuwJdK4g0TQwwPbeca9aqKHv5zvZw4i4G9G6fESVyMFc3Yag1ffpnq5EtNldHKTnMhlw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.28.0" + } + }, + "node_modules/@tiptap/extension-bubble-menu": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.28.0.tgz", + "integrity": "sha512-7AUNoHj2K4XLKCgW4uspeD/ENejPu2BeHvLTsiOoIO+XXDNSi2j0bbaIS8f2s/qnFirscwp/sbznp1qph/76qg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.28.0", + "@tiptap/pm": "3.28.0" + } + }, + "node_modules/@tiptap/extension-bullet-list": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-3.28.0.tgz", + "integrity": "sha512-dSVuNiH7PFMmWGkNER9vfUb5bXUHDARvHbJ3l+APEb+ZiusVN1KFdM3nd/RsW/Rt5Gd3XwlIEU/c2Uf7cxYDcw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "3.28.0" + } + }, + "node_modules/@tiptap/extension-code": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-3.28.0.tgz", + "integrity": "sha512-AUw2Acof3CQE6Q6Y22saK4lyg0nkeJ4XXniU65TdAi/9TE66TGiO4NQJJNNPgu8+VMEwl5j8VsIFK8sfTcNYtg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.28.0" + } + }, + "node_modules/@tiptap/extension-code-block": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-3.28.0.tgz", + "integrity": "sha512-bHITDzT0umTLh+SiEVQzIXkCMt/TzbPM1+HQy9ZxgQDHAJj/vdmfNAnP3RCOrz4lETXyhNQ2b6kxeu3lWckxyA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.28.0", + "@tiptap/pm": "3.28.0" + } + }, + "node_modules/@tiptap/extension-document": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-3.28.0.tgz", + "integrity": "sha512-5SAKtlB1Tr/eZFhISL86HqmUup6rItvPtuPyRjmZo/VgbMwXEwiyAh1sMgFp5VNaeSMM14vJSyQpjhSaOmaBqg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.28.0" + } + }, + "node_modules/@tiptap/extension-dropcursor": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-3.28.0.tgz", + "integrity": "sha512-JA+dXQjjfJBpD0nVsZeddGVXRsmanESM9+8CtM35hI9wJnYMXay/B+5GUhswO20zhT3zhB2ZOTGe9knu6A8nIQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extensions": "3.28.0" + } + }, + "node_modules/@tiptap/extension-floating-menu": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-3.28.0.tgz", + "integrity": "sha512-59SECvJq3pQfeJBuydEdhQqrpl0oDlk8N1Ovs1Si3/fJa6rEQAJB2zIvcpBHky9Z+5JodI2eueDnv8eimiyGbg==", + "license": "MIT", + "optional": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@floating-ui/dom": "^1.0.0", + "@tiptap/core": "3.28.0", + "@tiptap/pm": "3.28.0" + } + }, + "node_modules/@tiptap/extension-gapcursor": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-3.28.0.tgz", + "integrity": "sha512-Wo73kM4q8z4Va9i4+0n1cO0UEMVUVBHPqM6cAqEYXjB4T48LQkKjRsiQydCezm185rQAsmm1dyi72gtvVQfdMg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extensions": "3.28.0" + } + }, + "node_modules/@tiptap/extension-hard-break": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-3.28.0.tgz", + "integrity": "sha512-JHIFjX1luJgQ4VFEkIeXZpbc54Qiw+69P8FmlazYTh7AIJ6iLCpMFgQFELnivEAZ+/vS0lMPQubg0rCeM3UrHw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.28.0" + } + }, + "node_modules/@tiptap/extension-heading": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-3.28.0.tgz", + "integrity": "sha512-rKjGG/Ik2lNaXBNVmONEDm5DBfGDLM1NWgSf5RRfBISrH8Lm1xqFruOB9tIaB0YUoSV3SBOiwTF9svmzvKSoRA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.28.0" + } + }, + "node_modules/@tiptap/extension-horizontal-rule": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.28.0.tgz", + "integrity": "sha512-neBCMWprkppQUoLWyeJZDHqBw+xKX2oNhLD9MbFlhKIr092zgfP4mpCvQnSkn1OHl156KzZMp070+NyLBjgQ7A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.28.0", + "@tiptap/pm": "3.28.0" + } + }, + "node_modules/@tiptap/extension-image": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-image/-/extension-image-3.28.0.tgz", + "integrity": "sha512-aKGCdEjyujUcQ6tEtq4EPbKxEC16QsKapv3DeZs1c/UHFiEUalbbPHBnxjGnupiLz75IR+07GYqBoZ81kSCxiA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.28.0" + } + }, + "node_modules/@tiptap/extension-italic": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-3.28.0.tgz", + "integrity": "sha512-Yur/ELz6dNVKQC7m8wGjtoLFxamGjJmA0rUEEOacTH6J39aFmcSxYkEGNDkYHbZFyHFYqbej6eI3VE0h08O0mg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.28.0" + } + }, + "node_modules/@tiptap/extension-link": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-3.28.0.tgz", + "integrity": "sha512-hy/PqSeTyl317yseFcHGE+3XVfQKQYaL4uZuj27xlrcO7MZ15drt1h9sUZy1FTBF3mr8676pQu7aoEm/Ww4ZRA==", + "license": "MIT", + "dependencies": { + "linkifyjs": "^4.3.3" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.28.0", + "@tiptap/pm": "3.28.0" + } + }, + "node_modules/@tiptap/extension-list": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.28.0.tgz", + "integrity": "sha512-zQ66i5DuhVOndmZ0d7H475Y5Yb+BMx+zfCjFkCzEc6WVef5MumtxBVTkGLQ0ibxUaD71s4QQZbjHWagpaTg0eQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.28.0", + "@tiptap/pm": "3.28.0" + } + }, + "node_modules/@tiptap/extension-list-item": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-3.28.0.tgz", + "integrity": "sha512-GbXrnMac6knSetZY33NHwOrgXFPqH28uCklQqmOZQlsrdGqezDKk31qoEMr4GsKW9n/lViAeuc07oIzwLwCMng==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "3.28.0" + } + }, + "node_modules/@tiptap/extension-list-keymap": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list-keymap/-/extension-list-keymap-3.28.0.tgz", + "integrity": "sha512-u9Wks8c/eQAv0RkULNggOyTKDD69WVbcV9H5cbasPDUbq5XbEFVa9ajxhEGfMmQ5et3EX0QL8qBi50K0GqbIjA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "3.28.0" + } + }, + "node_modules/@tiptap/extension-mention": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-mention/-/extension-mention-3.28.0.tgz", + "integrity": "sha512-Y3TJOTLpTCLmUJuKGA5K8Rxl5GpgwVd7atda0yCmKKYO0czTL4afN5tNIUSWoBqj0nBQdi4DU+Xnl+s+EfM/4g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.28.0", + "@tiptap/pm": "3.28.0", + "@tiptap/suggestion": "3.28.0" + } + }, + "node_modules/@tiptap/extension-ordered-list": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-3.28.0.tgz", + "integrity": "sha512-OZNYrKKL9D01ySOujlNbKlLS9/3wGgKNYeoHZUg0e+Ta8WPVvL3W1zH6TgiU5sF2ZSGUBoq3w7mdaO/iROlUkw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "3.28.0" + } + }, + "node_modules/@tiptap/extension-paragraph": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-3.28.0.tgz", + "integrity": "sha512-8UMlQIjzqf6r2hSJ/VeJ00RqaOrOB1J5rTk02Vcw2pYeHkOqp+B0ff0HFu4abT9x1q4oXrBAgMsxRtgh/kR14Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.28.0" + } + }, + "node_modules/@tiptap/extension-strike": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-3.28.0.tgz", + "integrity": "sha512-VVj2ZZU9QYqiHLcjqMqRYvuHSsokj/AgUl+6TzLrKjlWwyZ18D4H2vkyI0g70iVTKnUpZ3sEy8WA/rqjgBjqBg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.28.0" + } + }, + "node_modules/@tiptap/extension-text": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-3.28.0.tgz", + "integrity": "sha512-Jqp1LgfY1mnp4TQHoy+vnHyfn6qnnAM6nHgGwbY5zA8b/Xf1Etll6pziTx9p1J1qcfAgSrnjOyAmA++H7VQqww==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.28.0" + } + }, + "node_modules/@tiptap/extension-text-align": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text-align/-/extension-text-align-3.28.0.tgz", + "integrity": "sha512-P+KQMTtCpLFq9dRvy/fbyu2BGALulT/1HtsLbpFG4tKATaKa+cFnJ7rLZF7b3AdAMDNtXdnivxAtixAMBt2QWw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.28.0" + } + }, + "node_modules/@tiptap/extension-text-style": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text-style/-/extension-text-style-3.28.0.tgz", + "integrity": "sha512-UreMyqZSv770+CXJK/l1qeHUdaNMQAVkxSOPWpiY9FiT8B4OQyjA7WBOlWrzbvVTzfJvXWk2Y3SWgVRx+/Cd9A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.28.0" + } + }, + "node_modules/@tiptap/extension-underline": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-3.28.0.tgz", + "integrity": "sha512-rwxCS6vTh2DJkNIYQX7JSrrRSmm76e2y48aZeuZO5ShkvLWMuJ3/zqDHRxAQVDiJhuE2Cp8NrTmPYlUc9YrT0A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.28.0" + } + }, + "node_modules/@tiptap/extensions": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/extensions/-/extensions-3.28.0.tgz", + "integrity": "sha512-DJT1khCK+O/pT1gQlAnoKAx6zwDkgv7GtnhSfkqm1/4KHC3x+SSJnBIgBl9oGHymA+DxWbW1EULU4V3d/kT2uQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.28.0", + "@tiptap/pm": "3.28.0" + } + }, + "node_modules/@tiptap/pm": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.28.0.tgz", + "integrity": "sha512-ALcpwZMUdat9gjJKlpscpoqXStoLhU246LPEVBDvJdIsoUKvUu3MrzfXik2Y8mtSGfhjtm9O2TRkWxQiFVMwsQ==", + "license": "MIT", + "dependencies": { + "prosemirror-changeset": "^2.4.1", + "prosemirror-commands": "^1.7.1", + "prosemirror-dropcursor": "^1.8.2", + "prosemirror-gapcursor": "^1.4.1", + "prosemirror-history": "^1.5.0", + "prosemirror-inputrules": "^1.5.1", + "prosemirror-keymap": "^1.2.3", + "prosemirror-model": "^1.25.9", + "prosemirror-schema-list": "^1.5.1", + "prosemirror-state": "^1.4.4", + "prosemirror-tables": "^1.8.5", + "prosemirror-transform": "^1.12.0", + "prosemirror-view": "^1.41.9" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + } + }, + "node_modules/@tiptap/react": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/react/-/react-3.28.0.tgz", + "integrity": "sha512-BxzSAqaDEldQ97K/v6+GizU1/Dxx9VWkRh7PLQql6bXlAMiz6T1G3dGt25vvv1hQ1FoMt5ExWY5NkrPmR8G8ew==", + "license": "MIT", + "dependencies": { + "@types/use-sync-external-store": "^0.0.6", + "fast-equals": "^5.3.3", + "use-sync-external-store": "^1.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "optionalDependencies": { + "@tiptap/extension-bubble-menu": "^3.28.0", + "@tiptap/extension-floating-menu": "^3.28.0" + }, + "peerDependencies": { + "@tiptap/core": "3.28.0", + "@tiptap/pm": "3.28.0", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "@types/react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@tiptap/starter-kit": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-3.28.0.tgz", + "integrity": "sha512-pqvFpValV+ONtlu3l4s73ROm/tEjoGMmt6uHmSJaLbqTcMHkdWuR3flJ/5brr4IDHe1foxmNicMbRxlje7yBYw==", + "license": "MIT", + "dependencies": { + "@tiptap/core": "^3.28.0", + "@tiptap/extension-blockquote": "^3.28.0", + "@tiptap/extension-bold": "^3.28.0", + "@tiptap/extension-bullet-list": "^3.28.0", + "@tiptap/extension-code": "^3.28.0", + "@tiptap/extension-code-block": "^3.28.0", + "@tiptap/extension-document": "^3.28.0", + "@tiptap/extension-dropcursor": "^3.28.0", + "@tiptap/extension-gapcursor": "^3.28.0", + "@tiptap/extension-hard-break": "^3.28.0", + "@tiptap/extension-heading": "^3.28.0", + "@tiptap/extension-horizontal-rule": "^3.28.0", + "@tiptap/extension-italic": "^3.28.0", + "@tiptap/extension-link": "^3.28.0", + "@tiptap/extension-list": "^3.28.0", + "@tiptap/extension-list-item": "^3.28.0", + "@tiptap/extension-list-keymap": "^3.28.0", + "@tiptap/extension-ordered-list": "^3.28.0", + "@tiptap/extension-paragraph": "^3.28.0", + "@tiptap/extension-strike": "^3.28.0", + "@tiptap/extension-text": "^3.28.0", + "@tiptap/extension-underline": "^3.28.0", + "@tiptap/extensions": "^3.28.0", + "@tiptap/pm": "^3.28.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + } + }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.5.tgz", + "integrity": "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/katex": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.8.tgz", + "integrity": "sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==", + "license": "MIT" + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdx": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.14.tgz", + "integrity": "sha512-T48PeuJtvLosNTPVhfnIp3i/n3a4g4Bad7YCq5k64D4u7NwDrAotikQ+5+sjtUvBmxCMlbo3dVL+C2dP0rWHzg==", + "license": "MIT" + }, + "node_modules/@types/mocha": { + "version": "10.0.10", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz", + "integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.19.43", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz", + "integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "license": "MIT" + }, + "node_modules/@types/prismjs": { + "version": "1.26.6", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.6.tgz", + "integrity": "sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==", + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.31", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.31.tgz", + "integrity": "sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@types/sinonjs__fake-timers": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz", + "integrity": "sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", + "license": "MIT" + }, + "node_modules/@types/whatwg-mimetype": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/whatwg-mimetype/-/whatwg-mimetype-3.0.2.tgz", + "integrity": "sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/which/-/which-2.0.2.tgz", + "integrity": "sha512-113D3mDkZDjo+EeUEHCFy0qniNc1ZpecGiAU7WSo7YDoSzolZIQKpYFHrPpjkB2nuyahcKfrmLXeQlh7gqJYdw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.3.tgz", + "integrity": "sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==", + "license": "ISC" + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/@vitest/expect": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.10.tgz", + "integrity": "sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.10", + "@vitest/utils": "4.1.10", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/expect/node_modules/tinyrainbow": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.10.tgz", + "integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.10", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.9.tgz", + "integrity": "sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.10.tgz", + "integrity": "sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.10", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitest/snapshot": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.9.tgz", + "integrity": "sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.9", + "magic-string": "^0.30.12", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.10.tgz", + "integrity": "sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.10.tgz", + "integrity": "sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.10", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils/node_modules/@vitest/pretty-format": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.10.tgz", + "integrity": "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils/node_modules/tinyrainbow": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@vscode/codicons": { + "version": "0.0.45", + "resolved": "https://registry.npmjs.org/@vscode/codicons/-/codicons-0.0.45.tgz", + "integrity": "sha512-1KAZ7XCMagp5Gdrlr4bbbcAqgcIL623iO1wW6rfcSVGAVUQvR0WP7bQx1SbJ11gmV3fdQTSEFIJQ/5C+HuVasw==", + "license": "CC-BY-4.0" + }, + "node_modules/@wdio/cli": { + "version": "9.29.1", + "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-9.29.1.tgz", + "integrity": "sha512-MjRHdM5mGuibhwv+pu8rJD1Pxl6JVj4Pvy9stuj/SjbTqWRxjLauLd3i7+tIMdmrK0ajGO0n249HT8vS8Mh0Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/snapshot": "^2.1.1", + "@wdio/config": "9.29.1", + "@wdio/globals": "9.29.1", + "@wdio/logger": "9.29.1", + "@wdio/protocols": "9.29.1", + "@wdio/types": "9.29.1", + "@wdio/utils": "9.29.1", + "async-exit-hook": "^2.0.1", + "chalk": "^5.4.1", + "chokidar": "^4.0.0", + "create-wdio": "9.29.1", + "dotenv": "^17.2.0", + "import-meta-resolve": "^4.0.0", + "lodash.flattendeep": "^4.4.0", + "lodash.pickby": "^4.6.0", + "lodash.union": "^4.6.0", + "read-pkg-up": "^10.0.0", + "tsx": "^4.7.2", + "webdriverio": "9.29.1", + "yargs": "^17.7.2" + }, + "bin": { + "wdio": "bin/wdio.js" + }, + "engines": { + "node": ">=18.20.0" + } + }, + "node_modules/@wdio/config": { + "version": "9.29.1", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-9.29.1.tgz", + "integrity": "sha512-8IXDiRG9wUUnpU6M/uzsVqIHJD/7o4y9RaOU2Jh/OdRJP/7rxwfGsa24Bv486rnMGdghztkwLCBJWG0jbeEtfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@wdio/logger": "9.29.1", + "@wdio/types": "9.29.1", + "@wdio/utils": "9.29.1", + "deepmerge-ts": "^7.0.3", + "glob": "^10.2.2", + "import-meta-resolve": "^4.0.0", + "jiti": "^2.6.1" + }, + "engines": { + "node": ">=18.20.0" + } + }, + "node_modules/@wdio/dot-reporter": { + "version": "9.29.1", + "resolved": "https://registry.npmjs.org/@wdio/dot-reporter/-/dot-reporter-9.29.1.tgz", + "integrity": "sha512-5UVgxKHVoJfJVSg3VH9n0yPkstHzX65g5zRBtNX51hqXmSPRE9kSLGq53Lo91UTORc0og3i0UT93zZqEQhpzjA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@wdio/reporter": "9.29.1", + "@wdio/types": "9.29.1", + "chalk": "^5.0.1" + }, + "engines": { + "node": ">=18.20.0" + } + }, + "node_modules/@wdio/globals": { + "version": "9.29.1", + "resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-9.29.1.tgz", + "integrity": "sha512-F96BKppx4HGD64v+s57TM4K4zaxqUCg2RXHk6sjB2xrSa7P+d2VYV28ID2ddF7iSodVfPlpa1i2/jy8jMGrU8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.20.0" + }, + "peerDependencies": { + "expect-webdriverio": "^5.6.5", + "webdriverio": "^9.0.0" + }, + "peerDependenciesMeta": { + "expect-webdriverio": { + "optional": false + }, + "webdriverio": { + "optional": false + } + } + }, + "node_modules/@wdio/local-runner": { + "version": "9.29.1", + "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-9.29.1.tgz", + "integrity": "sha512-ypgi3gTZYY3eStp1U9H6Gjl0mer55CYMdbtRQ27s6evN1QABcwkGCTuzwqHoO6RmKzwPOuht2mnWb9HwYJaNnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "^20.1.0", + "@wdio/logger": "9.29.1", + "@wdio/repl": "9.16.2", + "@wdio/runner": "9.29.1", + "@wdio/types": "9.29.1", + "@wdio/xvfb": "9.29.1", + "exit-hook": "^4.0.0", + "expect-webdriverio": "^5.6.5", + "split2": "^4.1.0", + "stream-buffers": "^3.0.2" + }, + "engines": { + "node": ">=18.20.0" + } + }, + "node_modules/@wdio/logger": { + "version": "9.29.1", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-9.29.1.tgz", + "integrity": "sha512-0ZAEIo6PNyMIJPlOGkIgyOJUjcd0pC8/QHlVAAe1c91/IcjZ1X+k0yidXHaboJdN7dq1XPUacmhRdtua0U5EZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.1.2", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "safe-regex2": "^5.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18.20.0" + } + }, + "node_modules/@wdio/mocha-framework": { + "version": "9.29.1", + "resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-9.29.1.tgz", + "integrity": "sha512-GG3z0OtD2eu15ql3vnI6VcLJ3INUfSrqbuop/tCAbCjkkKgpjq1JOno0lrDNKRt5Ndq4a4/c9Wu5uxfL+CItYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mocha": "^10.0.6", + "@types/node": "^20.11.28", + "@wdio/logger": "9.29.1", + "@wdio/types": "9.29.1", + "@wdio/utils": "9.29.1", + "mocha": "^10.3.0" + }, + "engines": { + "node": ">=18.20.0" + } + }, + "node_modules/@wdio/native-core": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@wdio/native-core/-/native-core-1.0.0.tgz", + "integrity": "sha512-SBVipUZk1+fiwwyGkDjp0gZsV+AGlZ1NE3rPviPCzs6QKm6Qmj7di/05P5MdqYUq/PslrVEWNIp6TYfL+wjEKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@wdio/logger": "9.18.0", + "@wdio/native-types": "2.3.1", + "@wdio/native-utils": "2.4.0", + "debug": "^4.4.3", + "get-port": "^7.1.0", + "tslib": "^2.8.1" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.11.0" + } + }, + "node_modules/@wdio/native-core/node_modules/@wdio/logger": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-9.18.0.tgz", + "integrity": "sha512-HdzDrRs+ywAqbXGKqe1i/bLtCv47plz4TvsHFH3j729OooT5VH38ctFn5aLXgECmiAKDkmH/A6kOq2Zh5DIxww==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.1.2", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "safe-regex2": "^5.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18.20.0" + } + }, + "node_modules/@wdio/native-core/node_modules/@wdio/native-types": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@wdio/native-types/-/native-types-2.3.1.tgz", + "integrity": "sha512-q6BOAd7Yg8lQJJWW/z1a4ratTttMIy39MfbAIgw8PKrXB6Oc+x95KXkuIcCGDINTk+X92Lbjxefiww4jiPam8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.11.0" + } + }, + "node_modules/@wdio/native-spy": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@wdio/native-spy/-/native-spy-1.1.0.tgz", + "integrity": "sha512-1BTbiWo9fNOsnSRYTjBE0Z6PtknFMtN7/TH2SsnishkIABUHH8ONKB+NWiTCiX8IkFiARguo2bJHEQBOULXlwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.11.0" + } + }, + "node_modules/@wdio/native-types": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@wdio/native-types/-/native-types-2.4.0.tgz", + "integrity": "sha512-GjgPskOoTvl17Jwj8aAU3A31gpklL5M1KfbrwYffbQT16CTpJTD8A4PdoS2ZjGoCWcyLBR1CWdJI3W8T0JBLjw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.11.0" + } + }, + "node_modules/@wdio/native-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@wdio/native-utils/-/native-utils-2.5.0.tgz", + "integrity": "sha512-Qv0mJ2elRBZCgYbHCnKPNgE9VaqnmNJyjythTDYyOQpj8pAs6FZXXmWXGkUIdMds5cK0ux/qtxyKU0Y0tDsUUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@wdio/logger": "9.18.0", + "debug": "^4.4.3", + "esbuild": "^0.28.0", + "find-up-simple": "^1.0.1", + "json5": "^2.2.3", + "smol-toml": "^1.6.0", + "yaml": "^2.9.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.11.0" + }, + "peerDependencies": { + "tsx": "^4.22.4" + }, + "peerDependenciesMeta": { + "tsx": { + "optional": true + } + } + }, + "node_modules/@wdio/native-utils/node_modules/@wdio/logger": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-9.18.0.tgz", + "integrity": "sha512-HdzDrRs+ywAqbXGKqe1i/bLtCv47plz4TvsHFH3j729OooT5VH38ctFn5aLXgECmiAKDkmH/A6kOq2Zh5DIxww==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.1.2", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "safe-regex2": "^5.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18.20.0" + } + }, + "node_modules/@wdio/protocols": { + "version": "9.29.1", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-9.29.1.tgz", + "integrity": "sha512-NFlBQOA4zDb4D/ETpVMqDgbJyEqdhGRsJWybLOXG7PGlPwfcrfmTMHC1+Boq4KODgpwbhCmI9zIk2JQmGYIttQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@wdio/repl": { + "version": "9.16.2", + "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-9.16.2.tgz", + "integrity": "sha512-FLTF0VL6+o5BSTCO7yLSXocm3kUnu31zYwzdsz4n9s5YWt83sCtzGZlZpt7TaTzb3jVUfxuHNQDTb8UMkCu0lQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "^20.1.0" + }, + "engines": { + "node": ">=18.20.0" + } + }, + "node_modules/@wdio/reporter": { + "version": "9.29.1", + "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-9.29.1.tgz", + "integrity": "sha512-CKAcVy9BGwvufokMcl3H+yNcvD11Klku/1BPz8bKSRv7/KzueXR06s1cPbJH3tv9r9zxPErxgdVMpulN8I0qAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "^20.1.0", + "@wdio/logger": "9.29.1", + "@wdio/types": "9.29.1", + "diff": "^8.0.2", + "object-inspect": "^1.12.0" + }, + "engines": { + "node": ">=18.20.0" + } + }, + "node_modules/@wdio/runner": { + "version": "9.29.1", + "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-9.29.1.tgz", + "integrity": "sha512-LV9+0U74J1YModG0T64Kdnh+xvOcd9MWGFlKyXnCtfFDV+47K9BpoDMrc/ng3daLrIKcZGVbym+GhEShiM0DPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "^20.11.28", + "@wdio/config": "9.29.1", + "@wdio/dot-reporter": "9.29.1", + "@wdio/globals": "9.29.1", + "@wdio/logger": "9.29.1", + "@wdio/types": "9.29.1", + "@wdio/utils": "9.29.1", + "deepmerge-ts": "^7.0.3", + "webdriver": "9.29.1", + "webdriverio": "9.29.1" + }, + "engines": { + "node": ">=18.20.0" + }, + "peerDependencies": { + "expect-webdriverio": "^5.6.5", + "webdriverio": "^9.0.0" + }, + "peerDependenciesMeta": { + "expect-webdriverio": { + "optional": false + }, + "webdriverio": { + "optional": false + } + } + }, + "node_modules/@wdio/spec-reporter": { + "version": "9.29.1", + "resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-9.29.1.tgz", + "integrity": "sha512-iqlHW/qGDRGmxQKN7XyCHxfKphTbPNnniV3yxNXZRSGHCCQok5KFKOnj4fpUCKEyD5jtPAmP6Y0qc1UyR3Dc3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@wdio/reporter": "9.29.1", + "@wdio/types": "9.29.1", + "chalk": "^5.1.2", + "easy-table": "^1.2.0", + "pretty-ms": "^9.0.0" + }, + "engines": { + "node": ">=18.20.0" + } + }, + "node_modules/@wdio/tauri-plugin": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@wdio/tauri-plugin/-/tauri-plugin-1.2.0.tgz", + "integrity": "sha512-qeQQ4D0Q4BkwC+Cyez1I343DRm9UErCXksZ/DN1qCpJCorEEPKL3IiYb34OtNJBgnbhqwtGukyjOZYvnpPz95A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tauri-apps/api": "2.11.0", + "@tauri-apps/plugin-log": "2.8.0", + "@wdio/native-spy": "1.1.0", + "@wdio/native-utils": "2.4.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.11.0" + } + }, + "node_modules/@wdio/tauri-service": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@wdio/tauri-service/-/tauri-service-1.2.0.tgz", + "integrity": "sha512-/PEmbDKra6Lsodes5x1Sg5H98bG4hObYZWMyrlbv0e5fL0KVMQMxDP798jWWIqT6+iOPsIlkLirRJKfXXGVtsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@wdio/globals": "9.27.1", + "@wdio/logger": "9.18.0", + "@wdio/native-core": "1.0.0", + "@wdio/native-spy": "1.1.0", + "@wdio/native-types": "2.4.0", + "@wdio/native-utils": "2.4.0", + "@wdio/spec-reporter": "9.27.1", + "@wdio/types": "9.27.1", + "debug": "^4.4.3", + "get-port": "^7.1.0", + "tslib": "^2.8.1", + "webdriverio": "9.27.1" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.11.0" + }, + "peerDependencies": { + "webdriverio": "^9.0.0" + }, + "peerDependenciesMeta": { + "webdriverio": { + "optional": false + } + } + }, + "node_modules/@wdio/tauri-service/node_modules/@wdio/config": { + "version": "9.27.1", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-9.27.1.tgz", + "integrity": "sha512-QVfSCqcpMfVum9KlpxgjaLlSLXkc53UQ2CPJU+IUVBp8LkbSyeX972HQS8V9Hnn6vSPE1dYScItg7wblnJ8RQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@wdio/logger": "9.18.0", + "@wdio/types": "9.27.1", + "@wdio/utils": "9.27.1", + "deepmerge-ts": "^7.0.3", + "glob": "^10.2.2", + "import-meta-resolve": "^4.0.0", + "jiti": "^2.6.1" + }, + "engines": { + "node": ">=18.20.0" + } + }, + "node_modules/@wdio/tauri-service/node_modules/@wdio/globals": { + "version": "9.27.1", + "resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-9.27.1.tgz", + "integrity": "sha512-jm6gTQ6Qo3EOBY6PA09U/5Pf17WLEJM1/lTfhc6jzLFE770EuhuhbuphqrInH0hVR9WMyWtSZQ+LRCcLfcmOPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.20.0" + }, + "peerDependencies": { + "expect-webdriverio": "^5.6.5", + "webdriverio": "^9.0.0" + }, + "peerDependenciesMeta": { + "expect-webdriverio": { + "optional": false + }, + "webdriverio": { + "optional": false + } + } + }, + "node_modules/@wdio/tauri-service/node_modules/@wdio/logger": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-9.18.0.tgz", + "integrity": "sha512-HdzDrRs+ywAqbXGKqe1i/bLtCv47plz4TvsHFH3j729OooT5VH38ctFn5aLXgECmiAKDkmH/A6kOq2Zh5DIxww==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.1.2", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "safe-regex2": "^5.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18.20.0" + } + }, + "node_modules/@wdio/tauri-service/node_modules/@wdio/protocols": { + "version": "9.27.1", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-9.27.1.tgz", + "integrity": "sha512-Ril46AmySoiYX9nuKqFr3SNJqquU3VmF9FzSndQlDib0G3oA4pYx9wcBXvdvkFxRjjmFwQDzmvztKrssAHymgw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@wdio/tauri-service/node_modules/@wdio/reporter": { + "version": "9.27.1", + "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-9.27.1.tgz", + "integrity": "sha512-2ueVjd5hOCclfC+GV3yhaN/4Tids1mXMcpPtNTPushHIQY4gLmBqqKDe5RSXAED3bNU+DRdHq2uBiZTBd4QDJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "^20.1.0", + "@wdio/logger": "9.18.0", + "@wdio/types": "9.27.1", + "diff": "^8.0.2", + "object-inspect": "^1.12.0" + }, + "engines": { + "node": ">=18.20.0" + } + }, + "node_modules/@wdio/tauri-service/node_modules/@wdio/spec-reporter": { + "version": "9.27.1", + "resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-9.27.1.tgz", + "integrity": "sha512-q9UMJJbCcP+nCOojIvOIcsXnerhHICmWu94guRMRYPbW2IsG/5VM/uhzwru8SU/1WRXLtKgTjkuXXsjzjVpf2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@wdio/reporter": "9.27.1", + "@wdio/types": "9.27.1", + "chalk": "^5.1.2", + "easy-table": "^1.2.0", + "pretty-ms": "^9.0.0" + }, + "engines": { + "node": ">=18.20.0" + } + }, + "node_modules/@wdio/tauri-service/node_modules/@wdio/types": { + "version": "9.27.1", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-9.27.1.tgz", + "integrity": "sha512-EHBNCvLmvpYerln4mb/OBxzKtnavL2wdenjhwuYjzkZMOWHgm/uLXH6sLThM0y6DIbCU72Asth16fo1eDcsofA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "^20.1.0" + }, + "engines": { + "node": ">=18.20.0" + } + }, + "node_modules/@wdio/tauri-service/node_modules/@wdio/utils": { + "version": "9.27.1", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-9.27.1.tgz", + "integrity": "sha512-s2w1tFrvmpdkZ33LYsIw4ONRdWIIm4MxkyIuibbcG1ILV5fFMS9rU59csHuWIM0KhJoEoLU+fzE3ze9O7TpWhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@puppeteer/browsers": "^2.2.0", + "@wdio/logger": "9.18.0", + "@wdio/types": "9.27.1", + "decamelize": "^6.0.0", + "deepmerge-ts": "^7.0.3", + "edgedriver": "^6.1.2", + "geckodriver": "^6.1.0", + "get-port": "^7.0.0", + "import-meta-resolve": "^4.0.0", + "locate-app": "^2.2.24", + "mitt": "^3.0.1", + "safaridriver": "^1.0.0", + "split2": "^4.2.0", + "wait-port": "^1.1.0" + }, + "engines": { + "node": ">=18.20.0" + } + }, + "node_modules/@wdio/tauri-service/node_modules/webdriver": { + "version": "9.27.1", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-9.27.1.tgz", + "integrity": "sha512-vr6h+RNQ75O2cofgVrdupGxtKjPEBaBYx/lHCHe0giJfAK01oL0U/yrOksJi7kmpev/daN93ldFPhlIlmWtv8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "^20.1.0", + "@types/ws": "^8.5.3", + "@wdio/config": "9.27.1", + "@wdio/logger": "9.18.0", + "@wdio/protocols": "9.27.1", + "@wdio/types": "9.27.1", + "@wdio/utils": "9.27.1", + "deepmerge-ts": "^7.0.3", + "https-proxy-agent": "^7.0.6", + "undici": "^6.21.3", + "ws": "^8.8.0" + }, + "engines": { + "node": ">=18.20.0" + } + }, + "node_modules/@wdio/tauri-service/node_modules/webdriverio": { + "version": "9.27.1", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-9.27.1.tgz", + "integrity": "sha512-iPaIU/DluYY7zfLiwXDdoLU/6ZW8eup4PNwQikrCzTfvH/ITllRhFUe6NRDTEEePSxxRTeXAn9nehCs98xWGVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "^20.11.30", + "@types/sinonjs__fake-timers": "^8.1.5", + "@wdio/config": "9.27.1", + "@wdio/logger": "9.18.0", + "@wdio/protocols": "9.27.1", + "@wdio/repl": "9.16.2", + "@wdio/types": "9.27.1", + "@wdio/utils": "9.27.1", + "archiver": "^7.0.1", + "aria-query": "^5.3.0", + "cheerio": "^1.0.0-rc.12", + "css-shorthand-properties": "^1.1.1", + "css-value": "^0.0.1", + "grapheme-splitter": "^1.0.4", + "htmlfy": "^0.8.1", + "is-plain-obj": "^4.1.0", + "jszip": "^3.10.1", + "lodash.clonedeep": "^4.5.0", + "lodash.zip": "^4.2.0", + "query-selector-shadow-dom": "^1.0.1", + "resq": "^1.11.0", + "rgb2hex": "0.2.5", + "serialize-error": "^12.0.0", + "urlpattern-polyfill": "^10.0.0", + "webdriver": "9.27.1" + }, + "engines": { + "node": ">=18.20.0" + }, + "peerDependencies": { + "puppeteer-core": ">=22.x || <=24.x" + }, + "peerDependenciesMeta": { + "puppeteer-core": { + "optional": true + } + } + }, + "node_modules/@wdio/types": { + "version": "9.29.1", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-9.29.1.tgz", + "integrity": "sha512-jp8jgMv6TS35G96YzHZxw3PVN0Dz6xQ6tnMAicndAJ8Jt9AIXb0ywIse4TjaFywakO3dLoEhlyA3ZtR26vmt+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "^20.1.0" + }, + "engines": { + "node": ">=18.20.0" + } + }, + "node_modules/@wdio/utils": { + "version": "9.29.1", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-9.29.1.tgz", + "integrity": "sha512-jyt6b6FfdYwVbMISVhuyGC1xQGZj6xM03KhTHozH7a9/zu9b++94KRdT9HRbwX8zefjW0YeIC5+qWSIf7WWHZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@puppeteer/browsers": "^2.2.0", + "@wdio/logger": "9.29.1", + "@wdio/types": "9.29.1", + "decamelize": "^6.0.0", + "deepmerge-ts": "^7.0.3", + "edgedriver": "^6.1.2", + "geckodriver": "^6.1.0", + "get-port": "^7.0.0", + "import-meta-resolve": "^4.0.0", + "locate-app": "^2.2.24", + "mitt": "^3.0.1", + "safaridriver": "^1.0.0", + "split2": "^4.2.0", + "wait-port": "^1.1.0" + }, + "engines": { + "node": ">=18.20.0" + } + }, + "node_modules/@wdio/xvfb": { + "version": "9.29.1", + "resolved": "https://registry.npmjs.org/@wdio/xvfb/-/xvfb-9.29.1.tgz", + "integrity": "sha512-suC0EJcPVldpIyJA/UB9cV11PkW4sGgNmLHPhWU7NiASnbiFeHjK3EbevjzlwwBNYXx1KHO4jMY4Rep2wwVNuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@wdio/logger": "9.29.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@zip.js/zip.js": { + "version": "2.8.31", + "resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.8.31.tgz", + "integrity": "sha512-2NLmow9ax/5IdBbJKxNQp3Ur9mNxmgLfN2Yp/FKNh1ZIGs3OYkiC3AIUfIZouTPSgeW5+F1bzTAZAyD2Y4ZfFA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "bun": ">=0.7.0", + "deno": ">=1.0.0", + "node": ">=18.0.0" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/acorn": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/antd-style": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/antd-style/-/antd-style-4.1.0.tgz", + "integrity": "sha512-vnPBGg0OVlSz90KRYZhxd89aZiOImTiesF+9MQqN8jsLGZUQTjbP04X9jTdEfsztKUuMbBWg/RmB/wHTakbtMQ==", + "license": "MIT", + "dependencies": { + "@ant-design/cssinjs": "^2.0.0", + "@babel/runtime": "^7.24.1", + "@emotion/cache": "^11.11.0", + "@emotion/css": "^11.11.2", + "@emotion/react": "^11.11.4", + "@emotion/serialize": "^1.1.3", + "@emotion/utils": "^1.2.1", + "use-merge-value": "^1.2.0" + }, + "peerDependencies": { + "antd": ">=6.0.0", + "react": ">=18" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/anynum": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/anynum/-/anynum-1.0.1.tgz", + "integrity": "sha512-N6//FLET/tXYNM/F6ABca1oH6fWB+KlTt909Le28WMDBk8oaT4vY17DCrwg2MvmuqUKt3Ni4N5dGJ/EoBgcO6A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/archiver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz", + "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "archiver-utils": "^5.0.2", + "async": "^3.2.4", + "buffer-crc32": "^1.0.0", + "readable-stream": "^4.0.0", + "readdir-glob": "^1.1.2", + "tar-stream": "^3.0.0", + "zip-stream": "^6.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/archiver-utils": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz", + "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "^10.0.0", + "graceful-fs": "^4.2.0", + "is-stream": "^2.0.1", + "lazystream": "^1.0.0", + "lodash": "^4.17.15", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/archiver-utils/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/astring": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz", + "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==", + "license": "MIT", + "bin": { + "astring": "bin/astring" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, + "node_modules/async-exit-hook": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz", + "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/async-validator": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-3.5.2.tgz", + "integrity": "sha512-8eLCg00W9pIRZSB781UUX/H6Oskmm8xloZfr09lz5bikRpBVDlJ3hRVuxxP1SxcwsEYfJ4IU8Q19Y8/893r3rQ==", + "license": "MIT" + }, + "node_modules/b4a": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.1.tgz", + "integrity": "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/bare-events": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.9.1.tgz", + "integrity": "sha512-Z0oHEHAFDZkffN8Qc39zNZjQlMDkPJRyyyZieU1VH7u8c5S+qHZ2S8ixdKIAxEjfHO7FJxXmJWgteOghVanIsg==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "bare-abort-controller": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + } + } + }, + "node_modules/bare-fs": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.7.4.tgz", + "integrity": "sha512-y1kC+ffIx/tPLdTE693uNjHfzTfr+ravR5tvWlMXe25nELbkqV400S71qHDwbkAQ1FVEZobB1NFRzFbCCcyBCQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.5.4", + "bare-path": "^3.0.0", + "bare-stream": "^2.6.4", + "bare-url": "^2.2.2", + "fast-fifo": "^1.3.2" + }, + "engines": { + "bare": ">=1.16.0" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } + } + }, + "node_modules/bare-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.1.1.tgz", + "integrity": "sha512-JprUlveX3QjApC1cTpsUOiscADftCGVWkzitbHsRqv84hzYwYHw2mbluddsq5TvI8mH/8Ov1f4BiMAdcB0oYnQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/bare-stream": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.3.tgz", + "integrity": "sha512-Kc+brLqvEqGkjyfiwJmImAOqLZL7OsoLKuavx+hJjgVV3nLTOjloJyPMFxjUPerGGHrNH0fLU06jjykMLWrERQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.8.1", + "streamx": "^2.25.0", + "teex": "^1.0.1" + }, + "peerDependencies": { + "bare-abort-controller": "*", + "bare-buffer": "*", + "bare-events": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + }, + "bare-buffer": { + "optional": true + }, + "bare-events": { + "optional": true + } + } + }, + "node_modules/bare-url": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.5.tgz", + "integrity": "sha512-K+y9xF1tN+CdPu4qWwr0QiK1Al07eFPGYK5M2pDXcmHdMdgC/tT/bpmMe1hrmRHaidKLkXrC+cRNYf3XVDUhSQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-path": "^3.0.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.43", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.43.tgz", + "integrity": "sha512-AjYpR78kDWAY3Efj+cDTFH9t9SCoL7OoTp1BOb0mQV7S+6CiLwnWM3FyxhJtdPufDFKzmCSFoUncKjWgJEZTCQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/basic-ftp": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.3.1.tgz", + "integrity": "sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/bezier-easing": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/bezier-easing/-/bezier-easing-2.1.0.tgz", + "integrity": "sha512-gbIqZ/eslnUFC1tjEvtz0sgx+xTK20wDnYMIA27VA04R7w6xxXQPZDbibjA9DTWZRA2CXtwHykkVzlCaAJAZig==", + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, + "node_modules/brace-expansion": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.2.tgz", + "integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true, + "license": "ISC" + }, + "node_modules/browserslist": { + "version": "4.28.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.6.tgz", + "integrity": "sha512-FQBYNK15VMslhLHpA7+n+n1GOlF1kId2xcCg7/j95f24AOF6VDYMNH4mFxF7KuaTdv627faazpOAjFzMrfJOUw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.42", + "caniuse-lite": "^1.0.30001803", + "electron-to-chromium": "^1.5.389", + "node-releases": "^2.0.51", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-crc32": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", + "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/buffer-image-size": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/buffer-image-size/-/buffer-image-size-0.6.4.tgz", + "integrity": "sha512-nEh+kZOPY1w+gcCMobZ6ETUp9WfibndnosbpwB1iJk/8Gt5ZF2bhS6+B6bPYz424KtwsR6Rflc3tCz1/ghX2dQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001806", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz", + "integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chardet": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.2.0.tgz", + "integrity": "sha512-rddelWYNPRrXq6PtNEN2S3f6t9ILzvqaN5pVgi4kqt9jHQaXIial9PznB5iSPVlQSLNaaH22ItWz3EJtQ10+OA==", + "dev": true, + "license": "MIT" + }, + "node_modules/cheerio": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.2.0.tgz", + "integrity": "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "encoding-sniffer": "^0.2.1", + "htmlparser2": "^10.1.0", + "parse5": "^7.3.0", + "parse5-htmlparser2-tree-adapter": "^7.1.0", + "parse5-parser-stream": "^7.1.2", + "undici": "^7.19.0", + "whatwg-mimetype": "^4.0.0" + }, + "engines": { + "node": ">=20.18.1" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cheerio/node_modules/undici": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.28.0.tgz", + "integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/cheerio/node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "license": "MIT" + }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 12" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/collapse-white-space": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", + "integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/compress-commons": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz", + "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "crc-32": "^1.2.0", + "crc32-stream": "^6.0.0", + "is-stream": "^2.0.1", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/compress-commons/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/compute-scroll-into-view": { + "version": "1.0.20", + "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz", + "integrity": "sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==", + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/copy-text-to-clipboard": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-2.2.0.tgz", + "integrity": "sha512-WRvoIdnTs1rgPMkgA2pUOa/M4Enh2uzCwdKsOMYNAJiz/4ZvEJgmbF4OmninPmlFdAWisfeh0tH+Cpf7ni3RqQ==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc32-stream": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz", + "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==", + "dev": true, + "license": "MIT", + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/create-wdio": { + "version": "9.29.1", + "resolved": "https://registry.npmjs.org/create-wdio/-/create-wdio-9.29.1.tgz", + "integrity": "sha512-EWef5jtJ9pN+tYblwZvWwDEKEgZSMy8VZCUCWBIiw3Z48aDbqusxpOseZWZ/rAttsqGyntzIvHLxIo0r7kryxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "commander": "^14.0.0", + "cross-spawn": "^7.0.3", + "ejs": "^3.1.10", + "execa": "^9.6.0", + "import-meta-resolve": "^4.1.0", + "inquirer": "^12.7.0", + "normalize-package-data": "^7.0.0", + "read-pkg-up": "^10.1.0", + "recursive-readdir": "^2.2.3", + "semver": "^7.6.3", + "type-fest": "^4.41.0", + "yargs": "^17.7.2" + }, + "bin": { + "create-wdio": "bin/wdio.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/create-wdio/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-shorthand-properties": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/css-shorthand-properties/-/css-shorthand-properties-1.1.2.tgz", + "integrity": "sha512-C2AugXIpRGQTxaCW0N7n5jD/p5irUmCrwl03TrnMFBHDbdq44CFWR2zO7rK9xPN4Eo3pUxC4vQzQgbIpzrD1PQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/css-value": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/css-value/-/css-value-0.0.1.tgz", + "integrity": "sha512-FUV3xaJ63buRLgHrLQVlVgQnQdR4yqdLGaDu7g8CQcWjInDfM9plBTPI9FRfpahju1UBSaMckeb2/46ApS/V1Q==", + "dev": true + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true, + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/date-fns-tz": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/date-fns-tz/-/date-fns-tz-1.3.8.tgz", + "integrity": "sha512-qwNXUFtMHTTU6CFSFjoJ80W8Fzzp24LntbjFFBgL/faqds4e5mo9mftoRLgr3Vi1trISsg4awSpYVsOQCRnapQ==", + "license": "MIT", + "peerDependencies": { + "date-fns": ">=2.0.0" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.1.tgz", + "integrity": "sha512-G7Cqgaelq68XHJNGlZ7lrNQyhZGsFqpwtGFexqUv4IQdjKoSYF7ipZ9UuTJZUSQXFj/XaoBLuEVIVqr8EJngEQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/deepmerge-ts": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", + "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/diff": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT" + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dotenv": { + "version": "17.4.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", + "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/easy-table": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/easy-table/-/easy-table-1.2.0.tgz", + "integrity": "sha512-OFzVOv03YpvtcWGe5AayU5G2hgybsg3iqA6drU8UaoZyB9jLGMTrz9+asnLp/E+6qPh88yEI1gvyZFZ41dmgww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "optionalDependencies": { + "wcwidth": "^1.0.1" + } + }, + "node_modules/edge-paths": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/edge-paths/-/edge-paths-3.0.5.tgz", + "integrity": "sha512-sB7vSrDnFa4ezWQk9nZ/n0FdpdUuC6R1EOrlU3DL+bovcNFK28rqu2emmAUjujYEJTWIgQGqgVVWUZXMnc8iWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/which": "^2.0.1", + "which": "^2.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/shirshak55" + } + }, + "node_modules/edgedriver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/edgedriver/-/edgedriver-6.3.0.tgz", + "integrity": "sha512-ggEQL+oEyIcM4nP2QC3AtCQ04o4kDNefRM3hja0odvlPSnsaxiruMxEZ93v3gDCKWYW6BXUr51PPradb+3nffw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@wdio/logger": "^9.18.0", + "@zip.js/zip.js": "^2.8.11", + "decamelize": "^6.0.1", + "edge-paths": "^3.0.5", + "fast-xml-parser": "^5.3.3", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.6", + "which": "^6.0.0" + }, + "bin": { + "edgedriver": "bin/edgedriver.js" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/edgedriver/node_modules/isexe": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz", + "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=20" + } + }, + "node_modules/edgedriver/node_modules/which": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz", + "integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^4.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.393", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.393.tgz", + "integrity": "sha512-kiDJdIUawuEIcp9XoICKp1iTYDEbgguIPq526N1Q7jIQDeQ3CqoMx71025PI/7E48Ddtw2HuWsVjY7afEgNxmg==", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/encoding-sniffer": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz", + "integrity": "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "^0.6.3", + "whatwg-encoding": "^3.1.1" + }, + "funding": { + "url": "https://github.com/fb55/encoding-sniffer?sponsor=1" + } + }, + "node_modules/encoding-sniffer/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.1.tgz", + "integrity": "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-toolkit": { + "version": "1.49.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.49.0.tgz", + "integrity": "sha512-G5iZ6Pc/FNRY/soKZHC+TxGDD83rHUDXxzaWhGCX44vAv/tMs56WMusnm/KMNK+luUPsgA9U28cGr4RDlSzL2g==", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, + "node_modules/esast-util-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz", + "integrity": "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esast-util-from-js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esast-util-from-js/-/esast-util-from-js-2.0.1.tgz", + "integrity": "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "acorn": "^8.0.0", + "esast-util-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esbuild": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-util-attach-comments": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz", + "integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-build-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz", + "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-walker": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-scope": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/estree-util-scope/-/estree-util-scope-1.0.0.tgz", + "integrity": "sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-to-js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz", + "integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "astring": "^1.8.0", + "source-map": "^0.7.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-visit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz", + "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/events-universal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", + "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.7.0" + } + }, + "node_modules/execa": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.1.tgz", + "integrity": "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "cross-spawn": "^7.0.6", + "figures": "^6.1.0", + "get-stream": "^9.0.0", + "human-signals": "^8.0.1", + "is-plain-obj": "^4.1.0", + "is-stream": "^4.0.1", + "npm-run-path": "^6.0.0", + "pretty-ms": "^9.2.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^4.0.0", + "yoctocolors": "^2.1.1" + }, + "engines": { + "node": "^18.19.0 || >=20.5.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit-hook": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-4.0.0.tgz", + "integrity": "sha512-Fqs7ChZm72y40wKjOFXBKg7nJZvQJmewP5/7LtePDdnah/+FH9Hp5sgMujSCMPXlxOAW2//1jrW9pnsY7o20vQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/expect": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.4.1.tgz", + "integrity": "sha512-PMARsyh/JtqC20HoGqlFcIlQAyqUtW4PlI1rup1uhYJtKuwAjbvWi3GQMAn+STdHum/dk8xrKfUM1+5SAwpolA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "30.4.1", + "@jest/get-type": "30.1.0", + "jest-matcher-utils": "30.4.1", + "jest-message-util": "30.4.1", + "jest-mock": "30.4.1", + "jest-util": "30.4.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/expect-webdriverio": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/expect-webdriverio/-/expect-webdriverio-5.7.0.tgz", + "integrity": "sha512-jLOTrJoPBC3Wtd83ryHMbRcEajMGtAnn6OWtSnoJoDLt16nHvxVdjcI4Bc0n+1KAOr8DvQtlJ55f0M48kJtEpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/snapshot": "^4.1.7", + "deep-eql": "^5.0.2", + "expect": "^30.4.1", + "jest-matcher-utils": "^30.4.1" + }, + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "@wdio/globals": "^9.0.0", + "@wdio/logger": "^9.0.0", + "webdriverio": "^9.0.0" + }, + "peerDependenciesMeta": { + "@wdio/globals": { + "optional": false + }, + "@wdio/logger": { + "optional": false + }, + "webdriverio": { + "optional": false + } + } + }, + "node_modules/expect-webdriverio/node_modules/@vitest/pretty-format": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.10.tgz", + "integrity": "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/expect-webdriverio/node_modules/@vitest/snapshot": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.10.tgz", + "integrity": "sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.10", + "@vitest/utils": "4.1.10", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/expect-webdriverio/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/expect-webdriverio/node_modules/tinyrainbow": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extract-zip/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fast-copy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.2.tgz", + "integrity": "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-equals": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.4.1.tgz", + "integrity": "sha512-DjlFSM5Pk9cGcL0q5QXl66eGzx0N6szNgaswwc5ZphlBohjTVJSnGgI+rJVOgOi65qUoQnDZN4nDqi33udtydQ==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-xml-builder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.3.0.tgz", + "integrity": "sha512-F74cZEdCvuw9P41GAC3rod4X04jjWGM1JPEv/GWSqFTWLsdyMSBMBMlm9Hk3GLBgLBbdBNY8yee0pQh2RBVESQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "path-expression-matcher": "^1.6.2", + "xml-naming": "^0.3.0" + } + }, + "node_modules/fast-xml-parser": { + "version": "5.10.1", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.10.1.tgz", + "integrity": "sha512-IEMIf7298kXuZSRFoGfMYrl7is8LpavODgbNz1cwIudv7KwVFnuU+UsMporfq6PD6aXSlawZlARiA3UywCTfMw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "@nodable/entities": "^3.0.0", + "fast-xml-builder": "^1.2.0", + "is-unsafe": "^2.0.0", + "path-expression-matcher": "^1.6.2", + "strnum": "^2.4.1", + "xml-naming": "^0.3.0" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/figures": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", + "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-unicode-supported": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/filelist": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.6.tgz", + "integrity": "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "license": "MIT" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up-simple": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz", + "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/geckodriver": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/geckodriver/-/geckodriver-6.1.0.tgz", + "integrity": "sha512-ZRXLa4ZaYTTgUO4Eefw+RsQCleugU2QLb1ME7qTYxxuRj51yAhfnXaItXNs5/vUzfIaDHuZ+YnSF005hfp07nQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@wdio/logger": "^9.18.0", + "@zip.js/zip.js": "^2.8.11", + "decamelize": "^6.0.1", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.6", + "modern-tar": "^0.7.2" + }, + "bin": { + "geckodriver": "bin/geckodriver.js" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-port": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-7.2.0.tgz", + "integrity": "sha512-afP4W205ONCuMoPBqcR6PSXnzX35KTcJygfJfcp+QY+uwm3p20p1YczWXhlICIzGMCxYBQcySEcOgsJcrkyobg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", + "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-uri": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz", + "integrity": "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/happy-dom": { + "version": "20.10.6", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-20.10.6.tgz", + "integrity": "sha512-6QD0ilzDDt93tX44y8tbmZdAcdTRYDhUP+Asgi6pC8Pp5IA3cvaZGyoVN/EGtlq9ziT65iPuBBn3ASLr6hCgVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": ">=20.0.0", + "@types/whatwg-mimetype": "^3.0.2", + "@types/ws": "^8.18.1", + "buffer-image-size": "^0.6.4", + "entities": "^7.0.1", + "whatwg-mimetype": "^3.0.0", + "ws": "^8.21.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-from-dom": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/hast-util-from-dom/-/hast-util-from-dom-5.0.1.tgz", + "integrity": "sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q==", + "license": "ISC", + "dependencies": { + "@types/hast": "^3.0.0", + "hastscript": "^9.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-html": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", + "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "devlop": "^1.1.0", + "hast-util-from-parse5": "^8.0.0", + "parse5": "^7.0.0", + "vfile": "^6.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-html-isomorphic": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hast-util-from-html-isomorphic/-/hast-util-from-html-isomorphic-2.0.0.tgz", + "integrity": "sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-from-dom": "^5.0.0", + "hast-util-from-html": "^2.0.0", + "unist-util-remove-position": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-parse5": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", + "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^9.0.0", + "property-information": "^7.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-is-element": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-estree": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.3.tgz", + "integrity": "sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-attach-comments": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-text": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz", + "integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "hast-util-is-element": "^3.0.0", + "unist-util-find-after": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/hosted-git-info": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.1.0.tgz", + "integrity": "sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/html-url-attributes": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", + "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/htmlfy": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/htmlfy/-/htmlfy-0.8.1.tgz", + "integrity": "sha512-xWROBw9+MEGwxpotll0h672KCaLrKKiCYzsyN8ZgL9cQbVumFnyvsk2JqiB9ELAV1GLj1GG/jxZUjV9OZZi/yQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/htmlparser2": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz", + "integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "entities": "^7.0.1" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-signals": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", + "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/inline-style-parser": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", + "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", + "license": "MIT" + }, + "node_modules/inquirer": { + "version": "12.11.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-12.11.1.tgz", + "integrity": "sha512-9VF7mrY+3OmsAfjH3yKz/pLbJ5z22E23hENKw3/LNSaA/sAt3v49bDRY+Ygct1xwuKT+U+cBfTzjCPySna69Qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/prompts": "^7.10.1", + "@inquirer/type": "^3.0.10", + "mute-stream": "^2.0.0", + "run-async": "^4.0.6", + "rxjs": "^7.8.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/ip-address": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-mobile": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-mobile/-/is-mobile-5.0.0.tgz", + "integrity": "sha512-Tz/yndySvLAEXh+Uk8liFCxOwVH6YutuR74utvOcu7I9Di+DwM0mtdPVZNaVvvBUM2OXxne/NhOs1zAO7riusQ==", + "license": "MIT" + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unsafe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-unsafe/-/is-unsafe-2.0.0.tgz", + "integrity": "sha512-2LdV822R+wmI86unXA93WCFpL6g+av8ynWk0nrHyJqGop5VoocYsSLFgN8jrfalT6iGeLNM4KXuVSsULP53kEA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jake": { + "version": "10.9.4", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", + "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.6", + "filelist": "^1.0.4", + "picocolors": "^1.1.1" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-diff": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.4.1.tgz", + "integrity": "sha512-CRpFK0RtLriVDGcPPAnR6HMVI8bSR2jnUIgralhauzYQZIb4RH9AtEInTuQr65LmmGggGcRT6HIASxwqsVsmlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/diff-sequences": "30.4.0", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.4.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-diff/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/chalk/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/pretty-format": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.4.1.tgz", + "integrity": "sha512-K6KiKMHTL4jjX4u3Kir2EW07nRfcqVTXIImx50wbjHQTcZPgg+gjVeNTIT3l3L1Rd4UefxfogquC9J37SoFyyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "30.4.1", + "ansi-styles": "^5.2.0", + "react-is-18": "npm:react-is@^18.3.1", + "react-is-19": "npm:react-is@^19.2.5" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-diff/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-matcher-utils": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.4.1.tgz", + "integrity": "sha512-zvYfX5CaeEkFrrLS9suWe9rvJrm9J1Iv3ua8kIBv9GEPzcnsfBf0bob37la7s67fs0nlBC3EuvkOLnXQKxtx4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "jest-diff": "30.4.1", + "pretty-format": "30.4.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/chalk/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/pretty-format": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.4.1.tgz", + "integrity": "sha512-K6KiKMHTL4jjX4u3Kir2EW07nRfcqVTXIImx50wbjHQTcZPgg+gjVeNTIT3l3L1Rd4UefxfogquC9J37SoFyyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "30.4.1", + "ansi-styles": "^5.2.0", + "react-is-18": "npm:react-is@^18.3.1", + "react-is-19": "npm:react-is@^19.2.5" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-message-util": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.4.1.tgz", + "integrity": "sha512-kwCKIvq0MCW1HzLoGola9Te6JUdzgV0loyKJ3Qghrkz9i5/RRIHsL95BMQc2HBBhlBKC4j22K9p11TGHH8RBpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.4.1", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "jest-util": "30.4.1", + "picomatch": "^4.0.3", + "pretty-format": "30.4.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-message-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/chalk/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/pretty-format": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.4.1.tgz", + "integrity": "sha512-K6KiKMHTL4jjX4u3Kir2EW07nRfcqVTXIImx50wbjHQTcZPgg+gjVeNTIT3l3L1Rd4UefxfogquC9J37SoFyyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "30.4.1", + "ansi-styles": "^5.2.0", + "react-is-18": "npm:react-is@^18.3.1", + "react-is-19": "npm:react-is@^19.2.5" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-message-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-mock": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.4.1.tgz", + "integrity": "sha512-/i8SVb8/NSB7RfNi8gfqu8gxLV23KaL5EpAttyb9iz8qWRIqXRLflycz/32wXsYkOnaUlx8NAKnJYtpsmXUmfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.4.1", + "@types/node": "*", + "jest-util": "30.4.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-regex-util": { + "version": "30.4.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.4.0.tgz", + "integrity": "sha512-mWlvLviKIgIQ8VCuM1xRdD0TWp3zlzionlmDBjuXVBs+VkmXq6FgW9T4Emr7oGz/Rk6feDCGyiugolcQEyp3mg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-util": { + "version": "30.4.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.4.1.tgz", + "integrity": "sha512-vjQb1sACEiv13DKJMDToJpzVW0joCsIQrmbg0fi7CyOOt+g9jTuQl2A216pWRBYhOVt53XbL/2LbMKg1BECWOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.4.1", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.3" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", + "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "license": "MIT" + }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dev": true, + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/jszip/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/jszip/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/katex": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.17.0.tgz", + "integrity": "sha512-Vdw0ATsQ9V+LuegM/BTwQqV/6cTl5lbGcIrU+BCgLxyf6bo38ybOr372tuSIxir3CN720flu1meYR6XzNMwQnw==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/lazystream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/lazystream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/linkifyjs": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.3.3.tgz", + "integrity": "sha512-P8aEP5U/D1/IlTY2OeYsErdwh9bGuLE30NcXtKEjgdHcahveQoQwM2yZNsioQHsWFz0P7KKudisbrzCgR0sDHg==", + "license": "MIT" + }, + "node_modules/locate-app": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/locate-app/-/locate-app-2.5.0.tgz", + "integrity": "sha512-xIqbzPMBYArJRmPGUZD9CzV9wOqmVtQnaAn3wrj3s6WYW0bQvPI7x+sPYUGmDTYMHefVK//zc6HEYZ1qnxIK+Q==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://buymeacoffee.com/hejny" + }, + { + "type": "github", + "url": "https://github.com/hejny/locate-app/blob/main/README.md#%EF%B8%8F-contributing" + } + ], + "license": "Apache-2.0", + "dependencies": { + "@promptbook/utils": "0.69.5", + "type-fest": "4.26.0", + "userhome": "1.0.1" + } + }, + "node_modules/locate-app/node_modules/type-fest": { + "version": "4.26.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.26.0.tgz", + "integrity": "sha512-OduNjVJsFbifKb57UqZ2EMP1i4u64Xwow3NYXUtBbD4vIwJdQd4+xl8YDou1dlm4DVrtwT/7Ky8z8WyCULVfxw==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.pickby": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", + "integrity": "sha512-AZV+GsS/6ckvPOVQPXSiFFacKvKB4kOQu6ynt9wz0F3LO4R9Ij4K1ddYsIytDpSgLz88JHd9P+oaLeej5/Sl7Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.zip": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.zip/-/lodash.zip-4.2.0.tgz", + "integrity": "sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/loglevel": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.2.tgz", + "integrity": "sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/loglevel" + } + }, + "node_modules/loglevel-plugin-prefix": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/loglevel-plugin-prefix/-/loglevel-plugin-prefix-0.8.4.tgz", + "integrity": "sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lottie-web": { + "version": "5.13.0", + "resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.13.0.tgz", + "integrity": "sha512-+gfBXl6sxXMPe8tKQm7qzLnUy5DUPJPKIyRHwtpCpyUEYjHYRJC/5gjUvdkuO2c3JllrPtHXH5UJJK8LRYl5yQ==", + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "0.469.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.469.0.tgz", + "integrity": "sha512-28vvUnnKQ/dBwiCQtwJw7QauYnE7yd2Cyp4tTTJpvglX4EMpbflcdBgrgToX2j71B3YvugK/NH3BGUk+E/p/Fw==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/markdown-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", + "integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", + "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz", + "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-math": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-math/-/mdast-util-math-3.0.0.tgz", + "integrity": "sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "longest-streak": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.1.0", + "unist-util-remove-position": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz", + "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==", + "license": "MIT" + }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "license": "MIT", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-math": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz", + "integrity": "sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==", + "license": "MIT", + "dependencies": { + "@types/katex": "^0.16.0", + "devlop": "^1.0.0", + "katex": "^0.16.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-math/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/micromark-extension-math/node_modules/katex": { + "version": "0.16.47", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.47.tgz", + "integrity": "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/micromark-extension-mdx-expression": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.1.tgz", + "integrity": "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-jsx": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.2.tgz", + "integrity": "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdx-md": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz", + "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz", + "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==", + "license": "MIT", + "dependencies": { + "acorn": "^8.0.0", + "acorn-jsx": "^5.0.0", + "micromark-extension-mdx-expression": "^3.0.0", + "micromark-extension-mdx-jsx": "^3.0.0", + "micromark-extension-mdx-md": "^2.0.0", + "micromark-extension-mdxjs-esm": "^3.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs-esm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz", + "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.3.tgz", + "integrity": "sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-events-to-acorn": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.3.tgz", + "integrity": "sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true, + "license": "MIT" + }, + "node_modules/mocha": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", + "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^8.1.0", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9", + "yargs-unparser": "^2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/mocha/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/mocha/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/mocha/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/mocha/node_modules/diff": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.2.tgz", + "integrity": "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/mocha/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/mocha/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mocha/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/mocha/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/mocha/node_modules/yargs": { + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.2.tgz", + "integrity": "sha512-Nt9ZJjXTv5R8MHbqby/wXQ6Gi0Bb3TcYZkR1bzuL4yB2OxWPkXknz513gEF0GoA6tn00UpbPvERW8rzCuWCA6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/modern-tar": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/modern-tar/-/modern-tar-0.7.6.tgz", + "integrity": "sha512-sweCIVXzx1aIGTCdzcMlSZt1h8k5Tmk08VNAuRk3IU28XamGiOH5ypi11g6De2CH7PhYqSSnGy2A/EFhbWnVKg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/mute-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/netmask": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.1.1.tgz", + "integrity": "sha512-eonl3sLUha+S1GzTPxychyhnUzKyeQkZ7jLjKrBagJgPla13F+uQ71HgpFefyHgqrjEbCPkDArxYsjY8/+gLKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.51", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.51.tgz", + "integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/normalize-package-data": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-7.0.1.tgz", + "integrity": "sha512-linxNAT6M0ebEYZOx2tO6vBEFsVgnPpv+AVjk0wJHfaUIbq31Jm3T6vvZaarnOeWDh8ShnwXuaAyM7WT3RzErA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^8.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obug": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz", + "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/orderedmap": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-2.1.1.tgz", + "integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==", + "license": "MIT" + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pac-proxy-agent": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz", + "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.6", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "dev": true, + "license": "MIT", + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true, + "license": "(MIT AND Zlib)" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-ms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", + "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", + "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "domhandler": "^5.0.3", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-parser-stream": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz", + "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-expression-matcher": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.6.2.tgz", + "integrity": "sha512-enSlaiat05iasnzmgNxRj8reFdj3puY2QpNgP1aPIaVfT6nn9ICuPoFlKHk8EN22HcwewshO+mN2DGbkCEOtqQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/polished": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/polished/-/polished-4.3.1.tgz", + "integrity": "sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.17.8" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postcss": { + "version": "8.5.19", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.19.tgz", + "integrity": "sha512-Mz8SaolMd8nB+G13WkORcxQKHZ/NE4xXevtkJHVuG+guo9/wYKlIMTKAqGdEmYOXR2ijPjTYNHssizdaVSUNdQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pretty-ms": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz", + "integrity": "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-ms": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/property-information": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.2.0.tgz", + "integrity": "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/prosemirror-changeset": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.4.1.tgz", + "integrity": "sha512-96WBLhOaYhJ+kPhLg3uW359Tz6I/MfcrQfL4EGv4SrcqKEMC1gmoGrXHecPE8eOwTVCJ4IwgfzM8fFad25wNfw==", + "license": "MIT", + "dependencies": { + "prosemirror-transform": "^1.0.0" + } + }, + "node_modules/prosemirror-commands": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.7.1.tgz", + "integrity": "sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.10.2" + } + }, + "node_modules/prosemirror-dropcursor": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.3.tgz", + "integrity": "sha512-FoYbsJR8gK+DGlqhNoE29Loa38eIZPzQRIb1VMaDNBoo4OLP6vVof/jR8qFY/6XvUd6Dhug8MDCHl2a/h8RTfQ==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0", + "prosemirror-view": "^1.1.0" + } + }, + "node_modules/prosemirror-gapcursor": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.4.1.tgz", + "integrity": "sha512-pMdYaEnjNMSwl11yjEGtgTmLkR08m/Vl+Jj443167p9eB3HVQKhYCc4gmHVDsLPODfZfjr/MmirsdyZziXbQKw==", + "license": "MIT", + "dependencies": { + "prosemirror-keymap": "^1.0.0", + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-view": "^1.0.0" + } + }, + "node_modules/prosemirror-history": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.5.0.tgz", + "integrity": "sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.2.2", + "prosemirror-transform": "^1.0.0", + "prosemirror-view": "^1.31.0", + "rope-sequence": "^1.3.0" + } + }, + "node_modules/prosemirror-inputrules": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.5.1.tgz", + "integrity": "sha512-7wj4uMjKaXWAQ1CDgxNzNtR9AlsuwzHfdFH1ygEHA2KHF2DOEaXl1CJfNPAKCg9qNEh4rum975QLaCiQPyY6Fw==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.0.0" + } + }, + "node_modules/prosemirror-keymap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.3.tgz", + "integrity": "sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0", + "w3c-keyname": "^2.2.0" + } + }, + "node_modules/prosemirror-model": { + "version": "1.25.11", + "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.11.tgz", + "integrity": "sha512-QWg9RhnpLlogAmp3p96uEFrE5txQpFynd4vhBAELkwgOCWQs/X0yCzB3/hrHqiPwf91RG5KyWq6553zs9JqIOQ==", + "license": "MIT", + "dependencies": { + "orderedmap": "^2.0.0" + } + }, + "node_modules/prosemirror-schema-list": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.5.1.tgz", + "integrity": "sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.7.3" + } + }, + "node_modules/prosemirror-state": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.4.tgz", + "integrity": "sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-transform": "^1.0.0", + "prosemirror-view": "^1.27.0" + } + }, + "node_modules/prosemirror-tables": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.8.5.tgz", + "integrity": "sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw==", + "license": "MIT", + "dependencies": { + "prosemirror-keymap": "^1.2.3", + "prosemirror-model": "^1.25.4", + "prosemirror-state": "^1.4.4", + "prosemirror-transform": "^1.10.5", + "prosemirror-view": "^1.41.4" + } + }, + "node_modules/prosemirror-transform": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.12.0.tgz", + "integrity": "sha512-GxboyN4AMIsoHNtz5uf2r2Ru551i5hWeCMD6E2Ib4Eogqoub0NflniaBPVQ4MrGE5yZ8JV9tUHg9qcZTTrcN4w==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.21.0" + } + }, + "node_modules/prosemirror-view": { + "version": "1.42.1", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.42.1.tgz", + "integrity": "sha512-rRqzZnRgkyh69XoOMrfFJHwauHscLBmHbq772kwbic1ymQAM8gXjzEbJse5j1ep2UO2HRIAQL0bY3kZ/RoqjVw==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.25.8", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0" + } + }, + "node_modules/proxy-agent": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", + "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.6", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.1.0", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true, + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/query-selector-shadow-dom": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/query-selector-shadow-dom/-/query-selector-shadow-dom-1.0.1.tgz", + "integrity": "sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-draggable": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.7.0.tgz", + "integrity": "sha512-kTpANmKWVnFXiZ76Ag2ZowiFStuBYnJ606PI1TbUsOg29/400/JNIxI9+CuenhiAqFuXWJffz6F4UI3R51kUug==", + "license": "MIT", + "dependencies": { + "clsx": "^2.1.1", + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "react": ">= 16.3.0", + "react-dom": ">= 16.3.0" + } + }, + "node_modules/react-is": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.7.tgz", + "integrity": "sha512-kZFnouyVv7eP/Phmrlo9FK+zcAdriZJvzxXHF1Sl1P377WSGe2G/JxVolhTrB/jeV47lKImhNUsijjHAAbcl/A==", + "license": "MIT" + }, + "node_modules/react-is-18": { + "name": "react-is", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-is-19": { + "name": "react-is", + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.7.tgz", + "integrity": "sha512-kZFnouyVv7eP/Phmrlo9FK+zcAdriZJvzxXHF1Sl1P377WSGe2G/JxVolhTrB/jeV47lKImhNUsijjHAAbcl/A==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-markdown": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz", + "integrity": "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "html-url-attributes": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=18", + "react": ">=18" + } + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-resizable": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-resizable/-/react-resizable-3.2.0.tgz", + "integrity": "sha512-3NKQ0SLZV7rs3LQHeXlOzDSRQfFrkX6TVet77/Qk03zqiZyee37b7N8/gwDJAA8UUjRz7PdWCCy49hcso45SMQ==", + "license": "MIT", + "dependencies": { + "prop-types": "15.x", + "react-draggable": "^4.5.0" + }, + "peerDependencies": { + "react": ">= 16.3", + "react-dom": ">= 16.3" + } + }, + "node_modules/react-window": { + "version": "1.8.11", + "resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.11.tgz", + "integrity": "sha512-+SRbUVT2scadgFSWx+R1P754xHPEqvcfSfVX10QYg6POOz+WNgkN48pS+BtZNIMGiL1HYrSEiCkwsMS15QogEQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.0.0", + "memoize-one": ">=3.1.1 <6" + }, + "engines": { + "node": ">8.0.0" + }, + "peerDependencies": { + "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/read-pkg": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-8.1.0.tgz", + "integrity": "sha512-PORM8AgzXeskHO/WEv312k9U03B8K9JSiWF/8N9sUuFjBa+9SF2u6K7VClzXwDXab51jCd8Nd36CNM+zR97ScQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.1", + "normalize-package-data": "^6.0.0", + "parse-json": "^7.0.0", + "type-fest": "^4.2.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-10.1.0.tgz", + "integrity": "sha512-aNtBq4jR8NawpKJQldrQcSW9y/d+KWH4v24HWkHljOZ7H0av+YTGANBzRh9A5pw7v/bLVsLVPpOhJ7gHNVy8lA==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^6.3.0", + "read-pkg": "^8.1.0", + "type-fest": "^4.2.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/read-pkg-up/node_modules/yocto-queue": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", + "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/read-pkg/node_modules/json-parse-even-better-errors": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz", + "integrity": "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-pkg/node_modules/lines-and-columns": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.4.tgz", + "integrity": "sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/read-pkg/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", + "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/read-pkg/node_modules/parse-json": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-7.1.1.tgz", + "integrity": "sha512-SgOTCX/EZXtZxBE5eJ97P4yGM5n37BwRU+YMsH4vNzFqJV/oWFXXCmwFlgWUM4PrakybVOueJJ6pwHqSVhTFDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.21.4", + "error-ex": "^1.3.2", + "json-parse-even-better-errors": "^3.0.0", + "lines-and-columns": "^2.0.3", + "type-fest": "^3.8.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg/node_modules/parse-json/node_modules/type-fest": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", + "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dev": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/readdir-glob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.1.0" + } + }, + "node_modules/readdir-glob/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/recma-build-jsx": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz", + "integrity": "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-build-jsx": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-jsx": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/recma-jsx/-/recma-jsx-1.0.1.tgz", + "integrity": "sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==", + "license": "MIT", + "dependencies": { + "acorn-jsx": "^5.0.0", + "estree-util-to-js": "^2.0.0", + "recma-parse": "^1.0.0", + "recma-stringify": "^1.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/recma-parse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-parse/-/recma-parse-1.0.0.tgz", + "integrity": "sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "esast-util-from-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-stringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-stringify/-/recma-stringify-1.0.0.tgz", + "integrity": "sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-to-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/recursive-readdir/node_modules/brace-expansion": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", + "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/recursive-readdir/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/rehype-katex": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/rehype-katex/-/rehype-katex-7.0.1.tgz", + "integrity": "sha512-OiM2wrZ/wuhKkigASodFoo8wimG3H12LWQaH8qSPVJn9apWKFSH3YOCtbKpBorTVw/eI7cuT21XBbvwEswbIOA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/katex": "^0.16.0", + "hast-util-from-html-isomorphic": "^2.0.0", + "hast-util-to-text": "^4.0.0", + "katex": "^0.16.0", + "unist-util-visit-parents": "^6.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/rehype-katex/node_modules/katex": { + "version": "0.16.47", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.47.tgz", + "integrity": "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/rehype-recma": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rehype-recma/-/rehype-recma-1.0.0.tgz", + "integrity": "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "hast-util-to-estree": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", + "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-math": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/remark-math/-/remark-math-6.0.0.tgz", + "integrity": "sha512-MMqgnP74Igy+S3WwnhQ7kqGlEerTETXMvJhrUzDikVZ2/uogJCb+WHUg97hK9/jcfc0dkD73s3LN8zU49cTEtA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-math": "^3.0.0", + "micromark-extension-math": "^3.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-mdx": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.1.tgz", + "integrity": "sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==", + "license": "MIT", + "dependencies": { + "mdast-util-mdx": "^3.0.0", + "micromark-extension-mdxjs": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resq": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/resq/-/resq-1.11.0.tgz", + "integrity": "sha512-G10EBz+zAAy3zUd/CDoBbXRL6ia9kOo3xRHrMDsHljI0GDkhYlyjwoCx5+3eCC4swi1uCoZQhskuJkj7Gp57Bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^2.0.1" + } + }, + "node_modules/ret": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.5.0.tgz", + "integrity": "sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/rgb2hex": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/rgb2hex/-/rgb2hex-0.2.5.tgz", + "integrity": "sha512-22MOP1Rh7sAo1BZpDG6R5RFYzR2lYEgwq7HEmyW2qcsOqR2lQKmn+O//xV3YG/0rrhMC6KVX2hU+ZXuaw9a5bw==", + "dev": true, + "license": "MIT" + }, + "node_modules/rollup": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.2.tgz", + "integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.62.2", + "@rollup/rollup-android-arm64": "4.62.2", + "@rollup/rollup-darwin-arm64": "4.62.2", + "@rollup/rollup-darwin-x64": "4.62.2", + "@rollup/rollup-freebsd-arm64": "4.62.2", + "@rollup/rollup-freebsd-x64": "4.62.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.2", + "@rollup/rollup-linux-arm-musleabihf": "4.62.2", + "@rollup/rollup-linux-arm64-gnu": "4.62.2", + "@rollup/rollup-linux-arm64-musl": "4.62.2", + "@rollup/rollup-linux-loong64-gnu": "4.62.2", + "@rollup/rollup-linux-loong64-musl": "4.62.2", + "@rollup/rollup-linux-ppc64-gnu": "4.62.2", + "@rollup/rollup-linux-ppc64-musl": "4.62.2", + "@rollup/rollup-linux-riscv64-gnu": "4.62.2", + "@rollup/rollup-linux-riscv64-musl": "4.62.2", + "@rollup/rollup-linux-s390x-gnu": "4.62.2", + "@rollup/rollup-linux-x64-gnu": "4.62.2", + "@rollup/rollup-linux-x64-musl": "4.62.2", + "@rollup/rollup-openbsd-x64": "4.62.2", + "@rollup/rollup-openharmony-arm64": "4.62.2", + "@rollup/rollup-win32-arm64-msvc": "4.62.2", + "@rollup/rollup-win32-ia32-msvc": "4.62.2", + "@rollup/rollup-win32-x64-gnu": "4.62.2", + "@rollup/rollup-win32-x64-msvc": "4.62.2", + "fsevents": "~2.3.2" + } + }, + "node_modules/rope-sequence": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz", + "integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==", + "license": "MIT" + }, + "node_modules/run-async": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-4.0.6.tgz", + "integrity": "sha512-IoDlSLTs3Yq593mb3ZoKWKXMNu3UpObxhgA/Xuid5p4bbfi2jdY1Hj0m1K+0/tEuQTxIGMhQDqGjKb7RuxGpAQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safaridriver": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safaridriver/-/safaridriver-1.0.1.tgz", + "integrity": "sha512-jkg4434cYgtrIF2AeY/X0Wmd2W73cK5qIEFE3hDrrQenJH/2SDJIXGvPAigfvQTcE9+H31zkiNHbUqcihEiMRA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-regex2": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-5.1.1.tgz", + "integrity": "sha512-mOSBvHGDZMuIEZMdOz/aCEYDCv0E7nfcNsIhUF+/P+xC7Hyf3FkvymqgPbg9D1EdSGu+uKbJgy09K/RKKc7kJA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "ret": "~0.5.0" + }, + "bin": { + "safe-regex2": "bin/safe-regex2.js" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/scroll-into-view-if-needed": { + "version": "2.2.31", + "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz", + "integrity": "sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==", + "license": "MIT", + "dependencies": { + "compute-scroll-into-view": "^1.0.20" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/serialize-error": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-12.0.0.tgz", + "integrity": "sha512-ZYkZLAvKTKQXWuh5XpBw7CdbSzagarX39WyZ2H07CDLC5/KfsRGlIXV8d4+tfqX1M7916mRqR1QfNHSij+c9Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^4.31.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true, + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/smol-toml": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.7.0.tgz", + "integrity": "sha512-aqVvWoyO21L23mb+drl4RmMXbf6N7FdHjAhTRA9ZBL7apWBgfWC16KjrASI+1p9GAroljyMHj6fK67i0UiTNvQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 18" + }, + "funding": { + "url": "https://github.com/sponsors/cyyynthia" + } + }, + "node_modules/socks": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.9.tgz", + "integrity": "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ip-address": "^10.1.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/spacetrim": { + "version": "0.11.59", + "resolved": "https://registry.npmjs.org/spacetrim/-/spacetrim-0.11.59.tgz", + "integrity": "sha512-lLYsktklSRKprreOm7NXReW8YiX2VBjbgmXYEziOoGf/qsJqAEACaDvoTtUOycwjpaSh+bT8eu0KrJn7UNxiCg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://buymeacoffee.com/hejny" + }, + { + "type": "github", + "url": "https://github.com/hejny/spacetrim/blob/main/README.md#%EF%B8%8F-contributing" + } + ], + "license": "Apache-2.0" + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", + "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", + "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", + "dev": true, + "license": "MIT" + }, + "node_modules/stream-buffers": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-3.0.3.tgz", + "integrity": "sha512-pqMqwQCso0PBJt2PQmDO0cFj0lyqmiwOMiMSkVtRokl7e+ZTRYgDHKnuZNbqjiJXgsg4nuqtD/zxuo9KqTp0Yw==", + "dev": true, + "license": "Unlicense", + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/streamx": { + "version": "2.28.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.28.0.tgz", + "integrity": "sha512-1Yowhzjf0ivGMrTIkY9hav5TxobO9qIVqUE41fiCGMGgc3CLlf4MY+9AHmZqBWgDTue0fY9zWjYFVyf6Diuobw==", + "dev": true, + "license": "MIT", + "dependencies": { + "events-universal": "^1.0.0", + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/strip-final-newline": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", + "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strnum": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.4.1.tgz", + "integrity": "sha512-M9eUSMT2dCB2cTNPG7UYj6KuK7RJR2SN2+yCV/fTW3xzTCS6EaGZ5pSMgDIjB7r8zSfTGk+dvvn9rTjpVS9Mwg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "anynum": "^1.0.1" + } + }, + "node_modules/style-to-js": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz", + "integrity": "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==", + "license": "MIT", + "dependencies": { + "style-to-object": "1.0.14" + } + }, + "node_modules/style-to-object": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz", + "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.7" + } + }, + "node_modules/stylis": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.4.0.tgz", + "integrity": "sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==", + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tar-fs": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.3.tgz", + "integrity": "sha512-/hU4AXnIdZu+Gvl1pk0oI5f5HxWsCJRtY2aFaJdk9VvyL48DWU6iU5WAIPG+wIi1YvWA6eTJvIviP/tMAZZNwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^4.0.1", + "bare-path": "^3.0.0" + } + }, + "node_modules/tar-stream": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.2.0.tgz", + "integrity": "sha512-ojzvCvVaNp6aOTFmG7jaRD0meowIAuPc3cMMhSgKiVWws1GyHbGd/xvnyuRKcKlMpt3qvxx6r0hreCNITP9hIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "bare-fs": "^4.5.5", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/teex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", + "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "streamx": "^2.12.5" + } + }, + "node_modules/text-decoder": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", + "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", + "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyrainbow": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", + "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsx": { + "version": "4.23.1", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.1.tgz", + "integrity": "sha512-GQHnkIfxyx1wYCOS/wonik5MVRZU9hi1TEZmzGZSCJB1y9YgoZ8H6itNE/u4suE+yLmOzuE4E5S4TZ/ZX2wcWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.28.0" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici": { + "version": "6.27.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.27.0.tgz", + "integrity": "sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-find-after": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", + "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz", + "integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", + "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/urlpattern-polyfill": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.1.0.tgz", + "integrity": "sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw==", + "dev": true, + "license": "MIT" + }, + "node_modules/use-merge-value": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-merge-value/-/use-merge-value-1.2.0.tgz", + "integrity": "sha512-DXgG0kkgJN45TcyoXL49vJnn55LehnrmoHc7MbKi+QDBvr8dsesqws8UlyIWGHMR+JXgxc1nvY+jDGMlycsUcw==", + "license": "MIT", + "peerDependencies": { + "react": ">= 16.x" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/userhome": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/userhome/-/userhome-1.0.1.tgz", + "integrity": "sha512-5cnLm4gseXjAclKowC4IjByaGsjtAoV6PrOQOljplNB54ReUYJP8HdAFq2muHinSDAh09PPX/uXDPfdxRHvuSA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/utility-types": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz", + "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-location": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vite": { + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.3.tgz", + "integrity": "sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/vitest": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.10.tgz", + "integrity": "sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.10", + "@vitest/mocker": "4.1.10", + "@vitest/pretty-format": "4.1.10", + "@vitest/runner": "4.1.10", + "@vitest/snapshot": "4.1.10", + "@vitest/spy": "4.1.10", + "@vitest/utils": "4.1.10", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.10", + "@vitest/browser-preview": "4.1.10", + "@vitest/browser-webdriverio": "4.1.10", + "@vitest/coverage-istanbul": "4.1.10", + "@vitest/coverage-v8": "4.1.10", + "@vitest/ui": "4.1.10", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, + "node_modules/vitest/node_modules/@vitest/pretty-format": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.10.tgz", + "integrity": "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest/node_modules/@vitest/snapshot": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.10.tgz", + "integrity": "sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.10", + "@vitest/utils": "4.1.10", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/vitest/node_modules/tinyrainbow": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", + "license": "MIT" + }, + "node_modules/wait-port": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/wait-port/-/wait-port-1.1.0.tgz", + "integrity": "sha512-3e04qkoN3LxTMLakdqeWth8nih8usyg+sf1Bgdf9wwUkp05iuK1eSY/QpLvscT/+F/gA89+LpUmmgBtesbqI2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "commander": "^9.3.0", + "debug": "^4.3.4" + }, + "bin": { + "wait-port": "bin/wait-port.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/wait-port/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wait-port/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/wait-port/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/wait-port/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/webdriver": { + "version": "9.29.1", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-9.29.1.tgz", + "integrity": "sha512-uhxYap3qQXC9H2V8SDr7vcy0blZETeri4goLwbw1TFq4EZHF1Dv503Zc0PAjfkNQJCD4/rzAyr07+EX72kx1pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "^20.1.0", + "@types/ws": "^8.5.3", + "@wdio/config": "9.29.1", + "@wdio/logger": "9.29.1", + "@wdio/protocols": "9.29.1", + "@wdio/types": "9.29.1", + "@wdio/utils": "9.29.1", + "deepmerge-ts": "^7.0.3", + "https-proxy-agent": "^7.0.6", + "undici": "^6.21.3", + "ws": "^8.8.0" + }, + "engines": { + "node": ">=18.20.0" + } + }, + "node_modules/webdriverio": { + "version": "9.29.1", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-9.29.1.tgz", + "integrity": "sha512-UIplAnvbjdE0tucHVR/8Uk0Y7rz72VaEx/s0Tq91fMdXm+m+Za16e+b5tObh4xEEfyCITODPfzgBva9rA+xApQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "^20.11.30", + "@types/sinonjs__fake-timers": "^8.1.5", + "@wdio/config": "9.29.1", + "@wdio/logger": "9.29.1", + "@wdio/protocols": "9.29.1", + "@wdio/repl": "9.16.2", + "@wdio/types": "9.29.1", + "@wdio/utils": "9.29.1", + "archiver": "^7.0.1", + "aria-query": "^5.3.0", + "cheerio": "^1.0.0-rc.12", + "css-shorthand-properties": "^1.1.1", + "css-value": "^0.0.1", + "grapheme-splitter": "^1.0.4", + "htmlfy": "^0.8.1", + "is-plain-obj": "^4.1.0", + "jszip": "^3.10.1", + "lodash.clonedeep": "^4.5.0", + "lodash.zip": "^4.2.0", + "query-selector-shadow-dom": "^1.0.1", + "resq": "^1.11.0", + "rgb2hex": "0.2.5", + "serialize-error": "^12.0.0", + "urlpattern-polyfill": "^10.0.0", + "webdriver": "9.29.1" + }, + "engines": { + "node": ">=18.20.0" + }, + "peerDependencies": { + "puppeteer-core": ">=22.x || <=24.x" + }, + "peerDependenciesMeta": { + "puppeteer-core": { + "optional": true + } + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/workerpool": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.21.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.1.tgz", + "integrity": "sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-naming": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.3.0.tgz", + "integrity": "sha512-ghig2TBE/H11aOVgmahA3MhimvkBr6JIYknH/Dhdk10nXwdbIqBJsbfMxpvFPG8bAw77gN29aQWvKpmVoPlvPQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs": { + "version": "17.7.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", + "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser/node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs-unparser/node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yauzl/node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yoctocolors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", + "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yoctocolors-cjs": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz", + "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zip-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz", + "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "archiver-utils": "^5.0.0", + "compress-commons": "^6.0.2", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/zustand": { + "version": "5.0.14", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.14.tgz", + "integrity": "sha512-/8tAspM5LMPr28b3fwLYrtdj77ECpfZviaP75CMTnwO8ISyaE4GDIG/9rDDYq/cH9D2Xw2A2RXglLInmVBQB/g==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/frontends/desktop/package.json b/frontends/desktop/package.json index 49acb8f38..e53ff088c 100644 --- a/frontends/desktop/package.json +++ b/frontends/desktop/package.json @@ -1,10 +1,70 @@ { - "name": "genericagent-web2", - "version": "0.1.8", + "name": "genericagent-desktop", + "private": true, + "version": "0.2.0", + "type": "module", "scripts": { - "tauri": "tauri" + "dev": "vite", + "build": "vite build", + "preview": "vite preview", + "typecheck": "tsc --noEmit", + "test:ci-contract": "node scripts/verify-ci-contract.mjs", + "test": "vitest run", + "test:bridge": "vitest run src/__tests__/bridge/", + "test:stress": "vitest run src/__tests__/stress/", + "test:bundle": "node scripts/assert-dist-built.mjs", + "test:packaging": "node scripts/test-packaging.mjs", + "test:e2e-isolation": "npm run build && node scripts/assert-production-e2e-isolation.mjs", + "test:e2e-types": "tsc -p tsconfig.e2e.json", + "test:all": "vitest run && node scripts/assert-dist-built.mjs", + "e2e:browser": "tsx e2e/run.ts --mode=browser", + "e2e:desktop": "tsx e2e/run.ts --mode=desktop", + "e2e:desktop:full": "tsx e2e/run.ts --mode=desktop --suite=full", + "e2e:canary": "tsx e2e/canary.ts", + "e2e:doctor": "tsx e2e/doctor.ts", + "tauri": "tauri", + "build:dmg": "tauri build --bundles dmg && bash scripts/post-dmg.sh src-tauri/target/release/bundle/dmg/*.dmg", + "build:app": "tauri build --bundles app", + "postbuild:dmg": "bash scripts/post-dmg.sh src-tauri/target/release/bundle/dmg/*.dmg" + }, + "dependencies": { + "@douyinfe/semi-icons": "^2.71.1", + "@douyinfe/semi-ui": "^2.71.1", + "@lobehub/icons": "^5.10.1", + "@types/prismjs": "^1.26.6", + "@vscode/codicons": "^0.0.45", + "katex": "^0.17.0", + "prismjs": "^1.30.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-markdown": "^10.1.0", + "rehype-katex": "^7.0.1", + "remark-gfm": "^4.0.1", + "remark-math": "^6.0.0", + "zustand": "^5.0.14" }, "devDependencies": { - "@tauri-apps/cli": "^2" + "@tauri-apps/cli": "^2", + "@testing-library/dom": "^10.4.1", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.2", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "@vitejs/plugin-react": "^4.3.4", + "@wdio/cli": "^9.29.1", + "@wdio/local-runner": "^9.29.1", + "@wdio/mocha-framework": "^9.29.1", + "@wdio/spec-reporter": "^9.29.1", + "@wdio/tauri-plugin": "^1.2.0", + "@wdio/tauri-service": "^1.2.0", + "happy-dom": "^20.10.6", + "tsx": "^4.23.1", + "typescript": "^5.6.3", + "vite": "^6.0.5", + "vitest": "^4.1.9", + "webdriverio": "^9.29.1" + }, + "overrides": { + "@wdio/native-utils": "2.5.0" } } diff --git a/frontends/desktop/public/assets/fonts/azonix-wordmark.woff2 b/frontends/desktop/public/assets/fonts/azonix-wordmark.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..947bfbebca88ae495253f19f8b679b6929e55dd3 GIT binary patch literal 6848 zcmV;x8b9TCPew9NR8&s@02;sm3;+NC052>602*=t0RR9100000000000000000000 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∓Jw5)|1+k+LPLo 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 literal 0 HcmV?d00001 diff --git a/frontends/desktop/public/assets/fonts/noto-sans-latin.woff2 b/frontends/desktop/public/assets/fonts/noto-sans-latin.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..e082930455df9ca4195fa8274dbb1a9c1546d640 GIT binary patch literal 35856 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 literal 0 HcmV?d00001 diff --git a/frontends/desktop/public/assets/ga-logo.svg b/frontends/desktop/public/assets/ga-logo.svg new file mode 100644 index 000000000..a4d456c14 --- /dev/null +++ b/frontends/desktop/public/assets/ga-logo.svg @@ -0,0 +1,58 @@ + + GenericAgent + + + diff --git a/frontends/desktop/public/fallback.html b/frontends/desktop/public/fallback.html new file mode 100644 index 000000000..0be15ecb4 --- /dev/null +++ b/frontends/desktop/public/fallback.html @@ -0,0 +1,267 @@ + + + + + +GenericAgent — Fix startup + + + +

+

修复启动问题

+

检查下面的位置,然后重试。你的记忆、会话和配置不会受到影响。

+ + + + + + + + + +
+ 诊断信息 +
+ + +
+
GenericAgent Desktop startup diagnostics
+

诊断信息包含本机路径和错误日志,不包含 API Key、会话或记忆内容。

+
+
+ + + diff --git a/frontends/desktop/public/i18n.js b/frontends/desktop/public/i18n.js new file mode 100644 index 000000000..0c90a9f9e --- /dev/null +++ b/frontends/desktop/public/i18n.js @@ -0,0 +1,496 @@ +(() => { + const I18N = { + zh: { + 'app.title': 'GenericAgent 桌面版', + 'brand.sub': '桌面终端', + 'nav.chat': '聊天', 'nav.services': '后台服务', 'nav.channels': '消息通道', 'nav.status': '状态面板', + 'nav.collab': '指挥家', 'nav.token': '用量', + 'foot.settings': '配置', 'foot.ver': 'GenericAgent · 桌面版', + 'chat.startTitle': '开始对话', 'chat.startSub': '直接输入,或点预设功能一键启动', + 'preset.butler.t': '指挥家', 'preset.butler.d': '复杂任务自动拆解,只需查看进度和简报', + 'preset.plan.t': 'Plan 模式', 'preset.plan.d': '加载 Plan SOP,按探索→规划→执行→验证流程', + 'preset.goal.t': 'Goal 模式', 'preset.goal.d': '设定目标,自主完成', + 'preset.autonomous.t': '自主行动', 'preset.autonomous.d': '按 SOP 规划/执行任务,产出报告(reflect/autonomous.py 同源)', + 'preset.hive.t': 'Hive 协作', 'preset.hive.d': '多 worker 协同攻坚', + 'preset.review.t': '深度复核', 'preset.review.d': '挑刺式质量把关', + 'preset.findwork.t': '找点事做', 'preset.findwork.d': '分析当前情况,推荐一批让你感兴趣的 TODO', + 'preset.mine.t': '我的·周报', 'preset.mine.d': '自定义:抓本周提交并写周报', + 'preset.add.t': '自定义', 'preset.add.d': '任意一句话存为功能', + 'composer.placeholder': 'GA 能帮你做些什么?', + 'search.placeholder': '搜索会话…', 'conv.new': '新对话', + 'ctx.pin': '置顶', 'ctx.unpin': '取消置顶', 'ctx.rename': '重命名', 'ctx.del': '删除', + 'common.close': '关闭', 'common.more': '更多', 'common.optional': '选填', 'common.save': '保存', + 'modal.preset': '预设功能', 'modal.addModel': '添加模型', 'modal.editModel': '编辑模型', 'modal.settings': '配置', + 'modal.customPreset': '自定义预设', + 'modal.editCustomPreset': '编辑任务', + 'customPreset.titlePh': '标题,例如「写周报」', + 'customPreset.promptPh': 'Prompt 内容,发送时会作为消息提交', + 'customPreset.empty': '标题和 Prompt 不能为空', + 'customPreset.removeTitle': '删除', + 'customPreset.editTitle': '编辑', + 'builtinPreset.restoreBtn': '恢复默认预设', + 'set.appearance': '外观', 'set.plainUi': '素色', 'set.fontSize': '聊天字号', 'set.lang': '语言', 'set.model': '模型', 'set.addModel': '添加模型', 'set.features': '功能', 'set.importMykey': '导入已有模型配置(mykey.py)', 'set.exportMykey': '导出当前模型配置', 'set.importMemory': '导入已有记忆与会话记录(选择 GenericAgent 根目录)', 'set.gaSource': '接入独立 GenericAgent 源码(把桌面版当作壳)', 'set.gaSourceClear': '取消接入,改用内置版本', 'set.gaSourceCurrent': '当前接入', 'set.serviceManager': '后台服务管理', + 'shortcut.askConfirm': '是否在桌面创建 GenericAgent 快捷方式?', + 'appearance.light': '浅色', 'appearance.dark': '深色', + 'set.noModels': '暂无模型,点击下方添加', + 'lang.zh': '简体中文', 'lang.en': 'English', + 'model.name': '备注', 'model.namePh': '会显示在模型列表', + 'model.apikey': 'API Key', 'model.apikeyPh': 'sk-...', 'model.apikeyKeep': '留空则保持原 Key 不变', + 'model.apibase': 'API 地址', 'model.apibasePh': 'https://.../v1/messages', + 'model.protocol': '协议', 'model.protocolPick': '请选择…', 'model.protocolOai': 'OpenAI 兼容 (chat/completions)', 'model.protocolClaude': 'Anthropic (Claude /v1/messages)', + 'model.stream': '响应方式', 'model.streamOn': '流式', 'model.streamOff': '非流式', + 'model.model': '模型', 'model.modelPh': 'model 参数名', + 'model.modelHint': '须与中转站/官方文档中的 model 字段完全一致', + 'model.retries': '重试 (次)', 'model.connTimeout': '连接超时 (s)', 'model.readTimeout': '读取超时 (s)', + 'model.save': '保存', 'common.cancel': '取消', 'common.confirm': '确认', 'common.edit': '编辑', 'common.delete': '删除', + 'pq.title': '快速接入官方模型', 'pq.sub': '填好 API Key 即可使用', 'pq.toggle': '展开 / 收起', + 'pq.deepseekDesc': '官方 API · OpenAI 兼容', 'pq.qwenDesc': '通义千问 · 阿里云百炼', + 'guide.step1': '点击下方链接,登录后创建并复制 API Key', + 'guide.step2': '把 Key 粘贴到下方「API Key」输入框', + 'guide.step3': '点击保存,即可在模型列表中选用', + 'guide.prefillTip': '已为你预填 API 地址、协议与模型,可按需修改', + 'guide.getKey': '获取 {name} 的 API Key', 'guide.copy': '复制链接', 'guide.copied': '链接已复制', + 'err.modelSave': '保存失败', 'err.modelSwitch': '切换模型失败', 'err.modelRequired': '请填写模型、API Key 和 API 地址', + 'err.modelDelete': '删除失败', 'err.modelDeleteLast': '至少保留一个模型', + 'confirm.modelDelete': '确定删除该模型配置?', + 'model.aggregation': '渠道组(自动故障转移)', 'model.aggregationShort': '渠道组', 'model.aggregationDesc': '按顺序尝试,失败自动切换到下一个', + 'model.emptyMixin': '尚未加入模型', + 'model.addToMixin': '加入渠道组', 'model.inMixin': '已在渠道组', 'model.removeFromMixin': '移出渠道组', 'model.alreadyInMixin': '已在渠道组中', 'model.dragReorder': '拖拽调整顺序', + 'err.mixinFailed': '操作失败', + 'page.services.title': '后台服务', 'page.services.sub': 'IM 消息通道与后台进程,集中查看、启停与日志', + 'page.channels.title': '消息通道', 'page.channels.sub': '后台 IM 进程:列表、启停与日志(同 hub.pyw)', + 'page.status.title': '状态面板', 'page.status.sub': 'hub.pyw 管理的后台进程/服务,集中查看与启停', + 'page.collab.title': '指挥家', 'page.collab.sub': '交代目标,自动拆活与跟进', + 'collab.progressTitle': '分工进度', + 'collab.progressEmpty': '还没有任务在执行。告诉指挥家你的目标后,这里会显示拆分后的处理进度。', + 'collab.placeholder': '请对指挥家描述你想完成的目标', + 'collab.guideTitle': '把要完成的事告诉指挥家', + 'collab.guideWhen': '适合需要多步处理、要花一些时间才能完成的目标。日常聊天和快问快答,请用左侧「聊天」。', + 'collab.guideStep1t': '描述目标', + 'collab.guideStep1d': '在聊天框里写下你想做的事,发给指挥家', + 'collab.guideStep2t': '自动拆解', + 'collab.guideStep2d': '指挥家自动拆解、分配任务,实时监督和调度', + 'collab.guideStep3t': '交付摘要', + 'collab.guideStep3d': '指挥家根据执行状态,呈上任务简报', + 'collab.guideStep4t': '随时调整', + 'collab.guideStep4d': '随时补充要求或细节,指挥家都会处理', + 'collab.chipProgress': '现在进展如何?', + 'collab.chipPause': '先暂停当前任务', + 'collab.chipSummary': '总结一下目前的结果', + 'collab.showProgressTitle': '查看分工进度', + 'collab.statRunning': '进行中', + 'collab.statDone': '已完成', + 'collab.plusMenu': '更多操作', + 'collab.switchMode': '切换模式', + 'collab.typing': '指挥家正在处理', + 'collab.offline': '无法连接指挥家服务,请确认后端已启动。', + 'collab.retry': '重试', + 'collab.reconnect': '连接断开,正在重连… 已保留上次任务进度。', + 'collab.reconnectIn': '{n} 秒后重试', + 'collab.stRunning': '执行中', 'collab.stReported': '已回报', 'collab.stPaused': '已暂停', + 'collab.stFailed': '遇到问题', 'collab.stTerminated': '已终止', + 'collab.summaryRunning': '正在处理中…', 'collab.summaryWait': '等待回报', + 'collab.taskFallback': '任务 {n}', + 'collab.timeJust': '刚刚', + 'collab.timeSec': '{n} 秒前', + 'collab.timeMin': '{n} 分钟前', + 'collab.timeHr': '{n} 小时前', + 'collab.timeDay': '{n} 天前', + 'page.token.title': '用量', 'page.token.sub': '每会话与累计用量及缓存率', + 'status.connecting': '正在连接…', 'status.ready': '服务在线', 'status.running': '处理中', + 'status.disconnected': '服务离线', 'status.stopped': '已停止', 'status.idle': '待命', + 'conv.emptyList': '暂无会话,点「+ 新对话」开始', 'conv.defaultTitle': '新对话', + 'err.bridge': '服务未响应', 'err.newSession': '新建会话失败', 'err.poll': '轮询失败', 'err.stop': '停止失败', + 'err.interruptTimeout': '等待上一轮停止超时,请稍后再试', + 'sys.interruptPrev.hint': '已停止上一轮,正在处理新消息', + 'chat.interrupting': '正在停止上一轮…', + 'chat.sessionLoading': '正在加载会话…', + 'sys.stopRequested': '已请求停止', + 'slash.help': '可用命令:\n/new 新会话 /clear 清屏 /stop 停止 /settings 设置', + 'slash.unknown': '未知命令', + 'upload.hint': '上传文件:选择 / 拖拽 / 粘贴', + 'upload.button': '上传文件', + 'upload.tooLarge': '文件过大或数量超限', 'upload.empty': '跳过空文件', + 'upload.failed': '上传失败', + 'err.charLimit': '已达字数上限({n}),发送时将自动截断', 'err.charLimitReached': '已达字数上限({n})', 'err.numMax': '不能超过 {n}', + 'file.openFailed': '无法打开文件', + 'file.kindGeneric': '文件', + 'file.kindDoc': '文档', + 'file.kindSheet': '表格', + 'file.kindSlide': '幻灯片', + 'file.kindCode': '代码', + 'file.kindArchive': '压缩包', + 'file.kindAudio': '音频', + 'file.kindVideo': '视频', + 'upload.removeTitle': '移除', + 'upload.dropHint': '松开以上传文件', + 'lightbox.closeTitle': '关闭', + 'fold.thinking': '思考', 'fold.tool': '工具调用', 'fold.toolResult': '工具结果', 'fold.llm': 'LLM Running', 'fold.turn': '第 {n} 轮', + 'plan.header': '计划 ({done}/{total})', 'plan.complete': '✓ 计划完成 ({n}/{n})', + 'plan.running': '计划执行中', 'plan.completeTitle': '计划完成', + 'plan.placeholder': '计划模式已激活', 'plan.waiting': '等待写入 {path} …', 'plan.overflow': '还有 {n} 项', + 'plan.current': '当前', 'plan.fold': '折叠', 'plan.collapse': '收起', 'plan.expand': '展开', 'plan.details': '详情', 'plan.dismiss': '不再显示', + 'plan.capsuleRunning': '运行中', 'plan.capsuleComplete': '已完成', + 'timing.elapsed': '已运行 {t}', + 'model.auto': '自动选择', + 'model.menuLabel': '选择模型', + 'chip.plan': 'Plan', + 'chip.auto': 'Auto', + 'ch.wechat': '微信', 'ch.wecom': '企业微信', 'ch.lark': '飞书', 'ch.dingtalk': '钉钉', + 'ch.qq': 'QQ', 'ch.telegram': 'Telegram', 'ch.discord': 'Discord', + 'ch.loading': '加载中…', 'ch.empty': '未发现 IM 进程脚本', + 'ch.logEmpty': '暂无日志', + 'err.channelLoad': '加载失败', 'err.channelStart': '启动失败', 'err.channelStop': '停止失败', + 'err.mykeyImport': '导入模型配置失败', + 'err.mykeyExport': '导出模型配置失败', + 'err.channelNotConfigured': '请先在 mykey.py 中配置该平台', + 'sys.channelStarted': '已启动', 'sys.channelStopped': '已停止', + 'modal.channelLogs': '进程日志', + 'modal.mykeyConfig': 'mykey.py 配置', + 'sys.configSaved': '配置已保存', + 'sys.mykeyImported': '模型配置已导入', + 'sys.mykeyExported': '模型配置已导出', + 'sys.memoryImported': '记忆已导入', + 'err.memoryImport': '导入记忆失败', + 'sys.memoryImportBackup': '原记忆已备份至', + 'sys.memorySessions': '会话', + 'sys.gaSourcePickTitle': '选择要接入的 GenericAgent 源码根目录(含 agentmain.py)', + 'sys.gaSourceSwitching': '正在切换并重启后端...', + 'sys.gaSourceSet': '已接入独立 GenericAgent', + 'sys.gaSourceCleared': '已取消接入,恢复内置版本', + 'err.gaSourceSet': '接入失败', + 'err.gaSourceDesktopOnly': '此功能仅在桌面版中可用', + 'sys.memoryPickTitle': '选择 GenericAgent 根目录(包含 memory 与 temp 的目录)', + 'sys.memoryImportPrompt': '请输入 GenericAgent 根目录的完整路径(包含 memory 与 temp 的目录,而非 memory 文件夹本身):', + 'st.starting': '启动中…', 'st.stopping': '停止中…', 'st.online': '在线', 'st.offline': '离线', 'st.error': '错误', 'st.running': '运行', 'st.abnormal': '异常', 'st.missingDeps': '待安装', + 'act.configure': '配置', 'act.logs': '日志', 'act.restart': '重启', 'act.stop': '停止', 'act.start': '启动', 'act.exit': '退出', 'act.installDeps': '安装依赖', 'act.installing': '安装中…', + 'act.copy': '复制', 'act.copied': '已复制', 'act.copyTex': 'TeX', 'act.send': '发送', + 'sys.depsInstalled': '依赖安装完成', 'err.installDeps': '安装失败', + 'proc.imbotWechat': 'imbot · 微信', 'proc.imbotDing': 'imbot · 钉钉', 'proc.scheduler': '定时任务调度', 'proc.conductor': '指挥家', + 'cm.scheduling': '调度中', 'cm.running': '执行中', 'cm.idleSt': '空闲', + 'cm.master': '已派 3 子任务', 'cm.w1': '子任务:抓取数据', 'cm.w2': '子任务:复核结果', 'cm.sub': '等待派单', + 'tok.total': '累计', 'tok.cost': '缓存率', 'tok.today': '今日', 'tok.tabAll': '聊天', 'tok.tabConductor': '指挥家', 'tok.condTotal': '指挥家累计', 'tok.condCurrent': '指挥家本次', 'tok.condTip': '指挥家消耗不计入聊天累计', 'tok.condOffline': '指挥家服务离线', 'tok.disclaimer': '不同 API 网站的计费价格可能会有差异,请以实际网站为准。', + 'tok.colSession': '会话', 'tok.colIn': '输入', 'tok.colOut': '输出', 'tok.colCacheW': '缓存写入', 'tok.colCache': '缓存读取', 'tok.colCost': '成本', + 'tok.from': '从', 'tok.to': '到', 'tok.reset': '重置', 'tok.noData': '暂无记录', 'tok.deleted': '此会话已删除', + 'tok.pricingUnknown': '⚠ 此模型计费规则尚未明确,按默认估算', + 'tok.priceInput': '输入: $', 'tok.priceOutput': '输出: $', + 'tok.priceCacheW': '缓存写入: $', 'tok.priceCacheR': '缓存读取: $', + 'presetPrompt.goal': '进入 Goal 模式:读 L3 goal mode SOP,自主达成我接下来描述的目标。', + 'presetPrompt.plan': '进入 Plan 模式:先读 memory/plan_sop.md,按其中「探索→规划→执行→验证」流程,等我接下来描述要做的任务。', + 'presetPrompt.autonomous': '🤖 进入自主行动模式:阅读 memory/autonomous_operation_sop.md,按 SOP 选取或规划任务,独立执行并产出报告。', + 'presetPrompt.hive': '启动 Goal Hive 模式:按 hive SOP 拉起多个 worker 协同完成我接下来的目标。', + 'presetPrompt.review': '进入监察者模式:对刚才的产出严格挑刺、逐项复核并报告问题。', + 'presetPrompt.findwork': '按照自主行动的规划部分,充分分析我的情况,给我生成一批 TODO,务必让我感兴趣。', + 'presetPrompt.mine': '抓取本周的 git 提交并写一份周报。', + 'ask.banner': 'GA 等你回答', + 'ask.replyHint': '在下方输入框回复', + 'ask.placeholderOpen': '在此输入你的回答… (Enter 发送)', + }, + en: { + 'app.title': 'GenericAgent Desktop', + 'brand.sub': 'Desktop terminal', + 'nav.chat': 'Chat', 'nav.services': 'Services', 'nav.channels': 'Channels', 'nav.status': 'Status', + 'nav.collab': 'Conductor', 'nav.token': 'Usage', + 'foot.settings': 'Settings', 'foot.ver': 'GenericAgent · Desktop', + 'chat.startTitle': 'Start a conversation', 'chat.startSub': 'Type a message, or pick a preset', + 'preset.butler.t': 'Conductor', 'preset.butler.d': 'Auto-decompose complex tasks; just check progress and briefings', + 'preset.plan.t': 'Plan mode', 'preset.plan.d': 'Load Plan SOP — explore→plan→execute→verify', + 'preset.goal.t': 'Goal mode', 'preset.goal.d': 'Set a goal, run autonomously', + 'preset.autonomous.t': 'Autonomous mode', 'preset.autonomous.d': 'Plan/execute tasks per SOP and produce reports (same as reflect/autonomous.py)', + 'preset.hive.t': 'Hive', 'preset.hive.d': 'Multi-worker collaboration', + 'preset.review.t': 'Deep review', 'preset.review.d': 'Strict quality check', + 'preset.findwork.t': 'Find me work', 'preset.findwork.d': 'Analyze my context and suggest a batch of interesting TODOs', + 'preset.mine.t': 'My · Weekly', 'preset.mine.d': 'Custom: weekly report from commits', + 'preset.add.t': 'Custom', 'preset.add.d': 'Save any prompt as a function', + 'composer.placeholder': 'What can GA do for you?', + 'search.placeholder': 'Search chats…', 'conv.new': 'New chat', + 'ctx.pin': 'Pin', 'ctx.unpin': 'Unpin', 'ctx.rename': 'Rename', 'ctx.del': 'Delete', + 'common.close': 'Close', 'common.more': 'More', 'common.optional': 'Optional', 'common.save': 'Save', + 'modal.preset': 'Presets', 'modal.addModel': 'Add model', 'modal.editModel': 'Edit model', 'modal.settings': 'Settings', + 'modal.customPreset': 'Custom preset', + 'modal.editCustomPreset': 'Edit task', + 'customPreset.titlePh': 'Title, e.g. "Weekly report"', + 'customPreset.promptPh': 'Prompt body — sent as the message when clicked', + 'customPreset.empty': 'Title and Prompt cannot be empty', + 'customPreset.removeTitle': 'Delete', + 'customPreset.editTitle': 'Edit', + 'builtinPreset.restoreBtn': 'Restore defaults', + 'set.appearance': 'Appearance', 'set.plainUi': 'Plain', 'set.fontSize': 'Chat font size', 'set.lang': 'Language', 'set.model': 'Model', 'set.addModel': 'Add model', 'set.features': 'Features', 'set.importMykey': 'Import model config (mykey.py)', 'set.exportMykey': 'Export current model config', 'set.importMemory': 'Import existing memory & sessions (select GenericAgent root)', 'set.gaSource': 'Connect to a separate GenericAgent source (use desktop as a shell)', 'set.gaSourceClear': 'Disconnect, use the bundled version', 'set.gaSourceCurrent': 'Connected to', 'set.serviceManager': 'Service manager', + 'shortcut.askConfirm': 'Create a desktop shortcut for GenericAgent?', + 'appearance.light': 'Light', 'appearance.dark': 'Dark', + 'set.noModels': 'No models yet — add one below', + 'lang.zh': '简体中文', 'lang.en': 'English', + 'model.name': 'Note', 'model.namePh': 'Shown in the model list', + 'model.apikey': 'API Key', 'model.apikeyPh': 'sk-...', 'model.apikeyKeep': 'Leave blank to keep the current key', + 'model.apibase': 'API base URL', 'model.apibasePh': 'https://.../v1/messages', + 'model.protocol': 'Protocol', 'model.protocolPick': 'Select…', 'model.protocolOai': 'OpenAI-compatible (chat/completions)', 'model.protocolClaude': 'Anthropic (Claude /v1/messages)', + 'model.stream': 'Response', 'model.streamOn': 'Stream', 'model.streamOff': 'Non-stream', + 'model.model': 'Model', 'model.modelPh': 'model parameter name', + 'model.modelHint': 'Must match the model field in your provider docs exactly', + 'model.retries': 'Retries (×)', 'model.connTimeout': 'Connect (s)', 'model.readTimeout': 'Read (s)', + 'model.save': 'Save', 'common.cancel': 'Cancel', 'common.confirm': 'Confirm', 'common.edit': 'Edit', 'common.delete': 'Delete', + 'pq.title': 'Quick connect a model', 'pq.sub': 'Add your API key to get started', 'pq.toggle': 'Expand / collapse', + 'pq.deepseekDesc': 'Official API · OpenAI-compatible', 'pq.qwenDesc': 'Tongyi Qwen · Aliyun Bailian', + 'guide.step1': 'Open the link, sign in, then create & copy your API key', + 'guide.step2': 'Paste the key into the “API Key” field below', + 'guide.step3': 'Click Save — then pick it from the model list', + 'guide.prefillTip': 'API base, protocol and model are pre-filled — edit if needed', + 'guide.getKey': 'Get your {name} API key', 'guide.copy': 'Copy link', 'guide.copied': 'Link copied', + 'err.modelSave': 'Save failed', 'err.modelSwitch': 'Failed to switch model', 'err.modelRequired': 'Model, API Key and base URL are required', + 'err.modelDelete': 'Delete failed', 'err.modelDeleteLast': 'At least one model is required', + 'confirm.modelDelete': 'Delete this model profile?', + 'model.aggregation': 'Channel group (auto failover)', 'model.aggregationShort': 'Channel group', 'model.aggregationDesc': 'Tries in order, switches to the next on failure', + 'model.emptyMixin': 'No models added yet', + 'model.addToMixin': 'Add to channel', 'model.inMixin': 'In channel', 'model.removeFromMixin': 'Remove from channel', 'model.alreadyInMixin': 'Already in the channel', 'model.dragReorder': 'Drag to reorder', + 'err.mixinFailed': 'Operation failed', + 'page.services.title': 'Services', 'page.services.sub': 'IM channels and background processes — view, start/stop, logs', + 'page.channels.title': 'Channels', 'page.channels.sub': 'Background IM processes: list, start/stop, logs (hub.pyw style)', + 'page.status.title': 'Status', 'page.status.sub': 'Background processes/services managed by hub.pyw', + 'page.collab.title': 'Conductor', 'page.collab.sub': 'Describe a goal — split, delegate, and follow up', + 'collab.progressTitle': 'Progress', + 'collab.progressEmpty': 'No tasks running yet. After you describe a goal to Conductor, split tasks will appear here.', + 'collab.placeholder': 'Describe the goal you want to accomplish', + 'collab.guideTitle': 'Tell Conductor what you want done', + 'collab.guideWhen': 'Best for multi-step goals that take a while. For everyday chat and quick questions, use Chat in the sidebar.', + 'collab.guideStep1t': 'Describe your goal', + 'collab.guideStep1d': 'Write what you want done in the chat box and send it to Conductor', + 'collab.guideStep2t': 'Auto breakdown', + 'collab.guideStep2d': 'Conductor breaks down, assigns, monitors, and coordinates', + 'collab.guideStep3t': 'Summary', + 'collab.guideStep3d': 'Conductor delivers a briefing based on execution status', + 'collab.guideStep4t': 'Adjust anytime', + 'collab.guideStep4d': 'Add requirements or details anytime — Conductor handles them', + 'collab.chipProgress': 'How is it going?', + 'collab.chipPause': 'Pause current tasks', + 'collab.chipSummary': 'Summarize progress so far', + 'collab.showProgressTitle': 'View task progress', + 'collab.statRunning': 'Running', + 'collab.statDone': 'Done', + 'collab.plusMenu': 'More actions', + 'collab.switchMode': 'Switch mode', + 'collab.typing': 'Conductor is working', + 'collab.offline': 'Cannot reach the service. Make sure the backend is running.', + 'collab.retry': 'Retry', + 'collab.reconnect': 'Disconnected — reconnecting… Your last progress is kept.', + 'collab.reconnectIn': 'Retry in {n}s', + 'collab.stRunning': 'Running', 'collab.stReported': 'Reported', 'collab.stPaused': 'Paused', + 'collab.stFailed': 'Issue', 'collab.stTerminated': 'Ended', + 'collab.summaryRunning': 'Working…', 'collab.summaryWait': 'Awaiting report', + 'collab.taskFallback': 'Task {n}', + 'collab.timeJust': 'just now', + 'collab.timeSec': '{n}s ago', + 'collab.timeMin': '{n}m ago', + 'collab.timeHr': '{n}h ago', + 'collab.timeDay': '{n}d ago', + 'page.token.title': 'Usage', 'page.token.sub': 'Per-session and total usage & cache rate', + 'status.connecting': 'Connecting…', 'status.ready': 'Service online', 'status.running': 'Working…', + 'status.disconnected': 'Service offline', 'status.stopped': 'Stopped', 'status.idle': 'Standby', + 'conv.emptyList': 'No chats yet — click “+ New chat”', 'conv.defaultTitle': 'New chat', + 'err.bridge': 'Service not responding', 'err.newSession': 'Failed to create session', 'err.poll': 'Polling failed', 'err.stop': 'Stop failed', + 'err.interruptTimeout': 'Timed out waiting for the previous reply to stop — try again', + 'sys.interruptPrev.hint': 'Previous reply stopped — processing new message', + 'chat.interrupting': 'Stopping previous reply…', + 'chat.sessionLoading': 'Loading conversation…', + 'sys.stopRequested': 'Stop requested', + 'slash.help': 'Commands:\n/new new chat /clear clear /stop stop /settings settings', + 'slash.unknown': 'Unknown command', + 'upload.hint': 'Upload file: pick / drag / paste', + 'upload.button': 'Upload file', + 'upload.tooLarge': 'File too large or limit reached', 'upload.empty': 'Skipped empty file', + 'upload.failed': 'Upload failed', + 'err.charLimit': 'Character limit reached ({n}), text will be truncated on send', 'err.charLimitReached': 'Character limit reached ({n})', 'err.numMax': 'Cannot exceed {n}', + 'file.openFailed': 'Cannot open file', + 'file.kindGeneric': 'File', + 'file.kindDoc': 'Document', + 'file.kindSheet': 'Spreadsheet', + 'file.kindSlide': 'Slides', + 'file.kindCode': 'Code', + 'file.kindArchive': 'Archive', + 'file.kindAudio': 'Audio', + 'file.kindVideo': 'Video', + 'upload.removeTitle': 'Remove', + 'upload.dropHint': 'Drop to upload files', + 'lightbox.closeTitle': 'Close', + 'fold.thinking': 'Thinking', 'fold.tool': 'Tool call', 'fold.toolResult': 'Tool result', 'fold.llm': 'LLM Running', 'fold.turn': 'Turn {n}', + 'plan.header': 'Plan ({done}/{total})', 'plan.complete': '✓ Plan complete ({n}/{n})', + 'plan.running': 'Running plan', 'plan.completeTitle': 'Plan complete', + 'plan.placeholder': 'Plan mode activated', 'plan.waiting': 'waiting for {path} …', 'plan.overflow': '+{n} more', + 'plan.current': 'Now', 'plan.fold': 'Fold', 'plan.collapse': 'Collapse', 'plan.expand': 'Expand', 'plan.details': 'Details', 'plan.dismiss': 'Hide', + 'plan.capsuleRunning': 'Running', 'plan.capsuleComplete': 'Done', + 'timing.elapsed': 'Elapsed {t}', + 'model.auto': 'Auto', + 'model.menuLabel': 'Select model', + 'chip.plan': 'Plan', + 'chip.auto': 'Auto', + 'ch.wechat': 'WeChat', 'ch.wecom': 'WeCom', 'ch.lark': 'Lark', 'ch.dingtalk': 'DingTalk', + 'ch.qq': 'QQ', 'ch.telegram': 'Telegram', 'ch.discord': 'Discord', + 'ch.loading': 'Loading…', 'ch.empty': 'No IM process scripts found', + 'ch.logEmpty': 'No log output yet', + 'err.channelLoad': 'Failed to load', 'err.channelStart': 'Start failed', 'err.channelStop': 'Stop failed', + 'err.mykeyImport': 'Failed to import model config', + 'err.mykeyExport': 'Failed to export model config', + 'err.channelNotConfigured': 'Configure this platform in mykey.py first', + 'sys.channelStarted': 'Started', 'sys.channelStopped': 'Stopped', + 'modal.channelLogs': 'Process logs', + 'modal.mykeyConfig': 'mykey.py', + 'sys.configSaved': 'Configuration saved', + 'sys.mykeyImported': 'Model config imported', + 'sys.mykeyExported': 'Model config exported', + 'sys.memoryImported': 'Memory imported', + 'err.memoryImport': 'Failed to import memory', + 'sys.memoryImportBackup': 'Previous memory backed up to', + 'sys.memorySessions': 'sessions', + 'sys.gaSourcePickTitle': 'Select the GenericAgent source root to connect to (contains agentmain.py)', + 'sys.gaSourceSwitching': 'Switching and restarting the backend...', + 'sys.gaSourceSet': 'Connected to the external GenericAgent', + 'sys.gaSourceCleared': 'Disconnected, restored the bundled version', + 'err.gaSourceSet': 'Failed to connect', + 'err.gaSourceDesktopOnly': 'This feature is only available in the desktop app', + 'sys.memoryPickTitle': 'Select the GenericAgent root directory (the folder containing memory and temp)', + 'sys.memoryImportPrompt': 'Enter the full path of the GenericAgent root directory (the folder containing memory and temp, not the memory folder itself):', + 'st.starting': 'Starting…', 'st.stopping': 'Stopping…', 'st.online': 'Online', 'st.offline': 'Offline', 'st.error': 'Error', 'st.running': 'Running', 'st.abnormal': 'Error', 'st.missingDeps': 'Needs Setup', + 'act.configure': 'Configure', 'act.logs': 'Logs', 'act.restart': 'Restart', 'act.stop': 'Stop', 'act.start': 'Start', 'act.exit': 'Exit', 'act.installDeps': 'Install', 'act.installing': 'Installing…', + 'act.copy': 'Copy', 'act.copied': 'Copied', 'act.copyTex': 'TeX', 'act.send': 'Send', + 'sys.depsInstalled': 'Dependencies installed', 'err.installDeps': 'Install failed', + 'proc.imbotWechat': 'imbot · WeChat', 'proc.imbotDing': 'imbot · DingTalk', 'proc.scheduler': 'Scheduler', 'proc.conductor': 'Conductor', + 'cm.scheduling': 'Scheduling', 'cm.running': 'Running', 'cm.idleSt': 'Idle', + 'cm.master': 'Dispatched 3 subtasks', 'cm.w1': 'Subtask: fetch data', 'cm.w2': 'Subtask: review results', 'cm.sub': 'Waiting for tasks', + 'tok.total': 'Total', 'tok.cost': 'Cache rate', 'tok.today': 'Today', 'tok.tabAll': 'Chat', 'tok.tabConductor': 'Conductor', 'tok.condTotal': 'Conductor Total', 'tok.condCurrent': 'Conductor Current', 'tok.condTip': 'Conductor usage is not included in chat totals', 'tok.condOffline': 'Service offline', 'tok.disclaimer': 'Pricing may vary by API provider. Please refer to the actual website.', + 'tok.colSession': 'Session', 'tok.colIn': 'Input', 'tok.colOut': 'Output', 'tok.colCacheW': 'Cache write', 'tok.colCache': 'Cache read', 'tok.colCost': 'Cost', + 'tok.from': 'From', 'tok.to': 'To', 'tok.reset': 'Reset', 'tok.noData': 'No records', 'tok.deleted': 'Session deleted', + 'tok.pricingUnknown': '⚠ Pricing not confirmed, using defaults', + 'tok.priceInput': 'Input: $', 'tok.priceOutput': 'Output: $', + 'tok.priceCacheW': 'Cache write: $', 'tok.priceCacheR': 'Cache read: $', + 'presetPrompt.goal': 'Enter Goal mode: read the L3 goal-mode SOP and autonomously achieve the goal I describe next.', + 'presetPrompt.plan': 'Enter Plan mode: first read memory/plan_sop.md, follow its explore→plan→execute→verify flow, and wait for the task I describe next.', + 'presetPrompt.autonomous': '🤖 Enter autonomous mode: read memory/autonomous_operation_sop.md, follow the SOP to pick or plan a task, execute independently, and produce a report.', + 'presetPrompt.hive': 'Start Goal Hive mode: per the hive SOP, spawn multiple workers to collaboratively achieve the goal I describe next.', + 'presetPrompt.review': 'Enter reviewer mode: strictly scrutinize the previous output, review item by item and report issues.', + 'presetPrompt.findwork': 'Following the autonomous planning section, analyze my situation thoroughly and generate a batch of TODOs that genuinely interest me.', + 'presetPrompt.mine': 'Collect this week\'s git commits and write a weekly report.', + 'ask.banner': 'GA is waiting for your answer', + 'ask.replyHint': 'Reply in the input below', + 'ask.placeholderOpen': 'Type your answer here… (Enter to send)', + }, +}; + + const BOOT_I18N = { + zh: { + 'loading.starting_app': '正在启动 GenericAgent...', + 'loading.start': '首次运行:正在准备运行环境...', + 'loading.venv': '正在创建运行环境...', + 'loading.deps': '正在安装依赖...', + 'loading.done': '依赖安装完成', + 'loading.starting': '正在启动服务...', + 'setup.title': 'GenericAgent - 设置', + 'setup.heading': '需要设置', + 'setup.backend_failed': '后端未能启动,请配置下方路径。', + 'setup.prepare_error': '安装失败,错误详情:', + 'setup.py_label': 'Python 解释器路径', + 'setup.py_placeholder': 'python / 解释器路径', + 'setup.py_hint': '例如 C:/Python312/python.exe 或 ~/miniconda3/envs/myenv/bin/python', + 'setup.project_label': '项目目录', + 'setup.project_placeholder': 'GenericAgent 文件夹路径', + 'setup.project_hint': '包含 frontends/desktop_bridge.py 的文件夹', + 'setup.start': '启动', + 'setup.err_py': '请输入 Python 路径', + 'setup.err_project': '请输入项目目录', + 'setup.starting_bridge': '正在启动 bridge...', + 'setup.connected': '已连接,正在打开主窗口...', + 'setup.failed': '启动失败:{error}', + 'setup.limit': '已达字符数上限({n})' + }, + en: { + 'loading.starting_app': 'Starting GenericAgent...', + 'loading.start': 'First run: preparing the runtime...', + 'loading.venv': 'Creating the runtime environment...', + 'loading.deps': 'Installing dependencies...', + 'loading.done': 'Dependencies installed', + 'loading.starting': 'Starting services...', + 'setup.title': 'GenericAgent - Setup', + 'setup.heading': 'Setup Required', + 'setup.backend_failed': 'The backend could not start. Please configure the paths below.', + 'setup.prepare_error': 'Setup failed. Details:', + 'setup.py_label': 'Python interpreter path', + 'setup.py_placeholder': 'python / path to interpreter', + 'setup.py_hint': 'e.g. C:/Python312/python.exe or ~/miniconda3/envs/myenv/bin/python', + 'setup.project_label': 'Project directory', + 'setup.project_placeholder': 'path to GenericAgent folder', + 'setup.project_hint': 'The folder containing frontends/desktop_bridge.py', + 'setup.start': 'Start', + 'setup.err_py': 'Please enter Python path', + 'setup.err_project': 'Please enter project directory', + 'setup.starting_bridge': 'Starting bridge...', + 'setup.connected': 'Connected. Opening the main window...', + 'setup.failed': 'Failed: {error}', + 'setup.limit': 'Character limit reached ({n})' + } +}; + + for (const [code, messages] of Object.entries(BOOT_I18N)) { + I18N[code] = Object.assign(I18N[code] || {}, messages); + } + + const LANGS = Object.freeze(Object.keys(I18N)); + + function normalizeLang(code) { + return LANGS.includes(code) ? code : 'zh'; + } + + function browserLang() { + return (navigator.language || '').toLowerCase().startsWith('zh') ? 'zh' : 'en'; + } + + function bootLang() { + try { + const saved = localStorage.getItem('ga_lang'); + if (LANGS.includes(saved)) return saved; + } catch (_) {} + return browserLang(); + } + + function tFor(lang, key, vars) { + const active = normalizeLang(lang); + let text = (I18N[active] && I18N[active][key]) || (I18N.zh && I18N.zh[key]) || (I18N.en && I18N.en[key]) || key; + if (vars) { + for (const [name, value] of Object.entries(vars)) { + text = text.replaceAll(`{${name}}`, String(value)); + } + } + return text; + } + + function apply(root, activeLang) { + const lang = normalizeLang(activeLang || bootLang()); + const scope = root || document; + if (scope === document) document.documentElement.lang = lang === 'en' ? 'en' : 'zh-CN'; + scope.querySelectorAll('[data-i18n]').forEach(el => { + el.textContent = tFor(lang, el.dataset.i18n); + }); + scope.querySelectorAll('[data-i18n-ph]').forEach(el => { + el.setAttribute('data-ph', tFor(lang, el.dataset.i18nPh)); + }); + scope.querySelectorAll('[data-i18n-placeholder]').forEach(el => { + el.setAttribute('placeholder', tFor(lang, el.dataset.i18nPlaceholder)); + }); + scope.querySelectorAll('[data-i18n-title]').forEach(el => { + el.setAttribute('title', tFor(lang, el.dataset.i18nTitle)); + el.setAttribute('aria-label', tFor(lang, el.dataset.i18nTitle)); + }); + } + + window.GA_I18N = { + dict: I18N, + languages: LANGS, + t: tFor, + apply, + bootLang, + browserLang, + }; + + window.GA_BOOT_I18N = { + get lang() { return bootLang(); }, + t(key, vars) { return tFor(bootLang(), key, vars); }, + apply(root) { return apply(root || document, bootLang()); }, + }; +})(); diff --git a/frontends/desktop/public/phosphor-icons.js b/frontends/desktop/public/phosphor-icons.js new file mode 100644 index 000000000..101df095b --- /dev/null +++ b/frontends/desktop/public/phosphor-icons.js @@ -0,0 +1,101 @@ +(() => { + const PATHS = { + chatTeardropText: + 'M172,112a8,8,0,0,1-8,8H96a8,8,0,0,1,0-16h68A8,8,0,0,1,172,112Zm-8,24H96a8,8,0,0,0,0,16h68a8,8,0,0,0,0-16Zm68-12A100.11,100.11,0,0,1,132,224H48a16,16,0,0,1-16-16V124a100,100,0,0,1,200,0Zm-16,0a84,84,0,0,0-168,0v84h84A84.09,84.09,0,0,0,216,124Z', + broadcast: + 'M128,88a40,40,0,1,0,40,40A40,40,0,0,0,128,88Zm0,64a24,24,0,1,1,24-24A24,24,0,0,1,128,152Zm73.71,7.14a80,80,0,0,1-14.08,22.2,8,8,0,0,1-11.92-10.67,63.95,63.95,0,0,0,0-85.33,8,8,0,1,1,11.92-10.67,80.08,80.08,0,0,1,14.08,84.47ZM69,103.09a64,64,0,0,0,11.26,67.58,8,8,0,0,1-11.92,10.67,79.93,79.93,0,0,1,0-106.67A8,8,0,1,1,80.29,85.34,63.77,63.77,0,0,0,69,103.09ZM248,128a119.58,119.58,0,0,1-34.29,84,8,8,0,1,1-11.42-11.2,103.9,103.9,0,0,0,0-145.56A8,8,0,1,1,213.71,44,119.58,119.58,0,0,1,248,128ZM53.71,200.78A8,8,0,1,1,42.29,212a119.87,119.87,0,0,1,0-168,8,8,0,1,1,11.42,11.2,103.9,103.9,0,0,0,0,145.56Z', + chartBar: + 'M224,200h-8V40a8,8,0,0,0-8-8H152a8,8,0,0,0-8,8V80H96a8,8,0,0,0-8,8v40H48a8,8,0,0,0-8,8v64H32a8,8,0,0,0,0,16H224a8,8,0,0,0,0-16ZM160,48h40V200H160ZM104,96h40V200H104ZM56,144H88v56H56Z', + usersThree: + 'M244.8,150.4a8,8,0,0,1-11.2-1.6A51.6,51.6,0,0,0,192,128a8,8,0,0,1-7.37-4.89,8,8,0,0,1,0-6.22A8,8,0,0,1,192,112a24,24,0,1,0-23.24-30,8,8,0,1,1-15.5-4A40,40,0,1,1,219,117.51a67.94,67.94,0,0,1,27.43,21.68A8,8,0,0,1,244.8,150.4ZM190.92,212a8,8,0,1,1-13.84,8,57,57,0,0,0-98.16,0,8,8,0,1,1-13.84-8,72.06,72.06,0,0,1,33.74-29.92,48,48,0,1,1,58.36,0A72.06,72.06,0,0,1,190.92,212ZM128,176a32,32,0,1,0-32-32A32,32,0,0,0,128,176ZM72,120a8,8,0,0,0-8-8A24,24,0,1,1,87.24,82a8,8,0,1,0,15.5-4A40,40,0,1,0,37,117.51,67.94,67.94,0,0,0,9.6,139.19a8,8,0,1,0,12.8,9.61A51.6,51.6,0,0,1,64,128,8,8,0,0,0,72,120Z', + coins: + 'M184,89.57V84c0-25.08-37.83-44-88-44S8,58.92,8,84v40c0,20.89,26.25,37.49,64,42.46V172c0,25.08,37.83,44,88,44s88-18.92,88-44V132C248,111.3,222.58,94.68,184,89.57ZM232,132c0,13.22-30.79,28-72,28-3.73,0-7.43-.13-11.08-.37C170.49,151.77,184,139,184,124V105.74C213.87,110.19,232,122.27,232,132ZM72,150.25V126.46A183.74,183.74,0,0,0,96,128a183.74,183.74,0,0,0,24-1.54v23.79A163,163,0,0,1,96,152,163,163,0,0,1,72,150.25Zm96-40.32V124c0,8.39-12.41,17.4-32,22.87V123.5C148.91,120.37,159.84,115.71,168,109.93ZM96,56c41.21,0,72,14.78,72,28s-30.79,28-72,28S24,97.22,24,84,54.79,56,96,56ZM24,124V109.93c8.16,5.78,19.09,10.44,32,13.57v23.37C36.41,141.4,24,132.39,24,124Zm64,48v-4.17c2.63.1,5.29.17,8,.17,3.88,0,7.67-.13,11.39-.35A121.92,121.92,0,0,0,120,171.41v23.46C100.41,189.4,88,180.39,88,172Zm48,26.25V174.4a179.48,179.48,0,0,0,24,1.6,183.74,183.74,0,0,0,24-1.54v23.79a165.45,165.45,0,0,1-48,0Zm64-3.38V171.5c12.91-3.13,23.84-7.79,32-13.57V172C232,180.39,219.59,189.4,200,194.87Z', + sidebarSimple: + 'M216,40H40A16,16,0,0,0,24,56V200a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A16,16,0,0,0,216,40ZM40,56H80V200H40ZM216,200H96V56H216V200Z', + pencilSimple: + 'M227.31,73.37,182.63,28.68a16,16,0,0,0-22.63,0L36.69,152A15.86,15.86,0,0,0,32,163.31V208a16,16,0,0,0,16,16H92.69A15.86,15.86,0,0,0,104,219.31L227.31,96a16,16,0,0,0,0-22.63ZM92.69,208H48V163.31l88-88L180.69,120ZM192,108.68,147.31,64l24-24L216,84.68Z', + magnifyingGlass: + 'M229.66,218.34l-50.07-50.06a88.11,88.11,0,1,0-11.31,11.31l50.06,50.07a8,8,0,0,0,11.32-11.32ZM40,112a72,72,0,1,1,72,72A72.08,72.08,0,0,1,40,112Z', + books: + 'M231.65,194.55,198.46,36.75a16,16,0,0,0-19-12.39L132.65,34.42a16.08,16.08,0,0,0-12.3,19l33.19,157.8A16,16,0,0,0,169.16,224a16.25,16.25,0,0,0,3.38-.36l46.81-10.06A16.09,16.09,0,0,0,231.65,194.55ZM136,50.15c0-.06,0-.09,0-.09l46.8-10,3.33,15.87L139.33,66Zm6.62,31.47,46.82-10.05,3.34,15.9L146,97.53Zm6.64,31.57,46.82-10.06,13.3,63.24-46.82,10.06ZM216,197.94l-46.8,10-3.33-15.87L212.67,182,216,197.85C216,197.91,216,197.94,216,197.94ZM104,32H56A16,16,0,0,0,40,48V208a16,16,0,0,0,16,16h48a16,16,0,0,0,16-16V48A16,16,0,0,0,104,32ZM56,48h48V64H56Zm0,32h48v96H56Zm48,128H56V192h48v16Z', + gridFour: + 'M200,40H56A16,16,0,0,0,40,56V200a16,16,0,0,0,16,16H200a16,16,0,0,0,16-16V56A16,16,0,0,0,200,40Zm0,80H136V56h64ZM120,56v64H56V56ZM56,136h64v64H56Zm144,64H136V136h64v64Z', + robot: + 'M200,48H136V16a8,8,0,0,0-16,0V48H56A32,32,0,0,0,24,80V192a32,32,0,0,0,32,32H200a32,32,0,0,0,32-32V80A32,32,0,0,0,200,48Zm16,144a16,16,0,0,1-16,16H56a16,16,0,0,1-16-16V80A16,16,0,0,1,56,64H200a16,16,0,0,1,16,16Zm-52-56H92a28,28,0,0,0,0,56h72a28,28,0,0,0,0-56Zm-24,16v24H116V152ZM80,164a12,12,0,0,1,12-12h8v24H92A12,12,0,0,1,80,164Zm84,12h-8V152h8a12,12,0,0,1,0,24ZM72,108a12,12,0,1,1,12,12A12,12,0,0,1,72,108Zm88,0a12,12,0,1,1,12,12A12,12,0,0,1,160,108Z', + dotsThree: + 'M140,128a12,12,0,1,1-12-12A12,12,0,0,1,140,128Zm56-12a12,12,0,1,0,12,12A12,12,0,0,0,196,116ZM60,116a12,12,0,1,0,12,12A12,12,0,0,0,60,116Z', + folderSimplePlus: + 'M216,72H130.67L102.93,51.2a16.12,16.12,0,0,0-9.6-3.2H40A16,16,0,0,0,24,64V200a16,16,0,0,0,16,16H216.89A15.13,15.13,0,0,0,232,200.89V88A16,16,0,0,0,216,72Zm0,128H40V64H93.33L123.2,86.4A8,8,0,0,0,128,88h88Zm-56-56a8,8,0,0,1-8,8H136v16a8,8,0,0,1-16,0V152H104a8,8,0,0,1,0-16h16V120a8,8,0,0,1,16,0v16h16A8,8,0,0,1,160,144Z', + folderSimple: + 'M216,72H130.67L102.93,51.2a16.12,16.12,0,0,0-9.6-3.2H40A16,16,0,0,0,24,64V200a16,16,0,0,0,16,16H216.89A15.13,15.13,0,0,0,232,200.89V88A16,16,0,0,0,216,72Zm0,128H40V64H93.33L123.2,86.4A8,8,0,0,0,128,88h88Z', + bracketsCurly: + 'M43.18,128a29.78,29.78,0,0,1,8,10.26c4.8,9.9,4.8,22,4.8,33.74,0,24.31,1,36,24,36a8,8,0,0,1,0,16c-17.48,0-29.32-6.14-35.2-18.26-4.8-9.9-4.8-22-4.8-33.74,0-24.31-1-36-24-36a8,8,0,0,1,0-16c23,0,24-11.69,24-36,0-11.72,0-23.84,4.8-33.74C50.68,38.14,62.52,32,80,32a8,8,0,0,1,0,16C57,48,56,59.69,56,84c0,11.72,0,23.84-4.8,33.74A29.78,29.78,0,0,1,43.18,128ZM240,120c-23,0-24-11.69-24-36,0-11.72,0-23.84-4.8-33.74C205.32,38.14,193.48,32,176,32a8,8,0,0,0,0,16c23,0,24,11.69,24,36,0,11.72,0,23.84,4.8,33.74a29.78,29.78,0,0,0,8,10.26,29.78,29.78,0,0,0-8,10.26c-4.8,9.9-4.8,22-4.8,33.74,0,24.31-1,36-24,36a8,8,0,0,0,0,16c17.48,0,29.32-6.14,35.2-18.26,4.8-9.9,4.8-22,4.8-33.74,0-24.31,1-36,24-36a8,8,0,0,0,0-16Z', + gear: + 'M128,80a48,48,0,1,0,48,48A48.05,48.05,0,0,0,128,80Zm0,80a32,32,0,1,1,32-32A32,32,0,0,1,128,160Zm88-29.84q.06-2.16,0-4.32l14.92-18.64a8,8,0,0,0,1.48-7.06,107.21,107.21,0,0,0-10.88-26.25,8,8,0,0,0-6-3.93l-23.72-2.64q-1.48-1.56-3-3L186,40.54a8,8,0,0,0-3.94-6,107.71,107.71,0,0,0-26.25-10.87,8,8,0,0,0-7.06,1.49L130.16,40Q128,40,125.84,40L107.2,25.11a8,8,0,0,0-7.06-1.48A107.6,107.6,0,0,0,73.89,34.51a8,8,0,0,0-3.93,6L67.32,64.27q-1.56,1.49-3,3L40.54,70a8,8,0,0,0-6,3.94,107.71,107.71,0,0,0-10.87,26.25,8,8,0,0,0,1.49,7.06L40,125.84Q40,128,40,130.16L25.11,148.8a8,8,0,0,0-1.48,7.06,107.21,107.21,0,0,0,10.88,26.25,8,8,0,0,0,6,3.93l23.72,2.64q1.49,1.56,3,3L70,215.46a8,8,0,0,0,3.94,6,107.71,107.71,0,0,0,26.25,10.87,8,8,0,0,0,7.06-1.49L125.84,216q2.16.06,4.32,0l18.64,14.92a8,8,0,0,0,7.06,1.48,107.21,107.21,0,0,0,26.25-10.88,8,8,0,0,0,3.93-6l2.64-23.72q1.56-1.48,3-3L215.46,186a8,8,0,0,0,6-3.94,107.71,107.71,0,0,0,10.87-26.25,8,8,0,0,0-1.49-7.06Zm-16.1-6.5a73.93,73.93,0,0,1,0,8.68,8,8,0,0,0,1.74,5.48l14.19,17.73a91.57,91.57,0,0,1-6.23,15L187,173.11a8,8,0,0,0-5.1,2.64,74.11,74.11,0,0,1-6.14,6.14,8,8,0,0,0-2.64,5.1l-2.51,22.58a91.32,91.32,0,0,1-15,6.23l-17.74-14.19a8,8,0,0,0-5-1.75h-.48a73.93,73.93,0,0,1-8.68,0,8,8,0,0,0-5.48,1.74L100.45,215.8a91.57,91.57,0,0,1-15-6.23L82.89,187a8,8,0,0,0-2.64-5.1,74.11,74.11,0,0,1-6.14-6.14,8,8,0,0,0-5.1-2.64L46.43,170.6a91.32,91.32,0,0,1-6.23-15l14.19-17.74a8,8,0,0,0,1.74-5.48,73.93,73.93,0,0,1,0-8.68,8,8,0,0,0-1.74-5.48L40.2,100.45a91.57,91.57,0,0,1,6.23-15L69,82.89a8,8,0,0,0,5.1-2.64,74.11,74.11,0,0,1,6.14-6.14A8,8,0,0,0,82.89,69L85.4,46.43a91.32,91.32,0,0,1,15-6.23l17.74,14.19a8,8,0,0,0,5.48,1.74,73.93,73.93,0,0,1,8.68,0,8,8,0,0,0,5.48-1.74L155.55,40.2a91.57,91.57,0,0,1,15,6.23L173.11,69a8,8,0,0,0,2.64,5.1,74.11,74.11,0,0,1,6.14,6.14,8,8,0,0,0,5.1,2.64l22.58,2.51a91.32,91.32,0,0,1,6.23,15l-14.19,17.74A8,8,0,0,0,199.87,123.66Z', + caretLeft: + 'M165.66,202.34a8,8,0,0,1-11.32,11.32l-80-80a8,8,0,0,1,0-11.32l80-80a8,8,0,0,1,11.32,11.32L91.31,128Z', + caretDown: + 'M213.66,101.66l-80,80a8,8,0,0,1-11.32,0l-80-80A8,8,0,0,1,53.66,90.34L128,164.69l74.34-74.35a8,8,0,0,1,11.32,11.32Z', + caretRight: + 'M181.66,133.66l-80,80a8,8,0,0,1-11.32-11.32L164.69,128,90.34,53.66a8,8,0,0,1,11.32-11.32l80,80A8,8,0,0,1,181.66,133.66Z', + paperPlaneTilt: + 'M227.32,28.68a16,16,0,0,0-15.66-4.08l-.15,0L19.57,82.84a16,16,0,0,0-2.49,29.8L102,154l41.3,84.87A15.86,15.86,0,0,0,157.74,248q.69,0,1.38-.06a15.88,15.88,0,0,0,14-11.51l58.2-191.94c0-.05,0-.1,0-.15A16,16,0,0,0,227.32,28.68ZM157.83,231.85l-.05.14,0-.07-40.06-82.3,48-48a8,8,0,0,0-11.31-11.31l-48,48L24.08,98.25l-.07,0,.14,0L216,40Z', + paperclip: + 'M209.66,122.34a8,8,0,0,1,0,11.32l-82.05,82a56,56,0,0,1-79.2-79.21L147.67,35.73a40,40,0,1,1,56.61,56.55L105,193A24,24,0,1,1,71,159L154.3,74.38A8,8,0,1,1,165.7,85.6L82.39,170.31a8,8,0,1,0,11.27,11.36L192.93,81A24,24,0,1,0,159,47L59.76,147.68a40,40,0,1,0,56.53,56.62l82.06-82A8,8,0,0,1,209.66,122.34Z', + lightning: + 'M215.79,118.17a8,8,0,0,0-5-5.66L153.18,90.9l14.66-73.33a8,8,0,0,0-13.69-7l-112,120a8,8,0,0,0,3,13l57.63,21.61L88.16,238.43a8,8,0,0,0,13.69,7l112-120A8,8,0,0,0,215.79,118.17ZM109.37,214l10.47-52.38a8,8,0,0,0-5-9.06L62,132.71l84.62-90.66L136.16,94.43a8,8,0,0,0,5,9.06l52.8,19.8Z', + pushPinSimple: + 'M216,168h-9.29L185.54,48H192a8,8,0,0,0,0-16H64a8,8,0,0,0,0,16h6.46L49.29,168H40a8,8,0,0,0,0,16h80v56a8,8,0,0,0,16,0V184h80a8,8,0,0,0,0-16ZM86.71,48h82.58l21.17,120H65.54Z', + trash: + 'M216,48H176V40a24,24,0,0,0-24-24H104A24,24,0,0,0,80,40v8H40a8,8,0,0,0,0,16h8V208a16,16,0,0,0,16,16H192a16,16,0,0,0,16-16V64h8a8,8,0,0,0,0-16ZM96,40a8,8,0,0,1,8-8h48a8,8,0,0,1,8,8v8H96Zm96,168H64V64H192ZM112,104v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Zm48,0v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Z', + x: + 'M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z', + dotsThreeVertical: + 'M140,128a12,12,0,1,1-12-12A12,12,0,0,1,140,128Zm0-56a12,12,0,1,1-12-12A12,12,0,0,1,140,72Zm0,112a12,12,0,1,1-12-12A12,12,0,0,1,140,184Z', + plus: + 'M224,128a8,8,0,0,1-8,8H136v80a8,8,0,0,1-16,0V136H40a8,8,0,0,1,0-16h80V40a8,8,0,0,1,16,0v80h80A8,8,0,0,1,224,128Z', + copy: + 'M216,32H88a8,8,0,0,0-8,8V80H40a8,8,0,0,0-8,8V216a8,8,0,0,0,8,8H168a8,8,0,0,0,8-8V176h40a8,8,0,0,0,8-8V40A8,8,0,0,0,216,32ZM160,208H48V96H160Zm48-48H176V88a8,8,0,0,0-8-8H96V48H208Z', + check: + 'M229.66,77.66l-128,128a8,8,0,0,1-11.32,0l-56-56a8,8,0,0,1,11.32-11.32L96,188.69,218.34,66.34a8,8,0,0,1,11.32,11.32Z', + crosshair: + 'M232,120h-8.34A96.14,96.14,0,0,0,136,32.34V24a8,8,0,0,0-16,0v8.34A96.14,96.14,0,0,0,32.34,120H24a8,8,0,0,0,0,16h8.34A96.14,96.14,0,0,0,120,223.66V232a8,8,0,0,0,16,0v-8.34A96.14,96.14,0,0,0,223.66,136H232a8,8,0,0,0,0-16Zm-96,87.6V200a8,8,0,0,0-16,0v7.6A80.15,80.15,0,0,1,48.4,136H56a8,8,0,0,0,0-16H48.4A80.15,80.15,0,0,1,120,48.4V56a8,8,0,0,0,16,0V48.4A80.15,80.15,0,0,1,207.6,120H200a8,8,0,0,0,0,16h7.6A80.15,80.15,0,0,1,136,207.6ZM128,88a40,40,0,1,0,40,40A40,40,0,0,0,128,88Zm0,64a24,24,0,1,1,24-24A24,24,0,0,1,128,152Z', + compass: + 'M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216ZM172.42,72.84l-64,32a8.05,8.05,0,0,0-3.58,3.58l-32,64A8,8,0,0,0,80,184a8.1,8.1,0,0,0,3.58-.84l64-32a8.05,8.05,0,0,0,3.58-3.58l32-64a8,8,0,0,0-10.74-10.74ZM138,138,97.89,158.11,118,118l40.15-20.07Z', + listChecks: + 'M224,128a8,8,0,0,1-8,8H128a8,8,0,0,1,0-16h88A8,8,0,0,1,224,128ZM128,72h88a8,8,0,0,0,0-16H128a8,8,0,0,0,0,16Zm88,112H128a8,8,0,0,0,0,16h88a8,8,0,0,0,0-16ZM82.34,42.34,56,68.69,45.66,58.34A8,8,0,0,0,34.34,69.66l16,16a8,8,0,0,0,11.32,0l32-32A8,8,0,0,0,82.34,42.34Zm0,64L56,132.69,45.66,122.34a8,8,0,0,0-11.32,11.32l16,16a8,8,0,0,0,11.32,0l32-32a8,8,0,0,0-11.32-11.32Zm0,64L56,196.69,45.66,186.34a8,8,0,0,0-11.32,11.32l16,16a8,8,0,0,0,11.32,0l32-32a8,8,0,0,0-11.32-11.32Z', + star: + 'M239.18,97.26A16.38,16.38,0,0,0,224.92,86l-59-4.76L143.14,26.15a16.36,16.36,0,0,0-30.27,0L90.11,81.23,31.08,86a16.46,16.46,0,0,0-9.37,28.86l45,38.83L53,211.75a16.38,16.38,0,0,0,24.5,17.82L128,198.49l50.53,31.08A16.4,16.4,0,0,0,203,211.75l-13.76-58.07,45-38.83A16.43,16.43,0,0,0,239.18,97.26Zm-15.34,5.47-48.7,42a8,8,0,0,0-2.56,7.91l14.88,62.8a.37.37,0,0,1-.17.48c-.18.14-.23.11-.38,0l-54.72-33.65a8,8,0,0,0-8.38,0L69.09,215.94c-.15.09-.19.12-.38,0a.37.37,0,0,1-.17-.48l14.88-62.8a8,8,0,0,0-2.56-7.91l-48.7-42c-.12-.1-.23-.19-.13-.5s.18-.27.33-.29l63.92-5.16A8,8,0,0,0,103,91.86l24.62-59.61c.08-.17.11-.25.35-.25s.27.08.35.25L153,91.86a8,8,0,0,0,6.75,4.92l63.92,5.16c.15,0,.24,0,.33.29S224,102.63,223.84,102.73Z', + fileText: + 'M213.66,82.34l-56-56A8,8,0,0,0,152,24H56A16,16,0,0,0,40,40V216a16,16,0,0,0,16,16H200a16,16,0,0,0,16-16V88A8,8,0,0,0,213.66,82.34ZM160,51.31,188.69,80H160ZM200,216H56V40h88V88a8,8,0,0,0,8,8h48V216Zm-32-80a8,8,0,0,1-8,8H96a8,8,0,0,1,0-16h64A8,8,0,0,1,168,136Zm0,32a8,8,0,0,1-8,8H96a8,8,0,0,1,0-16h64A8,8,0,0,1,168,168Z', + gitFork: + 'M224,64a32,32,0,1,0-40,31v17a8,8,0,0,1-8,8H80a8,8,0,0,1-8-8V95a32,32,0,1,0-16,0v17a24,24,0,0,0,24,24h40v25a32,32,0,1,0,16,0V136h40a24,24,0,0,0,24-24V95A32.06,32.06,0,0,0,224,64ZM48,64A16,16,0,1,1,64,80,16,16,0,0,1,48,64Zm96,128a16,16,0,1,1-16-16A16,16,0,0,1,144,192ZM192,80a16,16,0,1,1,16-16A16,16,0,0,1,192,80Z', + hexagon: + 'M223.68,66.15,135.68,18h0a15.88,15.88,0,0,0-15.36,0l-88,48.17a16,16,0,0,0-8.32,14v95.64a16,16,0,0,0,8.32,14l88,48.17a15.88,15.88,0,0,0,15.36,0l88-48.17a16,16,0,0,0,8.32-14V80.18A16,16,0,0,0,223.68,66.15ZM216,175.82,128,224,40,175.82V80.18L128,32h0l88,48.17Z', + }; + + function gaIcon(name, className = '') { + const d = PATHS[name]; + if (!d) return ''; + const cls = className ? ` class="${className}"` : ''; + return `
头部的副标题(来自模型 抽取) */ +.fold-turn > summary .turn-head-sum{ + font-style:italic; color:var(--muted); font-weight:normal; margin-left:4px; + min-width:0; overflow:hidden; text-overflow:ellipsis; +} + +/* —— ask_user 显眼提醒 —— */ +.ask-user-notice{ + margin:8px 0 4px; + border:1px solid var(--line); + border-left:3px solid var(--accent); + border-radius:0; + background:color-mix(in srgb, var(--accent-bg) 55%, var(--card)); + padding:10px 12px; +} +.ask-user-notice.is-active{ + border-color:color-mix(in srgb, var(--accent) 28%, var(--line)); + background:color-mix(in srgb, var(--accent-bg) 72%, var(--card)); +} +.ask-user-notice.is-answered{ + opacity:.78; + background:var(--card); + border-color:var(--line); + border-left-color:var(--muted2); +} +.ask-user-banner{ + display:flex; align-items:baseline; flex-wrap:wrap; + gap:4px 6px; + margin-bottom:8px; + line-height:1.35; +} +.ask-user-banner-text{ + font-size:13px; font-weight:600; + color:var(--txt-strong); +} +.ask-user-notice.is-active .ask-user-banner-text{ + color:var(--accent); +} +.ask-user-notice.is-answered .ask-user-banner-text{ + color:var(--muted); +} +.ask-user-banner-sep{ + color:var(--muted2); + font-size:12px; user-select:none; +} +.ask-user-banner-hint{ + font-size:12px; font-weight:400; color:var(--muted); +} +.ask-user-body{ + font-size:14px; line-height:1.55; color:var(--txt); + font-weight:500; margin:0; +} +.ask-user-body strong{ color:var(--txt-strong); } +.ask-user-body code{ + background:rgba(127,127,127,.14); + padding:1px 5px; border-radius:4px; font-size:.92em; +} +/* 覆盖 .bubble.md ul/ol/p,题干内列表与正文左缘对齐 */ +.bubble.md .ask-user-notice .ask-user-body p{ + margin:0 0 4px; +} +.bubble.md .ask-user-notice .ask-user-body p:last-child{ + margin-bottom:0; +} +.bubble.md .ask-user-notice .ask-user-body p.ask-option-line{ + padding-left:1.25em; + margin:0; + font-weight:400; +} +.bubble.md .ask-user-notice .ask-user-body span.ask-option-line{ + display:block; + padding-left:1.25em; + margin:0; + font-weight:400; + line-height:1.55; +} +.bubble.md .ask-user-notice .ask-user-body ul, +.bubble.md .ask-user-notice .ask-user-body ol{ + margin:4px 0 0; padding:0; list-style:none; +} +.bubble.md .ask-user-notice .ask-user-body ul > li, +.bubble.md .ask-user-notice .ask-user-body ol > li{ + margin:0; padding:2px 0; padding-left:0; +} +.bubble.md .ask-user-notice .ask-user-body ol{ + counter-reset:ask-ol; +} +.bubble.md .ask-user-notice .ask-user-body ol > li{ + counter-increment:ask-ol; + display:block; +} +.bubble.md .ask-user-notice .ask-user-body ol > li::before{ + content:counter(ask-ol) ". "; + font-weight:500; + color:color-mix(in srgb, var(--txt) 38%, var(--muted)); +} +.bubble.md .ask-user-notice .ask-user-body ol > li > p{ + display:inline; + margin:0; +} +.ask-user-notice.is-active .ask-user-body ol > li::before{ + color:color-mix(in srgb, var(--accent) 72%, var(--txt)); +} +.ask-candidates{ + display:flex; flex-direction:column; gap:0; +} +.ask-candidates li{ + display:block; + font-size:14px; line-height:1.55; color:var(--txt); +} +.ask-candidate-key{ + font-weight:500; + color:color-mix(in srgb, var(--txt) 38%, var(--muted)); +} +.ask-user-notice.is-active .ask-candidate-key{ + color:color-mix(in srgb, var(--accent) 72%, var(--txt)); +} +.ask-user-notice.is-answered .ask-candidate-key{ + color:var(--muted2); +} +.ask-candidate-label{ + white-space:pre-wrap; word-break:break-word; +} + +/* —— 消息计时 badge —— */ +.task-elapsed{ + display:block; font-size:11px; color:var(--muted); + line-height:1; min-height:18px; + padding:0 6px; margin-bottom:2px; + border-radius:var(--radius-sm); +} + +/* ---- Conductor(仅保留与主聊天不同的部分,布局见 .page--chat-ui) ---- */ +#collab-welcome[hidden], .collab-msgs .msgs[hidden], +.collab-rail[hidden], .collab-prog-stats[hidden], +.collab-rail-run[hidden], .collab-rail-done[hidden], .collab-rail-issue[hidden]{ display:none !important; } +/* 顶栏中央:状态栏 + 离线时的刷新图标按钮(取代原本的 banner+重试) */ +.page > .page-top .page-top-center{ + grid-column:2; display:flex; align-items:center; justify-content:center; gap:6px; + min-width:0; +} +/* 收尾按钮:跟 .preset-restore 同款 — 白底 + 中性边框, hover 转 accent 色 */ +.collab-retry-btn{ + width:24px; height:24px; + border:1px solid var(--line); background:var(--card); border-radius:4px; + opacity:1; color:var(--txt-2); +} +.collab-retry-btn:hover{ background:var(--hover-2); color:var(--accent); border-color:var(--accent); opacity:1; } +.collab-retry-btn svg{ width:14px; height:14px; } +.collab-retry-btn[hidden]{ display:none !important; } +.page.page--chat-ui[data-page="collab"] .msg-area.collab-msgs{ overflow:hidden; padding:0; } +.page.page--chat-ui[data-page="collab"] .collab-scroll{ + flex:1 1 0; min-height:0; overflow:auto; + display:flex; flex-direction:column; align-items:center; justify-content:center; gap:14px; + padding:16px; +} +.page.page--chat-ui[data-page="collab"] .collab-msgs.has-msgs .collab-scroll{ + align-items:stretch; justify-content:flex-start; +} +.page.page--chat-ui[data-page="collab"] .collab-overlay{ + position:absolute; inset:0; z-index:10; pointer-events:none; +} +.page.page--chat-ui[data-page="collab"] .collab-overlay > .collab-rail, +.page.page--chat-ui[data-page="collab"] .collab-overlay > .collab-prog-panel{ pointer-events:auto; } +.page.page--chat-ui[data-page="collab"].dragover .collab-msgs::after{ + content:attr(data-drop-hint); position:absolute; inset:8px; z-index:20; pointer-events:none; + display:flex; align-items:center; justify-content:center; border-radius:var(--radius); + border:2px dashed var(--accent); background:color-mix(in srgb, var(--accent) 8%, var(--panel)); + font-size:13px; color:var(--accent); font-weight:500; +} +.collab-rail{ + position:absolute; left:0; top:50%; z-index:14; + transform:translateY(-50%); + transition:left .22s ease-out; +} +.page.page--chat-ui[data-page="collab"].collab-prog-open .collab-rail{ left:232px; } +.collab-rail-handle{ + display:flex; flex-direction:column; align-items:center; justify-content:center; gap:5px; + width:22px; padding:10px 3px; cursor:pointer; + border:1px solid var(--line); border-left:none; + border-radius:0 var(--radius-sm) var(--radius-sm) 0; + background:var(--card); color:var(--muted); + box-shadow:2px 0 8px rgba(0,0,0,.06); + transition:border-color .2s, color .2s, box-shadow .2s; +} +.collab-rail-handle:hover{ border-color:var(--line-strong); color:var(--txt-2); box-shadow:2px 0 12px rgba(0,0,0,.1); } +.collab-rail-grip{ + width:3px; height:18px; border-radius:2px; + background:linear-gradient(180deg, transparent, var(--line-strong) 20%, var(--line-strong) 80%, transparent); + opacity:.55; +} +.collab-rail-chev{ width:12px; height:12px; flex:0 0 auto; transition:transform .22s ease-out; } +.page.page--chat-ui[data-page="collab"].collab-prog-open .collab-rail-chev{ transform:rotate(180deg); } +.collab-rail-badge{ + display:flex; flex-direction:column; align-items:center; gap:2px; + font-size:10px; font-weight:500; line-height:1; + font-family:var(--font-num); font-variant-numeric:var(--font-num-variant); +} +.collab-rail-badge.pulse{ animation:collab-rail-pulse .55s ease-out; } +@keyframes collab-rail-pulse{ + 0%{ transform:scale(1); } + 35%{ transform:scale(1.12); } + 100%{ transform:scale(1); } +} +/* 把手运行数:转圈与呼吸上下分开,转圈内不叠绿点 */ +.collab-rail-spin{ + display:block; + width:12px; height:12px; + margin:0 auto; + border-radius:50%; + background:transparent; + border:2px solid color-mix(in srgb, var(--ok) 22%, transparent); + border-top-color:var(--ok); + animation:collab-rail-spin .8s linear infinite; +} +@keyframes collab-rail-spin{ to{ transform:rotate(360deg); } } +.collab-rail-dot{ width:6px; height:6px; border-radius:50%; background:var(--ok); flex:0 0 auto; } +.collab-rail-run .n{ color:var(--ok); } +.collab-rail-done .n{ color:var(--muted); } +.collab-rail-done .collab-rail-dot{ background:var(--muted2); } +.collab-rail-issue .n{ color:var(--danger); } +.collab-rail-dot--danger{ background:var(--danger-dot); } +.collab-prog-panel{ + position:absolute; top:0; left:0; bottom:0; width:232px; z-index:12; + display:flex; flex-direction:column; overflow:hidden; + background:var(--panel); border-right:1px solid var(--line); + box-shadow:4px 0 16px rgba(0,0,0,.06); + transform:translateX(-100%); transition:transform .22s ease-out; + pointer-events:none; +} +.page.page--chat-ui[data-page="collab"].collab-prog-open .collab-prog-panel{ + transform:translateX(0); pointer-events:auto; +} +.collab-prog-panel-head{ + flex:0 0 auto; display:flex; align-items:center; justify-content:space-between; gap:6px; + padding:8px 8px 4px 12px; + font-size:13px; font-weight:600; color:var(--txt-strong); +} +.collab-prog-panel-head .ic-btn{ width:26px; height:26px; } +.collab-prog-panel-head .ic-btn svg{ width:14px; height:14px; } +.collab-prog-stats{ + flex:0 0 auto; display:flex; flex-wrap:wrap; gap:5px; + padding:2px 10px 5px; +} +.collab-stat{ + display:inline-flex; align-items:center; gap:4px; + font-size:10px; font-weight:500; padding:2px 7px; border-radius:4px; + line-height:1.35; +} +.collab-stat--running{ color:var(--ok); background:color-mix(in srgb, var(--ok) 10%, var(--panel)); } +.collab-stat--done{ color:var(--muted); background:color-mix(in srgb, var(--muted) 10%, var(--panel)); } +.collab-prog-stats .ga-status-breathe--sm{ --breathe-box:8px; } +.collab-prog-stats .collab-rail-dot{ width:5px; height:5px; } +.collab-stat--done .collab-rail-dot{ background:var(--muted2); } +.collab-stat .n{ font-family:var(--font-num); font-variant-numeric:var(--font-num-variant); font-weight:500; font-size:10px; } +.collab-progress-empty{ + flex:0 0 auto; font-size:12px; color:var(--muted); line-height:1.35; + padding:4px 10px 2px; +} +#collab-workers{ + flex:1 1 0; min-height:0; overflow-y:auto; padding:6px 10px 12px; +} +.collab-card{ + position:relative; + border:1px solid var(--line); border-radius:6px; background:var(--card); + padding:8px 10px 8px 12px; margin-bottom:6px; border-left:3px solid var(--collab-st, var(--line)); + box-shadow:0 1px 4px rgba(0,0,0,.04); + transition:border-color .3s, box-shadow .3s, transform .2s; +} +.collab-card.pulse{ animation:collab-rail-pulse .55s ease-out; } +.collab-card:hover{ transform:translateY(-1px); box-shadow:0 4px 14px rgba(0,0,0,.07); } +.collab-card--running{ --collab-st:var(--ok); } +.collab-card--reported{ --collab-st:var(--muted); } +.collab-card--paused{ --collab-st:var(--amber); } +.collab-card--failed{ --collab-st:var(--danger); } +.collab-card--terminated{ --collab-st:var(--line-strong); } +.collab-card-st{ display:flex; align-items:center; gap:5px; font-size:11px; color:var(--muted); margin-bottom:4px; flex-wrap:wrap; } +.collab-dot{ width:7px; height:7px; border-radius:50%; background:var(--collab-st); flex:0 0 auto; } +.collab-st-ic{ display:inline-flex; align-items:center; justify-content:center; width:14px; height:14px; font-size:10px; font-weight:500; flex:0 0 auto; } +.collab-st-ic--ok{ color:var(--ok); } +.collab-st-ic--done{ color:var(--muted); } +.collab-st-ic--warn{ color:var(--danger); } +.collab-st-ic--pause,.collab-st-ic--off{ color:var(--muted); } +.collab-card-time{ margin-left:auto; font-size:10px; color:var(--muted); opacity:.85; } +.collab-card-title{ font-size:13px; font-weight:500; color:var(--txt-strong); margin-bottom:3px; line-height:1.35; } +.collab-card-sum{ font-size:11px; color:var(--muted); line-height:1.35; cursor:pointer; } +.collab-drawer-wrap{ position:fixed; inset:0; z-index:550; display:flex; } +.collab-drawer-backdrop{ position:absolute; inset:0; background:var(--overlay); } +.collab-drawer{ + position:absolute; right:0; top:0; bottom:0; width:min(420px,85vw); + background:var(--panel); border-left:1px solid var(--line); + box-shadow:var(--shadow-modal); display:flex; flex-direction:column; + animation:collabDrawerIn .2s ease-out; +} +@keyframes collabDrawerIn{ from{ transform:translateX(100%); } to{ transform:translateX(0); } } +.collab-drawer-head{ + display:flex; align-items:center; justify-content:space-between; + padding:14px 16px; border-bottom:1px solid var(--line-soft); +} +.collab-drawer-title{ font-size:14px; font-weight:600; color:var(--txt-strong); } +.collab-drawer-body{ + flex:1; overflow-y:auto; padding:16px; font-size:13px; line-height:1.55; color:var(--txt); +} +.collab-drawer-body p,.collab-drawer-body ul,.collab-drawer-body ol,.collab-drawer-body pre{ margin:0 0 .5em; } +.collab-drawer-body code{ font-size:12px; background:var(--field-bg); padding:1px 4px; border-radius:4px; } +.collab-drawer-body pre code{ display:block; padding:8px; border-radius:6px; white-space:pre-wrap; } +.collab-msg-enter{ animation:collab-msg-in .35s ease-out both; } +.bubble.sys .collab-wait-dots{ + display:inline-flex; align-items:center; justify-content:center; gap:5px; + vertical-align:middle; padding:2px 0; +} +.collab-wait-dots i{ + display:block; width:5px; height:5px; border-radius:50%; background:var(--muted); + animation:collab-wait-dot 1.2s ease-in-out infinite; font-style:normal; +} +.collab-wait-dots i:nth-child(1){ animation-delay:0s; } +.collab-wait-dots i:nth-child(2){ animation-delay:.2s; } +.collab-wait-dots i:nth-child(3){ animation-delay:.4s; } +@keyframes collab-wait-dot{ + 0%,80%,100%{ opacity:.35; transform:translateY(0); } + 40%{ opacity:1; transform:translateY(-3px); } +} +@keyframes collab-msg-in{ + from{ opacity:0; transform:translateY(8px); } + to{ opacity:1; transform:translateY(0); } +} +.collab-guide{ width:100%; max-width:var(--chat-col-w); margin:0 auto; } +.collab-guide .feature-head{ text-align:center; margin-bottom:22px; } +.collab-guide .page-title{ font-size:20px; line-height:1.35; margin-bottom:2px; } +.collab-guide .page-sub{ font-size:13px; line-height:1.55; margin-top:10px; margin-bottom:0; } +.collab-guide-steps{ + display:grid; grid-template-columns:repeat(4, minmax(0, 1fr)); gap:48px 56px; + margin:0 0 8px; align-items:start; +} +.collab-guide-step{ + display:flex; flex-direction:column; align-items:center; gap:22px; + text-align:center; min-height:100%; +} +.collab-guide-ic{ + flex:0 0 auto; width:52px; height:52px; border-radius:14px; + display:flex; align-items:center; justify-content:center; + background:color-mix(in srgb, var(--accent) 10%, var(--panel)); + color:var(--accent); + border:1px solid color-mix(in srgb, var(--accent) 16%, var(--line)); +} +.collab-guide-ic svg{ width:24px; height:24px; } +.collab-guide-txt{ display:flex; flex-direction:column; gap:12px; width:100%; } +.collab-guide-label{ font-size:14px; font-weight:500; color:var(--txt-strong); line-height:1.35; } +.collab-guide-desc{ font-size:12px; font-weight:400; font-style:italic; color:var(--muted); line-height:1.55; } +.collab-nav-badge{ + margin-left:auto; min-width:18px; height:18px; padding:0 5px; border-radius:999px; + background:var(--ok); color:#fff; font-size:10px; font-weight:500; line-height:1; text-align:center; +} +.page.page--chat-ui[data-page="collab"] > .chat-shell > .chat-panel > .collab-quick{ + flex:0 0 auto; + display:flex; flex-wrap:wrap; gap:8px; +} +@media (max-width:900px){ + .collab-guide-steps{ grid-template-columns:repeat(2, minmax(0, 1fr)); gap:40px 32px; } + .collab-guide-step{ gap:20px; } + .page.page--chat-ui[data-page="collab"].collab-prog-open .collab-rail{ left:min(232px, 72vw); } + .collab-prog-panel{ width:min(232px, 72vw); } +} diff --git a/frontends/desktop/public/vendor/marked.min.js b/frontends/desktop/public/vendor/marked.min.js new file mode 100644 index 000000000..4052d1b49 --- /dev/null +++ b/frontends/desktop/public/vendor/marked.min.js @@ -0,0 +1,6 @@ +/** + * marked v15.0.7 - a markdown parser + * Copyright (c) 2011-2025, Christopher Jeffrey. (MIT Licensed) + * https://github.com/markedjs/marked + */ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).marked={})}(this,(function(e){"use strict";function t(){return{async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null}}function n(t){e.defaults=t}e.defaults={async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null};const s={exec:()=>null};function r(e,t=""){let n="string"==typeof e?e:e.source;const s={replace:(e,t)=>{let r="string"==typeof t?t:t.source;return r=r.replace(i.caret,"$1"),n=n.replace(e,r),s},getRegex:()=>new RegExp(n,t)};return s}const i={codeRemoveIndent:/^(?: {1,4}| {0,3}\t)/gm,outputLinkReplace:/\\([\[\]])/g,indentCodeCompensation:/^(\s+)(?:```)/,beginningSpace:/^\s+/,endingHash:/#$/,startingSpaceChar:/^ /,endingSpaceChar:/ $/,nonSpaceChar:/[^ ]/,newLineCharGlobal:/\n/g,tabCharGlobal:/\t/g,multipleSpaceGlobal:/\s+/g,blankLine:/^[ \t]*$/,doubleBlankLine:/\n[ \t]*\n[ \t]*$/,blockquoteStart:/^ {0,3}>/,blockquoteSetextReplace:/\n {0,3}((?:=+|-+) *)(?=\n|$)/g,blockquoteSetextReplace2:/^ {0,3}>[ \t]?/gm,listReplaceTabs:/^\t+/,listReplaceNesting:/^ {1,4}(?=( {4})*[^ ])/g,listIsTask:/^\[[ xX]\] /,listReplaceTask:/^\[[ xX]\] +/,anyLine:/\n.*\n/,hrefBrackets:/^<(.*)>$/,tableDelimiter:/[:|]/,tableAlignChars:/^\||\| *$/g,tableRowBlankLine:/\n[ \t]*$/,tableAlignRight:/^ *-+: *$/,tableAlignCenter:/^ *:-+: *$/,tableAlignLeft:/^ *:-+ *$/,startATag:/^/i,startPreScriptTag:/^<(pre|code|kbd|script)(\s|>)/i,endPreScriptTag:/^<\/(pre|code|kbd|script)(\s|>)/i,startAngleBracket:/^$/,pedanticHrefTitle:/^([^'"]*[^\s])\s+(['"])(.*)\2/,unicodeAlphaNumeric:/[\p{L}\p{N}]/u,escapeTest:/[&<>"']/,escapeReplace:/[&<>"']/g,escapeTestNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,escapeReplaceNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g,unescapeTest:/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi,caret:/(^|[^\[])\^/g,percentDecode:/%25/g,findPipe:/\|/g,splitPipe:/ \|/,slashPipe:/\\\|/g,carriageReturn:/\r\n|\r/g,spaceLine:/^ +$/gm,notSpaceStart:/^\S*/,endingNewline:/\n$/,listItemRegex:e=>new RegExp(`^( {0,3}${e})((?:[\t ][^\\n]*)?(?:\\n|$))`),nextBulletRegex:e=>new RegExp(`^ {0,${Math.min(3,e-1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ \t][^\\n]*)?(?:\\n|$))`),hrRegex:e=>new RegExp(`^ {0,${Math.min(3,e-1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`),fencesBeginRegex:e=>new RegExp(`^ {0,${Math.min(3,e-1)}}(?:\`\`\`|~~~)`),headingBeginRegex:e=>new RegExp(`^ {0,${Math.min(3,e-1)}}#`),htmlBeginRegex:e=>new RegExp(`^ {0,${Math.min(3,e-1)}}<(?:[a-z].*>|!--)`,"i")},l=/^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,o=/(?:[*+-]|\d{1,9}[.)])/,a=/^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html|table))+?)\n {0,3}(=+|-+) *(?:\n+|$)/,c=r(a).replace(/bull/g,o).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).replace(/\|table/g,"").getRegex(),h=r(a).replace(/bull/g,o).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).replace(/table/g,/ {0,3}\|?(?:[:\- ]*\|)+[\:\- ]*\n/).getRegex(),p=/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,u=/(?!\s*\])(?:\\.|[^\[\]\\])+/,g=r(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label",u).replace("title",/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(),k=r(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g,o).getRegex(),d="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",f=/|$))/,x=r("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|\\n*|$)|\\n*|$)|)[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$)|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$))","i").replace("comment",f).replace("tag",d).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),b=r(p).replace("hr",l).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("|table","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",d).getRegex(),w={blockquote:r(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph",b).getRegex(),code:/^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/,def:g,fences:/^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,heading:/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,hr:l,html:x,lheading:c,list:k,newline:/^(?:[ \t]*(?:\n|$))+/,paragraph:b,table:s,text:/^[^\n]+/},m=r("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr",l).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("blockquote"," {0,3}>").replace("code","(?: {4}| {0,3}\t)[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",d).getRegex(),y={...w,lheading:h,table:m,paragraph:r(p).replace("hr",l).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("table",m).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",d).getRegex()},$={...w,html:r("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",f).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:s,lheading:/^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,paragraph:r(p).replace("hr",l).replace("heading"," *#{1,6} *[^\n]").replace("lheading",c).replace("|table","").replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").replace("|tag","").getRegex()},R=/^( {2,}|\\)\n(?!\s*$)/,S=/[\p{P}\p{S}]/u,T=/[\s\p{P}\p{S}]/u,z=/[^\s\p{P}\p{S}]/u,A=r(/^((?![*_])punctSpace)/,"u").replace(/punctSpace/g,T).getRegex(),_=/(?!~)[\p{P}\p{S}]/u,P=/^(?:\*+(?:((?!\*)punct)|[^\s*]))|^_+(?:((?!_)punct)|([^\s_]))/,I=r(P,"u").replace(/punct/g,S).getRegex(),L=r(P,"u").replace(/punct/g,_).getRegex(),B="^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)",C=r(B,"gu").replace(/notPunctSpace/g,z).replace(/punctSpace/g,T).replace(/punct/g,S).getRegex(),q=r(B,"gu").replace(/notPunctSpace/g,/(?:[^\s\p{P}\p{S}]|~)/u).replace(/punctSpace/g,/(?!~)[\s\p{P}\p{S}]/u).replace(/punct/g,_).getRegex(),E=r("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)","gu").replace(/notPunctSpace/g,z).replace(/punctSpace/g,T).replace(/punct/g,S).getRegex(),Z=r(/\\(punct)/,"gu").replace(/punct/g,S).getRegex(),v=r(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme",/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email",/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(),D=r(f).replace("(?:--\x3e|$)","--\x3e").getRegex(),M=r("^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^").replace("comment",D).replace("attribute",/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(),O=/(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,Q=r(/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/).replace("label",O).replace("href",/<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/).replace("title",/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(),j=r(/^!?\[(label)\]\[(ref)\]/).replace("label",O).replace("ref",u).getRegex(),N=r(/^!?\[(ref)\](?:\[\])?/).replace("ref",u).getRegex(),G={_backpedal:s,anyPunctuation:Z,autolink:v,blockSkip:/\[[^[\]]*?\]\((?:\\.|[^\\\(\)]|\((?:\\.|[^\\\(\)])*\))*\)|`[^`]*?`|<[^<>]*?>/g,br:R,code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,del:s,emStrongLDelim:I,emStrongRDelimAst:C,emStrongRDelimUnd:E,escape:/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,link:Q,nolink:N,punctuation:A,reflink:j,reflinkSearch:r("reflink|nolink(?!\\()","g").replace("reflink",j).replace("nolink",N).getRegex(),tag:M,text:/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\":">",'"':""","'":"'"},V=e=>K[e];function W(e,t){if(t){if(i.escapeTest.test(e))return e.replace(i.escapeReplace,V)}else if(i.escapeTestNoEncode.test(e))return e.replace(i.escapeReplaceNoEncode,V);return e}function Y(e){try{e=encodeURI(e).replace(i.percentDecode,"%")}catch{return null}return e}function ee(e,t){const n=e.replace(i.findPipe,((e,t,n)=>{let s=!1,r=t;for(;--r>=0&&"\\"===n[r];)s=!s;return s?"|":" |"})).split(i.splitPipe);let s=0;if(n[0].trim()||n.shift(),n.length>0&&!n.at(-1)?.trim()&&n.pop(),t)if(n.length>t)n.splice(t);else for(;n.length0)return{type:"space",raw:t[0]}}code(e){const t=this.rules.block.code.exec(e);if(t){const e=t[0].replace(this.rules.other.codeRemoveIndent,"");return{type:"code",raw:t[0],codeBlockStyle:"indented",text:this.options.pedantic?e:te(e,"\n")}}}fences(e){const t=this.rules.block.fences.exec(e);if(t){const e=t[0],n=function(e,t,n){const s=e.match(n.other.indentCodeCompensation);if(null===s)return t;const r=s[1];return t.split("\n").map((e=>{const t=e.match(n.other.beginningSpace);if(null===t)return e;const[s]=t;return s.length>=r.length?e.slice(r.length):e})).join("\n")}(e,t[3]||"",this.rules);return{type:"code",raw:e,lang:t[2]?t[2].trim().replace(this.rules.inline.anyPunctuation,"$1"):t[2],text:n}}}heading(e){const t=this.rules.block.heading.exec(e);if(t){let e=t[2].trim();if(this.rules.other.endingHash.test(e)){const t=te(e,"#");this.options.pedantic?e=t.trim():t&&!this.rules.other.endingSpaceChar.test(t)||(e=t.trim())}return{type:"heading",raw:t[0],depth:t[1].length,text:e,tokens:this.lexer.inline(e)}}}hr(e){const t=this.rules.block.hr.exec(e);if(t)return{type:"hr",raw:te(t[0],"\n")}}blockquote(e){const t=this.rules.block.blockquote.exec(e);if(t){let e=te(t[0],"\n").split("\n"),n="",s="";const r=[];for(;e.length>0;){let t=!1;const i=[];let l;for(l=0;l1,r={type:"list",raw:"",ordered:s,start:s?+n.slice(0,-1):"",loose:!1,items:[]};n=s?`\\d{1,9}\\${n.slice(-1)}`:`\\${n}`,this.options.pedantic&&(n=s?n:"[*+-]");const i=this.rules.other.listItemRegex(n);let l=!1;for(;e;){let n=!1,s="",o="";if(!(t=i.exec(e)))break;if(this.rules.block.hr.test(e))break;s=t[0],e=e.substring(s.length);let a=t[2].split("\n",1)[0].replace(this.rules.other.listReplaceTabs,(e=>" ".repeat(3*e.length))),c=e.split("\n",1)[0],h=!a.trim(),p=0;if(this.options.pedantic?(p=2,o=a.trimStart()):h?p=t[1].length+1:(p=t[2].search(this.rules.other.nonSpaceChar),p=p>4?1:p,o=a.slice(p),p+=t[1].length),h&&this.rules.other.blankLine.test(c)&&(s+=c+"\n",e=e.substring(c.length+1),n=!0),!n){const t=this.rules.other.nextBulletRegex(p),n=this.rules.other.hrRegex(p),r=this.rules.other.fencesBeginRegex(p),i=this.rules.other.headingBeginRegex(p),l=this.rules.other.htmlBeginRegex(p);for(;e;){const u=e.split("\n",1)[0];let g;if(c=u,this.options.pedantic?(c=c.replace(this.rules.other.listReplaceNesting," "),g=c):g=c.replace(this.rules.other.tabCharGlobal," "),r.test(c))break;if(i.test(c))break;if(l.test(c))break;if(t.test(c))break;if(n.test(c))break;if(g.search(this.rules.other.nonSpaceChar)>=p||!c.trim())o+="\n"+g.slice(p);else{if(h)break;if(a.replace(this.rules.other.tabCharGlobal," ").search(this.rules.other.nonSpaceChar)>=4)break;if(r.test(a))break;if(i.test(a))break;if(n.test(a))break;o+="\n"+c}h||c.trim()||(h=!0),s+=u+"\n",e=e.substring(u.length+1),a=g.slice(p)}}r.loose||(l?r.loose=!0:this.rules.other.doubleBlankLine.test(s)&&(l=!0));let u,g=null;this.options.gfm&&(g=this.rules.other.listIsTask.exec(o),g&&(u="[ ] "!==g[0],o=o.replace(this.rules.other.listReplaceTask,""))),r.items.push({type:"list_item",raw:s,task:!!g,checked:u,loose:!1,text:o,tokens:[]}),r.raw+=s}const o=r.items.at(-1);if(!o)return;o.raw=o.raw.trimEnd(),o.text=o.text.trimEnd(),r.raw=r.raw.trimEnd();for(let e=0;e"space"===e.type)),n=t.length>0&&t.some((e=>this.rules.other.anyLine.test(e.raw)));r.loose=n}if(r.loose)for(let e=0;e({text:e,tokens:this.lexer.inline(e),header:!1,align:i.align[t]}))));return i}}lheading(e){const t=this.rules.block.lheading.exec(e);if(t)return{type:"heading",raw:t[0],depth:"="===t[2].charAt(0)?1:2,text:t[1],tokens:this.lexer.inline(t[1])}}paragraph(e){const t=this.rules.block.paragraph.exec(e);if(t){const e="\n"===t[1].charAt(t[1].length-1)?t[1].slice(0,-1):t[1];return{type:"paragraph",raw:t[0],text:e,tokens:this.lexer.inline(e)}}}text(e){const t=this.rules.block.text.exec(e);if(t)return{type:"text",raw:t[0],text:t[0],tokens:this.lexer.inline(t[0])}}escape(e){const t=this.rules.inline.escape.exec(e);if(t)return{type:"escape",raw:t[0],text:t[1]}}tag(e){const t=this.rules.inline.tag.exec(e);if(t)return!this.lexer.state.inLink&&this.rules.other.startATag.test(t[0])?this.lexer.state.inLink=!0:this.lexer.state.inLink&&this.rules.other.endATag.test(t[0])&&(this.lexer.state.inLink=!1),!this.lexer.state.inRawBlock&&this.rules.other.startPreScriptTag.test(t[0])?this.lexer.state.inRawBlock=!0:this.lexer.state.inRawBlock&&this.rules.other.endPreScriptTag.test(t[0])&&(this.lexer.state.inRawBlock=!1),{type:"html",raw:t[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,block:!1,text:t[0]}}link(e){const t=this.rules.inline.link.exec(e);if(t){const e=t[2].trim();if(!this.options.pedantic&&this.rules.other.startAngleBracket.test(e)){if(!this.rules.other.endAngleBracket.test(e))return;const t=te(e.slice(0,-1),"\\");if((e.length-t.length)%2==0)return}else{const e=function(e,t){if(-1===e.indexOf(t[1]))return-1;let n=0;for(let s=0;s-1){const n=(0===t[0].indexOf("!")?5:4)+t[1].length+e;t[2]=t[2].substring(0,e),t[0]=t[0].substring(0,n).trim(),t[3]=""}}let n=t[2],s="";if(this.options.pedantic){const e=this.rules.other.pedanticHrefTitle.exec(n);e&&(n=e[1],s=e[3])}else s=t[3]?t[3].slice(1,-1):"";return n=n.trim(),this.rules.other.startAngleBracket.test(n)&&(n=this.options.pedantic&&!this.rules.other.endAngleBracket.test(e)?n.slice(1):n.slice(1,-1)),ne(t,{href:n?n.replace(this.rules.inline.anyPunctuation,"$1"):n,title:s?s.replace(this.rules.inline.anyPunctuation,"$1"):s},t[0],this.lexer,this.rules)}}reflink(e,t){let n;if((n=this.rules.inline.reflink.exec(e))||(n=this.rules.inline.nolink.exec(e))){const e=t[(n[2]||n[1]).replace(this.rules.other.multipleSpaceGlobal," ").toLowerCase()];if(!e){const e=n[0].charAt(0);return{type:"text",raw:e,text:e}}return ne(n,e,n[0],this.lexer,this.rules)}}emStrong(e,t,n=""){let s=this.rules.inline.emStrongLDelim.exec(e);if(!s)return;if(s[3]&&n.match(this.rules.other.unicodeAlphaNumeric))return;if(!(s[1]||s[2]||"")||!n||this.rules.inline.punctuation.exec(n)){const n=[...s[0]].length-1;let r,i,l=n,o=0;const a="*"===s[0][0]?this.rules.inline.emStrongRDelimAst:this.rules.inline.emStrongRDelimUnd;for(a.lastIndex=0,t=t.slice(-1*e.length+n);null!=(s=a.exec(t));){if(r=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!r)continue;if(i=[...r].length,s[3]||s[4]){l+=i;continue}if((s[5]||s[6])&&n%3&&!((n+i)%3)){o+=i;continue}if(l-=i,l>0)continue;i=Math.min(i,i+l+o);const t=[...s[0]][0].length,a=e.slice(0,n+s.index+t+i);if(Math.min(n,i)%2){const e=a.slice(1,-1);return{type:"em",raw:a,text:e,tokens:this.lexer.inlineTokens(e)}}const c=a.slice(2,-2);return{type:"strong",raw:a,text:c,tokens:this.lexer.inlineTokens(c)}}}}codespan(e){const t=this.rules.inline.code.exec(e);if(t){let e=t[2].replace(this.rules.other.newLineCharGlobal," ");const n=this.rules.other.nonSpaceChar.test(e),s=this.rules.other.startingSpaceChar.test(e)&&this.rules.other.endingSpaceChar.test(e);return n&&s&&(e=e.substring(1,e.length-1)),{type:"codespan",raw:t[0],text:e}}}br(e){const t=this.rules.inline.br.exec(e);if(t)return{type:"br",raw:t[0]}}del(e){const t=this.rules.inline.del.exec(e);if(t)return{type:"del",raw:t[0],text:t[2],tokens:this.lexer.inlineTokens(t[2])}}autolink(e){const t=this.rules.inline.autolink.exec(e);if(t){let e,n;return"@"===t[2]?(e=t[1],n="mailto:"+e):(e=t[1],n=e),{type:"link",raw:t[0],text:e,href:n,tokens:[{type:"text",raw:e,text:e}]}}}url(e){let t;if(t=this.rules.inline.url.exec(e)){let e,n;if("@"===t[2])e=t[0],n="mailto:"+e;else{let s;do{s=t[0],t[0]=this.rules.inline._backpedal.exec(t[0])?.[0]??""}while(s!==t[0]);e=t[0],n="www."===t[1]?"http://"+t[0]:t[0]}return{type:"link",raw:t[0],text:e,href:n,tokens:[{type:"text",raw:e,text:e}]}}}inlineText(e){const t=this.rules.inline.text.exec(e);if(t){const e=this.lexer.state.inRawBlock;return{type:"text",raw:t[0],text:t[0],escaped:e}}}}class re{tokens;options;state;tokenizer;inlineQueue;constructor(t){this.tokens=[],this.tokens.links=Object.create(null),this.options=t||e.defaults,this.options.tokenizer=this.options.tokenizer||new se,this.tokenizer=this.options.tokenizer,this.tokenizer.options=this.options,this.tokenizer.lexer=this,this.inlineQueue=[],this.state={inLink:!1,inRawBlock:!1,top:!0};const n={other:i,block:U.normal,inline:J.normal};this.options.pedantic?(n.block=U.pedantic,n.inline=J.pedantic):this.options.gfm&&(n.block=U.gfm,this.options.breaks?n.inline=J.breaks:n.inline=J.gfm),this.tokenizer.rules=n}static get rules(){return{block:U,inline:J}}static lex(e,t){return new re(t).lex(e)}static lexInline(e,t){return new re(t).inlineTokens(e)}lex(e){e=e.replace(i.carriageReturn,"\n"),this.blockTokens(e,this.tokens);for(let e=0;e!!(s=n.call({lexer:this},e,t))&&(e=e.substring(s.raw.length),t.push(s),!0))))continue;if(s=this.tokenizer.space(e)){e=e.substring(s.raw.length);const n=t.at(-1);1===s.raw.length&&void 0!==n?n.raw+="\n":t.push(s);continue}if(s=this.tokenizer.code(e)){e=e.substring(s.raw.length);const n=t.at(-1);"paragraph"===n?.type||"text"===n?.type?(n.raw+="\n"+s.raw,n.text+="\n"+s.text,this.inlineQueue.at(-1).src=n.text):t.push(s);continue}if(s=this.tokenizer.fences(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.heading(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.hr(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.blockquote(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.list(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.html(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.def(e)){e=e.substring(s.raw.length);const n=t.at(-1);"paragraph"===n?.type||"text"===n?.type?(n.raw+="\n"+s.raw,n.text+="\n"+s.raw,this.inlineQueue.at(-1).src=n.text):this.tokens.links[s.tag]||(this.tokens.links[s.tag]={href:s.href,title:s.title});continue}if(s=this.tokenizer.table(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.lheading(e)){e=e.substring(s.raw.length),t.push(s);continue}let r=e;if(this.options.extensions?.startBlock){let t=1/0;const n=e.slice(1);let s;this.options.extensions.startBlock.forEach((e=>{s=e.call({lexer:this},n),"number"==typeof s&&s>=0&&(t=Math.min(t,s))})),t<1/0&&t>=0&&(r=e.substring(0,t+1))}if(this.state.top&&(s=this.tokenizer.paragraph(r))){const i=t.at(-1);n&&"paragraph"===i?.type?(i.raw+="\n"+s.raw,i.text+="\n"+s.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=i.text):t.push(s),n=r.length!==e.length,e=e.substring(s.raw.length)}else if(s=this.tokenizer.text(e)){e=e.substring(s.raw.length);const n=t.at(-1);"text"===n?.type?(n.raw+="\n"+s.raw,n.text+="\n"+s.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=n.text):t.push(s)}else if(e){const t="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(t);break}throw new Error(t)}}return this.state.top=!0,t}inline(e,t=[]){return this.inlineQueue.push({src:e,tokens:t}),t}inlineTokens(e,t=[]){let n=e,s=null;if(this.tokens.links){const e=Object.keys(this.tokens.links);if(e.length>0)for(;null!=(s=this.tokenizer.rules.inline.reflinkSearch.exec(n));)e.includes(s[0].slice(s[0].lastIndexOf("[")+1,-1))&&(n=n.slice(0,s.index)+"["+"a".repeat(s[0].length-2)+"]"+n.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex))}for(;null!=(s=this.tokenizer.rules.inline.blockSkip.exec(n));)n=n.slice(0,s.index)+"["+"a".repeat(s[0].length-2)+"]"+n.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);for(;null!=(s=this.tokenizer.rules.inline.anyPunctuation.exec(n));)n=n.slice(0,s.index)+"++"+n.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);let r=!1,i="";for(;e;){let s;if(r||(i=""),r=!1,this.options.extensions?.inline?.some((n=>!!(s=n.call({lexer:this},e,t))&&(e=e.substring(s.raw.length),t.push(s),!0))))continue;if(s=this.tokenizer.escape(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.tag(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.link(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.reflink(e,this.tokens.links)){e=e.substring(s.raw.length);const n=t.at(-1);"text"===s.type&&"text"===n?.type?(n.raw+=s.raw,n.text+=s.text):t.push(s);continue}if(s=this.tokenizer.emStrong(e,n,i)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.codespan(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.br(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.del(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.autolink(e)){e=e.substring(s.raw.length),t.push(s);continue}if(!this.state.inLink&&(s=this.tokenizer.url(e))){e=e.substring(s.raw.length),t.push(s);continue}let l=e;if(this.options.extensions?.startInline){let t=1/0;const n=e.slice(1);let s;this.options.extensions.startInline.forEach((e=>{s=e.call({lexer:this},n),"number"==typeof s&&s>=0&&(t=Math.min(t,s))})),t<1/0&&t>=0&&(l=e.substring(0,t+1))}if(s=this.tokenizer.inlineText(l)){e=e.substring(s.raw.length),"_"!==s.raw.slice(-1)&&(i=s.raw.slice(-1)),r=!0;const n=t.at(-1);"text"===n?.type?(n.raw+=s.raw,n.text+=s.text):t.push(s)}else if(e){const t="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(t);break}throw new Error(t)}}return t}}class ie{options;parser;constructor(t){this.options=t||e.defaults}space(e){return""}code({text:e,lang:t,escaped:n}){const s=(t||"").match(i.notSpaceStart)?.[0],r=e.replace(i.endingNewline,"")+"\n";return s?'
'+(n?r:W(r,!0))+"
\n":"
"+(n?r:W(r,!0))+"
\n"}blockquote({tokens:e}){return`
\n${this.parser.parse(e)}
\n`}html({text:e}){return e}heading({tokens:e,depth:t}){return`${this.parser.parseInline(e)}\n`}hr(e){return"
\n"}list(e){const t=e.ordered,n=e.start;let s="";for(let t=0;t\n"+s+"\n"}listitem(e){let t="";if(e.task){const n=this.checkbox({checked:!!e.checked});e.loose?"paragraph"===e.tokens[0]?.type?(e.tokens[0].text=n+" "+e.tokens[0].text,e.tokens[0].tokens&&e.tokens[0].tokens.length>0&&"text"===e.tokens[0].tokens[0].type&&(e.tokens[0].tokens[0].text=n+" "+W(e.tokens[0].tokens[0].text),e.tokens[0].tokens[0].escaped=!0)):e.tokens.unshift({type:"text",raw:n+" ",text:n+" ",escaped:!0}):t+=n+" "}return t+=this.parser.parse(e.tokens,!!e.loose),`
  • ${t}
  • \n`}checkbox({checked:e}){return"'}paragraph({tokens:e}){return`

    ${this.parser.parseInline(e)}

    \n`}table(e){let t="",n="";for(let t=0;t${s}`),"\n\n"+t+"\n"+s+"
    \n"}tablerow({text:e}){return`\n${e}\n`}tablecell(e){const t=this.parser.parseInline(e.tokens),n=e.header?"th":"td";return(e.align?`<${n} align="${e.align}">`:`<${n}>`)+t+`\n`}strong({tokens:e}){return`${this.parser.parseInline(e)}`}em({tokens:e}){return`${this.parser.parseInline(e)}`}codespan({text:e}){return`${W(e,!0)}`}br(e){return"
    "}del({tokens:e}){return`${this.parser.parseInline(e)}`}link({href:e,title:t,tokens:n}){const s=this.parser.parseInline(n),r=Y(e);if(null===r)return s;let i='
    ",i}image({href:e,title:t,text:n}){const s=Y(e);if(null===s)return W(n);let r=`${n}{const r=e[s].flat(1/0);n=n.concat(this.walkTokens(r,t))})):e.tokens&&(n=n.concat(this.walkTokens(e.tokens,t)))}}return n}use(...e){const t=this.defaults.extensions||{renderers:{},childTokens:{}};return e.forEach((e=>{const n={...e};if(n.async=this.defaults.async||n.async||!1,e.extensions&&(e.extensions.forEach((e=>{if(!e.name)throw new Error("extension name required");if("renderer"in e){const n=t.renderers[e.name];t.renderers[e.name]=n?function(...t){let s=e.renderer.apply(this,t);return!1===s&&(s=n.apply(this,t)),s}:e.renderer}if("tokenizer"in e){if(!e.level||"block"!==e.level&&"inline"!==e.level)throw new Error("extension level must be 'block' or 'inline'");const n=t[e.level];n?n.unshift(e.tokenizer):t[e.level]=[e.tokenizer],e.start&&("block"===e.level?t.startBlock?t.startBlock.push(e.start):t.startBlock=[e.start]:"inline"===e.level&&(t.startInline?t.startInline.push(e.start):t.startInline=[e.start]))}"childTokens"in e&&e.childTokens&&(t.childTokens[e.name]=e.childTokens)})),n.extensions=t),e.renderer){const t=this.defaults.renderer||new ie(this.defaults);for(const n in e.renderer){if(!(n in t))throw new Error(`renderer '${n}' does not exist`);if(["options","parser"].includes(n))continue;const s=n,r=e.renderer[s],i=t[s];t[s]=(...e)=>{let n=r.apply(t,e);return!1===n&&(n=i.apply(t,e)),n||""}}n.renderer=t}if(e.tokenizer){const t=this.defaults.tokenizer||new se(this.defaults);for(const n in e.tokenizer){if(!(n in t))throw new Error(`tokenizer '${n}' does not exist`);if(["options","rules","lexer"].includes(n))continue;const s=n,r=e.tokenizer[s],i=t[s];t[s]=(...e)=>{let n=r.apply(t,e);return!1===n&&(n=i.apply(t,e)),n}}n.tokenizer=t}if(e.hooks){const t=this.defaults.hooks||new ae;for(const n in e.hooks){if(!(n in t))throw new Error(`hook '${n}' does not exist`);if(["options","block"].includes(n))continue;const s=n,r=e.hooks[s],i=t[s];ae.passThroughHooks.has(n)?t[s]=e=>{if(this.defaults.async)return Promise.resolve(r.call(t,e)).then((e=>i.call(t,e)));const n=r.call(t,e);return i.call(t,n)}:t[s]=(...e)=>{let n=r.apply(t,e);return!1===n&&(n=i.apply(t,e)),n}}n.hooks=t}if(e.walkTokens){const t=this.defaults.walkTokens,s=e.walkTokens;n.walkTokens=function(e){let n=[];return n.push(s.call(this,e)),t&&(n=n.concat(t.call(this,e))),n}}this.defaults={...this.defaults,...n}})),this}setOptions(e){return this.defaults={...this.defaults,...e},this}lexer(e,t){return re.lex(e,t??this.defaults)}parser(e,t){return oe.parse(e,t??this.defaults)}parseMarkdown(e){return(t,n)=>{const s={...n},r={...this.defaults,...s},i=this.onError(!!r.silent,!!r.async);if(!0===this.defaults.async&&!1===s.async)return i(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));if(null==t)return i(new Error("marked(): input parameter is undefined or null"));if("string"!=typeof t)return i(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(t)+", string expected"));r.hooks&&(r.hooks.options=r,r.hooks.block=e);const l=r.hooks?r.hooks.provideLexer():e?re.lex:re.lexInline,o=r.hooks?r.hooks.provideParser():e?oe.parse:oe.parseInline;if(r.async)return Promise.resolve(r.hooks?r.hooks.preprocess(t):t).then((e=>l(e,r))).then((e=>r.hooks?r.hooks.processAllTokens(e):e)).then((e=>r.walkTokens?Promise.all(this.walkTokens(e,r.walkTokens)).then((()=>e)):e)).then((e=>o(e,r))).then((e=>r.hooks?r.hooks.postprocess(e):e)).catch(i);try{r.hooks&&(t=r.hooks.preprocess(t));let e=l(t,r);r.hooks&&(e=r.hooks.processAllTokens(e)),r.walkTokens&&this.walkTokens(e,r.walkTokens);let n=o(e,r);return r.hooks&&(n=r.hooks.postprocess(n)),n}catch(e){return i(e)}}}onError(e,t){return n=>{if(n.message+="\nPlease report this to https://github.com/markedjs/marked.",e){const e="

    An error occurred:

    "+W(n.message+"",!0)+"
    ";return t?Promise.resolve(e):e}if(t)return Promise.reject(n);throw n}}}const he=new ce;function pe(e,t){return he.parse(e,t)}pe.options=pe.setOptions=function(e){return he.setOptions(e),pe.defaults=he.defaults,n(pe.defaults),pe},pe.getDefaults=t,pe.defaults=e.defaults,pe.use=function(...e){return he.use(...e),pe.defaults=he.defaults,n(pe.defaults),pe},pe.walkTokens=function(e,t){return he.walkTokens(e,t)},pe.parseInline=he.parseInline,pe.Parser=oe,pe.parser=oe.parse,pe.Renderer=ie,pe.TextRenderer=le,pe.Lexer=re,pe.lexer=re.lex,pe.Tokenizer=se,pe.Hooks=ae,pe.parse=pe;const ue=pe.options,ge=pe.setOptions,ke=pe.use,de=pe.walkTokens,fe=pe.parseInline,xe=pe,be=oe.parse,we=re.lex;e.Hooks=ae,e.Lexer=re,e.Marked=ce,e.Parser=oe,e.Renderer=ie,e.TextRenderer=le,e.Tokenizer=se,e.getDefaults=t,e.lexer=we,e.marked=pe,e.options=ue,e.parse=xe,e.parseInline=fe,e.parser=be,e.setOptions=ge,e.use=ke,e.walkTokens=de})); diff --git a/frontends/desktop/scripts/gen_ds_store.py b/frontends/desktop/scripts/gen_ds_store.py new file mode 100644 index 000000000..e359434a9 --- /dev/null +++ b/frontends/desktop/scripts/gen_ds_store.py @@ -0,0 +1,68 @@ +"""Generate a .DS_Store file for DMG layout. + +Usage: python3 gen_ds_store.py + +Creates a .DS_Store that configures Finder to display: +- 540x380 window +- icon view, 128px icons +- at (140, 190), Applications at (400, 190) +""" +import sys +import struct +from ds_store import DSStore, DSStoreEntry +from mac_alias import Alias +import plistlib + +def main(): + output_path = sys.argv[1] + app_name = sys.argv[2] + + with DSStore.open(output_path, 'w+') as ds: + # Icon view properties for the folder + icvp = { + 'backgroundColorBlue': 1.0, + 'backgroundColorGreen': 1.0, + 'backgroundColorRed': 1.0, + 'backgroundType': 1, # 1 = solid color + 'gridOffsetX': 0.0, + 'gridOffsetY': 0.0, + 'gridSpacing': 100.0, + 'iconSize': 128.0, + 'labelOnBottom': True, + 'showIconPreview': True, + 'showItemInfo': False, + 'textSize': 13.0, + 'viewOptionsVersion': 1, + 'arrangeBy': 'none', + } + ds['.'] = DSStoreEntry('.', 'icvp', plistlib.dumps(icvp, fmt=plistlib.FMT_BINARY)) + + # Window bounds/settings + # vSrn = view style (icnv = icon view) + ds['.'] = DSStoreEntry('.', 'vSrn', 1) + + # bwsp = browser window settings plist + bwsp = { + 'WindowBounds': '{{100, 100}, {540, 380}}', + 'ShowPathbar': False, + 'ShowSidebar': False, + 'ShowStatusBar': False, + 'ShowToolbar': False, + 'ShowTabView': False, + 'SidebarWidth': 0, + } + ds['.'] = DSStoreEntry('.', 'bwsp', plistlib.dumps(bwsp, fmt=plistlib.FMT_BINARY)) + + # Icon positions (Iloc = icon location, 16 bytes: x(4) + y(4) + padding(8)) + # GenericAgent.app at (140, 190) + iloc_app = struct.pack('>II', 140, 190) + b'\xff\xff\xff\xff\xff\xff\x00\x00' + ds[app_name] = DSStoreEntry(app_name, 'Iloc', iloc_app) + + # Applications at (400, 190) + iloc_apps = struct.pack('>II', 400, 190) + b'\xff\xff\xff\xff\xff\xff\x00\x00' + ds['Applications'] = DSStoreEntry('Applications', 'Iloc', iloc_apps) + + print(f"Generated: {output_path}") + +if __name__ == '__main__': + main() diff --git a/frontends/desktop/scripts/post-dmg.sh b/frontends/desktop/scripts/post-dmg.sh new file mode 100644 index 000000000..50b58f0ea --- /dev/null +++ b/frontends/desktop/scripts/post-dmg.sh @@ -0,0 +1,153 @@ +#!/bin/bash +# Repackage a Tauri-bundled DMG into a clean DMG with proper Finder layout. +# Only contains .app + Applications symlink + .DS_Store for layout. +# No .VolumeIcon.icns, .background, .fseventsd or other debris. +# +# Usage: ./scripts/post-dmg.sh +# Requires: macOS (hdiutil), Python 3 with ds_store package + +set -euo pipefail + +DMG_PATH="${1:-}" +HDIUTIL_BIN="${HDIUTIL_BIN:-hdiutil}" +if [[ -z "$DMG_PATH" ]]; then + echo "Usage: $0 " >&2 + exit 1 +fi + +if [[ ! -f "$DMG_PATH" ]]; then + echo "Error: DMG not found: $DMG_PATH" >&2 + exit 1 +fi + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +DMG_DIR="$(cd "$(dirname "$DMG_PATH")" && pwd)" +DMG_NAME="$(basename "$DMG_PATH")" +STAGE_DIR="$(mktemp -d)" +RW_DMG="$(mktemp -u).dmg" + +cleanup() { + if [[ -n "${MOUNT_POINT:-}" ]] && mount | grep -q "$MOUNT_POINT"; then + "$HDIUTIL_BIN" detach "$MOUNT_POINT" -force 2>/dev/null || true + fi + rm -rf "$STAGE_DIR" "$RW_DMG" +} +trap cleanup EXIT + +# --- Step 1: Extract app from original DMG --- +echo "Mounting original DMG..." +MOUNT_OUTPUT="$("$HDIUTIL_BIN" attach "$DMG_PATH" -readonly -noverify -noautoopen -plist)" +MOUNT_POINT="$(echo "$MOUNT_OUTPUT" | grep -A1 'mount-point' | grep '' | sed 's/.*\(.*\)<\/string>.*/\1/' | head -1)" + +if [[ -z "$MOUNT_POINT" ]]; then + echo "Error: could not determine mount point" >&2 + exit 1 +fi + +APP_NAME="" +for item in "$MOUNT_POINT"/*.app; do + if [[ -d "$item" ]]; then + APP_NAME="$(basename "$item")" + ditto "$item" "$STAGE_DIR/$APP_NAME" + break + fi +done + +if [[ -z "$APP_NAME" ]]; then + echo "Error: no .app found in DMG" >&2 + exit 1 +fi + +"$HDIUTIL_BIN" detach "$MOUNT_POINT" -quiet +unset MOUNT_POINT + +# --- Step 2: Prepare stage directory --- +ln -s /Applications "$STAGE_DIR/Applications" + +# Generate .DS_Store with layout metadata +python3 -c " +import struct, plistlib, sys +sys.path.insert(0, '') +from ds_store import DSStore, DSStoreEntry + +app_name = '$APP_NAME' +output = '$STAGE_DIR/.DS_Store' + +entries = [] + +# Icon positions (Iloc: x(4) + y(4) + padding(8)) +iloc_app = struct.pack('>II', 140, 190) + b'\xff\xff\xff\xff\xff\xff\x00\x00' +entries.append(DSStoreEntry(app_name, 'Iloc', 'blob', iloc_app)) + +iloc_apps = struct.pack('>II', 400, 190) + b'\xff\xff\xff\xff\xff\xff\x00\x00' +entries.append(DSStoreEntry('Applications', 'Iloc', 'blob', iloc_apps)) + +# Icon view properties +icvp = { + 'backgroundColorBlue': 1.0, + 'backgroundColorGreen': 1.0, + 'backgroundColorRed': 1.0, + 'backgroundType': 1, + 'gridOffsetX': 0.0, + 'gridOffsetY': 0.0, + 'gridSpacing': 100.0, + 'iconSize': 128.0, + 'labelOnBottom': True, + 'showIconPreview': True, + 'showItemInfo': False, + 'textSize': 13.0, + 'viewOptionsVersion': 1, + 'arrangeBy': 'none', +} +entries.append(DSStoreEntry('.', 'icvp', 'blob', plistlib.dumps(icvp, fmt=plistlib.FMT_BINARY))) + +# View style (1 = icon view) +entries.append(DSStoreEntry('.', 'vSrn', 'long', 1)) + +# Browser window settings +bwsp = { + 'WindowBounds': '{{100, 100}, {540, 380}}', + 'ShowSidebar': False, + 'ShowStatusBar': False, + 'ShowToolbar': False, + 'ShowTabView': False, + 'SidebarWidth': 0, +} +entries.append(DSStoreEntry('.', 'bwsp', 'blob', plistlib.dumps(bwsp, fmt=plistlib.FMT_BINARY))) + +with DSStore.open(output, 'w+') as ds: + for e in entries: + ds.insert(e) +" + +echo " Stage: $APP_NAME + Applications + .DS_Store" + +# --- Step 3: Create final DMG --- +VOLNAME="${APP_NAME%.app}" +CREATE_STATUS=1 +for attempt in 1 2 3; do + rm -f "$DMG_DIR/$DMG_NAME" + if "$HDIUTIL_BIN" create \ + -volname "$VOLNAME" \ + -srcfolder "$STAGE_DIR" \ + -ov \ + -format UDZO \ + "$DMG_DIR/$DMG_NAME"; then + CREATE_STATUS=0 + break + else + CREATE_STATUS=$? + fi + + if [[ "$attempt" -lt 3 ]]; then + echo "hdiutil create failed (attempt $attempt/3, exit $CREATE_STATUS); retrying..." >&2 + sleep $((attempt * 2)) + fi +done + +if [[ "$CREATE_STATUS" -ne 0 ]]; then + echo "Error: hdiutil create failed after 3 attempts" >&2 + exit "$CREATE_STATUS" +fi + +echo "Done: $DMG_NAME ($(du -h "$DMG_DIR/$DMG_NAME" | cut -f1))" diff --git a/frontends/desktop/src-tauri/Cargo.lock b/frontends/desktop/src-tauri/Cargo.lock index b2e5389dc..3c5d829e6 100644 --- a/frontends/desktop/src-tauri/Cargo.lock +++ b/frontends/desktop/src-tauri/Cargo.lock @@ -229,7 +229,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b" dependencies = [ "atk-sys", - "glib", + "glib 0.18.5", "libc", ] @@ -239,10 +239,10 @@ version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086" dependencies = [ - "glib-sys", - "gobject-sys", + "glib-sys 0.18.1", + "gobject-sys 0.18.0", "libc", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -257,6 +257,58 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "axum" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" +dependencies = [ + "axum-core", + "bytes", + "form_urlencoded", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde_core", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "sync_wrapper", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "base64" version = "0.21.7" @@ -395,7 +447,7 @@ checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" dependencies = [ "bitflags 2.11.1", "cairo-sys-rs", - "glib", + "glib 0.18.5", "libc", "once_cell", "thiserror 1.0.69", @@ -407,9 +459,9 @@ version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" dependencies = [ - "glib-sys", + "glib-sys 0.18.1", "libc", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -488,7 +540,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" dependencies = [ "smallvec", - "target-lexicon", + "target-lexicon 0.12.16", +] + +[[package]] +name = "cfg-expr" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb693542bcafa528e198be0ebd9d3632ca5b7c93dbe7237460e199910835997c" +dependencies = [ + "smallvec", + "target-lexicon 0.13.5", ] [[package]] @@ -1191,7 +1253,7 @@ dependencies = [ [[package]] name = "ga-desktop" -version = "0.1.8" +version = "0.2.0" dependencies = [ "dirs 5.0.1", "rfd", @@ -1199,7 +1261,10 @@ dependencies = [ "serde_json", "tauri", "tauri-build", + "tauri-plugin-opener", "tauri-plugin-single-instance", + "tauri-plugin-wdio", + "tauri-plugin-wdio-webdriver", ] [[package]] @@ -1212,7 +1277,7 @@ dependencies = [ "gdk-pixbuf", "gdk-sys", "gio", - "glib", + "glib 0.18.5", "libc", "pango", ] @@ -1225,7 +1290,7 @@ checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec" dependencies = [ "gdk-pixbuf-sys", "gio", - "glib", + "glib 0.18.5", "libc", "once_cell", ] @@ -1236,11 +1301,11 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" dependencies = [ - "gio-sys", - "glib-sys", - "gobject-sys", + "gio-sys 0.18.1", + "glib-sys 0.18.1", + "gobject-sys 0.18.0", "libc", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -1251,13 +1316,13 @@ checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", - "gio-sys", - "glib-sys", - "gobject-sys", + "gio-sys 0.18.1", + "glib-sys 0.18.1", + "gobject-sys 0.18.0", "libc", "pango-sys", "pkg-config", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -1267,11 +1332,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69" dependencies = [ "gdk-sys", - "glib-sys", - "gobject-sys", + "glib-sys 0.18.1", + "gobject-sys 0.18.0", "libc", "pkg-config", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -1283,7 +1348,7 @@ dependencies = [ "gdk", "gdkx11-sys", "gio", - "glib", + "glib 0.18.5", "libc", "x11", ] @@ -1295,9 +1360,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e2e7445fe01ac26f11601db260dd8608fe172514eb63b3b5e261ea6b0f4428d" dependencies = [ "gdk-sys", - "glib-sys", + "glib-sys 0.18.1", "libc", - "system-deps", + "system-deps 6.2.2", "x11", ] @@ -1357,8 +1422,8 @@ dependencies = [ "futures-core", "futures-io", "futures-util", - "gio-sys", - "glib", + "gio-sys 0.18.1", + "glib 0.18.5", "libc", "once_cell", "pin-project-lite", @@ -1372,13 +1437,26 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" dependencies = [ - "glib-sys", - "gobject-sys", + "glib-sys 0.18.1", + "gobject-sys 0.18.0", "libc", - "system-deps", + "system-deps 6.2.2", "winapi", ] +[[package]] +name = "gio-sys" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0071fe88dba8e40086c8ff9bbb62622999f49628344b1d1bf490a48a29d80f22" +dependencies = [ + "glib-sys 0.21.5", + "gobject-sys 0.21.5", + "libc", + "system-deps 7.0.8", + "windows-sys 0.61.2", +] + [[package]] name = "glib" version = "0.18.5" @@ -1391,10 +1469,10 @@ dependencies = [ "futures-executor", "futures-task", "futures-util", - "gio-sys", - "glib-macros", - "glib-sys", - "gobject-sys", + "gio-sys 0.18.1", + "glib-macros 0.18.5", + "glib-sys 0.18.1", + "gobject-sys 0.18.0", "libc", "memchr", "once_cell", @@ -1402,6 +1480,27 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "glib" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16de123c2e6c90ce3b573b7330de19be649080ec612033d397d72da265f1bd8b" +dependencies = [ + "bitflags 2.11.1", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "gio-sys 0.21.5", + "glib-macros 0.21.5", + "glib-sys 0.21.5", + "gobject-sys 0.21.5", + "libc", + "memchr", + "smallvec", +] + [[package]] name = "glib-macros" version = "0.18.5" @@ -1416,6 +1515,19 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "glib-macros" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf59b675301228a696fe01c3073974643365080a76cc3ed5bc2cbc466ad87f17" +dependencies = [ + "heck 0.5.0", + "proc-macro-crate 3.5.0", + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "glib-sys" version = "0.18.1" @@ -1423,7 +1535,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" dependencies = [ "libc", - "system-deps", + "system-deps 6.2.2", +] + +[[package]] +name = "glib-sys" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d95e1a3a19ae464a7286e14af9a90683c64d70c02532d88d87ce95056af3e6c" +dependencies = [ + "libc", + "system-deps 7.0.8", ] [[package]] @@ -1438,9 +1560,20 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" dependencies = [ - "glib-sys", + "glib-sys 0.18.1", "libc", - "system-deps", + "system-deps 6.2.2", +] + +[[package]] +name = "gobject-sys" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dca35da0d19a18f4575f3cb99fe1c9e029a2941af5662f326f738a21edaf294" +dependencies = [ + "glib-sys 0.21.5", + "libc", + "system-deps 7.0.8", ] [[package]] @@ -1456,7 +1589,7 @@ dependencies = [ "gdk", "gdk-pixbuf", "gio", - "glib", + "glib 0.18.5", "gtk-sys", "gtk3-macros", "libc", @@ -1474,12 +1607,12 @@ dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", "gdk-sys", - "gio-sys", - "glib-sys", - "gobject-sys", + "gio-sys 0.18.1", + "glib-sys 0.18.1", + "gobject-sys 0.18.0", "libc", "pango-sys", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -1589,6 +1722,12 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + [[package]] name = "hyper" version = "1.9.0" @@ -1602,6 +1741,7 @@ dependencies = [ "http", "http-body", "httparse", + "httpdate", "itoa", "pin-project-lite", "smallvec", @@ -1819,6 +1959,25 @@ version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" +[[package]] +name = "is-docker" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" +dependencies = [ + "once_cell", +] + +[[package]] +name = "is-wsl" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" +dependencies = [ + "is-docker", + "once_cell", +] + [[package]] name = "itoa" version = "1.0.18" @@ -1832,7 +1991,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca5671e9ffce8ffba57afc24070e906da7fc4b1ba66f2cabebf61bf2ea257fcc" dependencies = [ "bitflags 1.3.2", - "glib", + "glib 0.18.5", "javascriptcore-rs-sys", ] @@ -1842,10 +2001,10 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1be78d14ffa4b75b66df31840478fef72b51f8c2465d4ca7c194da9f7a5124" dependencies = [ - "glib-sys", - "gobject-sys", + "glib-sys 0.18.1", + "gobject-sys 0.18.0", "libc", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -1949,7 +2108,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a" dependencies = [ - "glib", + "glib 0.18.5", "gtk", "gtk-sys", "libappindicator-sys", @@ -2039,6 +2198,12 @@ dependencies = [ "web_atoms", ] +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + [[package]] name = "memchr" version = "2.8.0" @@ -2187,9 +2352,17 @@ checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ "bitflags 2.11.1", "block2", + "libc", "objc2", + "objc2-cloud-kit", + "objc2-core-data", "objc2-core-foundation", + "objc2-core-graphics", + "objc2-core-image", + "objc2-core-text", + "objc2-core-video", "objc2-foundation", + "objc2-quartz-core", ] [[package]] @@ -2209,6 +2382,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa" dependencies = [ + "bitflags 2.11.1", "objc2", "objc2-foundation", ] @@ -2269,6 +2443,19 @@ dependencies = [ "objc2-core-graphics", ] +[[package]] +name = "objc2-core-video" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d425caf1df73233f29fd8a5c3e5edbc30d2d4307870f802d18f00d83dc5141a6" +dependencies = [ + "bitflags 2.11.1", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-io-surface", +] + [[package]] name = "objc2-encode" version = "4.1.0" @@ -2292,6 +2479,7 @@ checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ "bitflags 2.11.1", "block2", + "libc", "objc2", "objc2-core-foundation", ] @@ -2307,6 +2495,16 @@ dependencies = [ "objc2-core-foundation", ] +[[package]] +name = "objc2-javascript-core" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a1e6550c4caed348956ce3370c9ffeca70bb1dbed4fa96112e7c6170e074586" +dependencies = [ + "objc2", + "objc2-core-foundation", +] + [[package]] name = "objc2-quartz-core" version = "0.3.2" @@ -2319,6 +2517,17 @@ dependencies = [ "objc2-foundation", ] +[[package]] +name = "objc2-security" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe137109bd1e8b5a99390f77a7d8b2961dafc1a1c5db8f2e60329ad6d895a" +dependencies = [ + "bitflags 2.11.1", + "objc2", + "objc2-core-foundation", +] + [[package]] name = "objc2-ui-kit" version = "0.3.2" @@ -2362,6 +2571,8 @@ dependencies = [ "objc2-app-kit", "objc2-core-foundation", "objc2-foundation", + "objc2-javascript-core", + "objc2-security", ] [[package]] @@ -2370,6 +2581,17 @@ version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +[[package]] +name = "open" +version = "5.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd8d3b65c44123a56e0133d2cd06ce4361bd3ca99d41198b2f25e3c3db9b8b4a" +dependencies = [ + "dunce", + "is-wsl", + "libc", +] + [[package]] name = "option-ext" version = "0.2.0" @@ -2393,7 +2615,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" dependencies = [ "gio", - "glib", + "glib 0.18.5", "libc", "once_cell", "pango-sys", @@ -2405,10 +2627,10 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" dependencies = [ - "glib-sys", - "gobject-sys", + "glib-sys 0.18.1", + "gobject-sys 0.18.0", "libc", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -2920,6 +3142,12 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + [[package]] name = "same-file" version = "1.0.6" @@ -3087,6 +3315,17 @@ dependencies = [ "zmij", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + [[package]] name = "serde_repr" version = "0.1.20" @@ -3116,6 +3355,18 @@ dependencies = [ "serde_core", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "serde_with" version = "3.20.0" @@ -3270,7 +3521,7 @@ checksum = "471f924a40f31251afc77450e781cb26d55c0b650842efafc9c6cbd2f7cc4f9f" dependencies = [ "futures-channel", "gio", - "glib", + "glib 0.18.5", "libc", "soup3-sys", ] @@ -3281,11 +3532,11 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ebe8950a680a12f24f15ebe1bf70db7af98ad242d9db43596ad3108aab86c27" dependencies = [ - "gio-sys", - "glib-sys", - "gobject-sys", + "gio-sys 0.18.1", + "glib-sys 0.18.1", + "gobject-sys 0.18.0", "libc", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -3382,13 +3633,26 @@ version = "6.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" dependencies = [ - "cfg-expr", + "cfg-expr 0.15.8", "heck 0.5.0", "pkg-config", "toml 0.8.2", "version-compare", ] +[[package]] +name = "system-deps" +version = "7.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396a35feb67335377e0251fcbc1092fc85c484bd4e3a7a54319399da127796e7" +dependencies = [ + "cfg-expr 0.20.8", + "heck 0.5.0", + "pkg-config", + "toml 1.1.2+spec-1.1.0", + "version-compare", +] + [[package]] name = "tao" version = "0.35.2" @@ -3446,6 +3710,12 @@ version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" +[[package]] +name = "target-lexicon" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" + [[package]] name = "tauri" version = "2.11.1" @@ -3559,6 +3829,44 @@ dependencies = [ "tauri-utils", ] +[[package]] +name = "tauri-plugin" +version = "2.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74be5dd4bed9afbd145e5716b5fa2ec28cbc29c34ffa61c258c9273d896c8020" +dependencies = [ + "anyhow", + "glob", + "plist", + "schemars 0.8.22", + "serde", + "serde_json", + "tauri-utils", + "walkdir", +] + +[[package]] +name = "tauri-plugin-opener" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17e1bea14edce6b793a04e2417e3fd924b9bc4faae83cdee7d714156cceeed29" +dependencies = [ + "dunce", + "glob", + "objc2-app-kit", + "objc2-foundation", + "open", + "schemars 0.8.22", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "thiserror 2.0.18", + "url", + "windows", + "zbus", +] + [[package]] name = "tauri-plugin-single-instance" version = "2.4.2" @@ -3574,6 +3882,56 @@ dependencies = [ "zbus", ] +[[package]] +name = "tauri-plugin-wdio" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8aa9b559f110924b9897793767a3bb4880c195db75838030eb224f94d21565d9" +dependencies = [ + "log", + "serde", + "serde_json", + "tauri", + "tauri-build", + "tauri-plugin", + "thiserror 1.0.69", + "tokio", + "uuid", +] + +[[package]] +name = "tauri-plugin-wdio-webdriver" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30c5bffe978c41b06ad44a5f4b5b543405918cf316b98756c678a6431061f2e9" +dependencies = [ + "async-trait", + "axum", + "base64 0.22.1", + "block2", + "cairo-rs", + "glib 0.21.5", + "gtk", + "javascriptcore-rs", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-web-kit", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "tempfile", + "thiserror 2.0.18", + "tokio", + "tracing", + "uuid", + "webkit2gtk", + "webview2-com", + "windows", + "windows-core 0.61.2", +] + [[package]] name = "tauri-runtime" version = "2.11.1" @@ -3627,9 +3985,9 @@ dependencies = [ [[package]] name = "tauri-utils" -version = "2.9.1" +version = "2.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d57200389a2f82b4b0a40ae29ca19b6978116e8f4d4e974c3234ce40c0ffbdec" +checksum = "3e176a18e67764923c4f1ce66f25ae4abe5f688384d5eb1a0fa6c77f3d90f887" dependencies = [ "anyhow", "brotli", @@ -3804,9 +4162,21 @@ dependencies = [ "mio", "pin-project-lite", "socket2", + "tokio-macros", "windows-sys 0.61.2", ] +[[package]] +name = "tokio-macros" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6328af13490e73a9b4694030fafd93f8c8c6a9dede33e821c3fc63eddf8042ba" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "tokio-util" version = "0.7.18" @@ -3953,6 +4323,7 @@ dependencies = [ "tokio", "tower-layer", "tower-service", + "tracing", ] [[package]] @@ -3991,6 +4362,7 @@ version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -4451,10 +4823,10 @@ dependencies = [ "gdk", "gdk-sys", "gio", - "gio-sys", - "glib", - "glib-sys", - "gobject-sys", + "gio-sys 0.18.1", + "glib 0.18.5", + "glib-sys 0.18.1", + "gobject-sys 0.18.0", "gtk", "gtk-sys", "javascriptcore-rs", @@ -4473,15 +4845,15 @@ dependencies = [ "bitflags 1.3.2", "cairo-sys-rs", "gdk-sys", - "gio-sys", - "glib-sys", - "gobject-sys", + "gio-sys 0.18.1", + "glib-sys 0.18.1", + "gobject-sys 0.18.0", "gtk-sys", "javascriptcore-rs-sys", "libc", "pkg-config", "soup3-sys", - "system-deps", + "system-deps 6.2.2", ] [[package]] diff --git a/frontends/desktop/src-tauri/Cargo.toml b/frontends/desktop/src-tauri/Cargo.toml index 3914e307e..d11d9c00a 100644 --- a/frontends/desktop/src-tauri/Cargo.toml +++ b/frontends/desktop/src-tauri/Cargo.toml @@ -1,19 +1,26 @@ [package] name = "ga-desktop" -version = "0.1.8" +version = "0.2.0" edition = "2021" [build-dependencies] tauri-build = { version = "2", features = [] } [dependencies] -tauri = { version = "2", features = ["devtools"] } +tauri = { version = "2", features = ["devtools", "tray-icon"] } tauri-plugin-single-instance = "2" +tauri-plugin-opener = "2" +tauri-plugin-wdio = { version = "1.2.0", optional = true } +tauri-plugin-wdio-webdriver = { version = "1.2.0", optional = true } serde = { version = "1", features = ["derive"] } serde_json = "1" dirs = "5" rfd = "0.15" +[features] +default = [] +e2e = ["dep:tauri-plugin-wdio", "dep:tauri-plugin-wdio-webdriver"] + [lib] name = "ga_desktop_lib" crate-type = ["lib", "cdylib", "staticlib"] diff --git a/frontends/desktop/src-tauri/capabilities/default.json b/frontends/desktop/src-tauri/capabilities/default.json index e5401c2cf..7fa86536f 100644 --- a/frontends/desktop/src-tauri/capabilities/default.json +++ b/frontends/desktop/src-tauri/capabilities/default.json @@ -11,11 +11,15 @@ "core:window:allow-show", "core:window:allow-hide", "core:window:allow-set-focus", + "core:window:allow-minimize", + "core:window:allow-toggle-maximize", "core:window:allow-close", "core:window:allow-get-all-windows", "core:webview:default", "allow-start-bridge", "allow-start-bridge-with-config", + "allow-retry-bootstrap", + "allow-get-bootstrap-snapshot", "allow-get-config", "allow-export-mykey", "allow-pick-directory", @@ -24,6 +28,8 @@ "allow-clear-ga-source", "allow-move-ga-runtime", "allow-shortcut-should-ask", - "allow-shortcut-decide" + "allow-shortcut-decide", + "core:window:allow-start-dragging", + "opener:default" ] } diff --git a/frontends/desktop/src-tauri/permissions/bridge-commands.toml b/frontends/desktop/src-tauri/permissions/bridge-commands.toml index 27dc07df9..3145cf19b 100644 --- a/frontends/desktop/src-tauri/permissions/bridge-commands.toml +++ b/frontends/desktop/src-tauri/permissions/bridge-commands.toml @@ -8,6 +8,16 @@ identifier = "allow-start-bridge-with-config" description = "Spawn bridge from setup with explicit python/project paths." commands.allow = ["start_bridge_with_config"] +[[permission]] +identifier = "allow-retry-bootstrap" +description = "Retry the unified desktop bootstrap with validated Python and project paths." +commands.allow = ["retry_bootstrap"] + +[[permission]] +identifier = "allow-get-bootstrap-snapshot" +description = "Read the current desktop bootstrap state and filtered diagnostics." +commands.allow = ["get_bootstrap_snapshot"] + [[permission]] identifier = "allow-get-config" description = "Read saved bridge spawn configuration." diff --git a/frontends/desktop/src-tauri/src/lib.rs b/frontends/desktop/src-tauri/src/lib.rs index c0b63df0f..60eb92543 100644 --- a/frontends/desktop/src-tauri/src/lib.rs +++ b/frontends/desktop/src-tauri/src/lib.rs @@ -1,27 +1,392 @@ -use std::process::{Command, Child, Stdio}; -use std::io::{BufRead, BufReader}; -use std::sync::Mutex; -use std::net::TcpStream; -use std::time::{Duration, Instant}; -use std::thread; +use serde::{Deserialize, Serialize}; +use std::collections::VecDeque; +use std::fs::OpenOptions; +use std::io::{BufRead, BufReader, Write}; +use std::net::{SocketAddr, TcpStream, ToSocketAddrs}; use std::path::{Path, PathBuf}; -use tauri::Manager; +use std::process::{Child, Command, Stdio}; +use std::sync::{LazyLock, Mutex}; +use std::thread; +use std::time::{Duration, Instant}; +use tauri::{Emitter, Manager}; #[cfg(windows)] use std::os::windows::process::CommandExt; +#[cfg(windows)] +use tauri::menu::{MenuBuilder, MenuItemBuilder}; +#[cfg(windows)] +use tauri::tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent}; + static BRIDGE_PROCESS: Mutex> = Mutex::new(None); +static BRIDGE_LOG_READERS: Mutex>> = Mutex::new(Vec::new()); + +#[derive(Clone, Debug, PartialEq)] +struct BridgeEndpoint { + host: String, + port: u16, +} + +impl BridgeEndpoint { + fn socket_addr(&self) -> String { + format!("{}:{}", self.host, self.port) + } + + fn tcp_addr(&self) -> Option { + (self.host.as_str(), self.port) + .to_socket_addrs() + .ok()? + .find(|addr| addr.ip().is_loopback()) + } +} + +fn bridge_endpoint_from_values( + host: Option<&str>, + port: Option<&str>, +) -> Result { + let host = host.unwrap_or("127.0.0.1").trim(); + if host != "127.0.0.1" && host != "localhost" && host != "::1" { + return Err("BRIDGE_HOST must be loopback".to_string()); + } + let port = port + .unwrap_or("14168") + .parse::() + .map_err(|_| "BRIDGE_PORT must be between 1 and 65535".to_string())?; + if port == 0 { + return Err("BRIDGE_PORT must be between 1 and 65535".to_string()); + } + Ok(BridgeEndpoint { + host: host.to_string(), + port, + }) +} + +fn bridge_endpoint() -> BridgeEndpoint { + bridge_endpoint_from_values( + std::env::var("BRIDGE_HOST").ok().as_deref(), + std::env::var("BRIDGE_PORT").ok().as_deref(), + ) + .unwrap_or(BridgeEndpoint { + host: "127.0.0.1".to_string(), + port: 14168, + }) +} + +const MAX_DIAGNOSTIC_LINES: usize = 100; +const MAX_DIAGNOSTIC_LINE_BYTES: usize = 2 * 1024; + +fn sanitize_diagnostic_line(line: &str) -> String { + let lower = line.to_ascii_lowercase(); + const SENSITIVE_MARKERS: [&str; 12] = [ + "apikey", + "api_key", + "authorization", + "bearer", + "secret", + "token", + "mykey", + "[session]", + "[turn]", + "memory", + "conversation", + "llm_history", + ]; + if SENSITIVE_MARKERS + .iter() + .any(|marker| lower.contains(marker)) + { + return "[redacted sensitive diagnostic line]".to_string(); + } + + let mut end = line.len().min(MAX_DIAGNOSTIC_LINE_BYTES); + while end > 0 && !line.is_char_boundary(end) { + end -= 1; + } + line[..end].to_string() +} + +fn push_bounded_log(logs: &mut VecDeque, line: &str) { + logs.push_back(sanitize_diagnostic_line(line)); + while logs.len() > MAX_DIAGNOSTIC_LINES { + logs.pop_front(); + } +} + +#[derive(Debug, PartialEq)] +enum ListenerIdentity { + Owned, + KnownGenericAgent, + Foreign, +} + +fn classify_listener_identity( + identity: Option<&serde_json::Value>, + project_dir: &str, +) -> ListenerIdentity { + let Some(identity) = identity else { + return ListenerIdentity::Foreign; + }; + let reported_root = identity + .get("ga_root") + .and_then(|value| value.as_str()) + .unwrap_or(""); + let reported_build = identity + .get("build_id") + .and_then(|value| value.as_str()) + .unwrap_or(""); + let reported_pid = identity + .get("pid") + .and_then(|value| value.as_u64()) + .unwrap_or(0); + if reported_root.is_empty() || reported_pid == 0 { + return ListenerIdentity::Foreign; + } + let same_root = { + let (reported, expected) = (norm_path(reported_root), norm_path(project_dir)); + #[cfg(windows)] + { + reported.eq_ignore_ascii_case(&expected) + } + #[cfg(not(windows))] + { + reported == expected + } + }; + if same_root && reported_build == env!("GA_BUILD_ID") { + ListenerIdentity::Owned + } else { + ListenerIdentity::KnownGenericAgent + } +} + +#[cfg(any(windows, test))] +fn should_retry_without_breakaway(raw_os_error: Option) -> bool { + raw_os_error == Some(5) +} + +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +#[serde(rename_all = "snake_case")] +enum BootstrapMode { + HotStart, + ColdStart, + Prepare, +} + +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +#[serde(rename_all = "snake_case")] +enum BootstrapPhase { + Idle, + Resolving, + Preparing, + StartingService, + OpeningUi, + Ready, + Failed, +} + +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +#[serde(rename_all = "snake_case")] +enum BootstrapFailureCode { + ConfigUnresolved, + PrepareFailed, + SpawnFailed, + PortConflict, + ServiceTimeout, + ServiceExited, + UiNavigationFailed, + Unknown, +} + +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +#[serde(rename_all = "snake_case")] +enum PortState { + Free, + Owned, + Foreign, + Unknown, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +struct BootstrapFailure { + code: BootstrapFailureCode, + detail: String, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +struct BootstrapDiagnostics { + build_id: String, + platform: String, + project_dir: String, + python_path: String, + port_state: PortState, + bridge_identity: Option, + recent_logs: Vec, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +struct BootstrapSnapshot { + seq: u64, + mode: BootstrapMode, + phase: BootstrapPhase, + stage: Option, + progress: u8, + failure: Option, + diagnostics: BootstrapDiagnostics, +} + +fn current_platform() -> String { + #[cfg(windows)] + { + "windows".to_string() + } + #[cfg(target_os = "macos")] + { + "macos".to_string() + } + #[cfg(all(not(windows), not(target_os = "macos")))] + { + "linux".to_string() + } +} -/// Last first-run prepare error, surfaced to the setup window (fallback.html) so the -/// user sees WHY the install failed instead of a generic "configure paths" screen. -static PREPARE_ERROR: Mutex> = Mutex::new(None); +static BOOTSTRAP_STATE: LazyLock> = LazyLock::new(|| { + Mutex::new(BootstrapSnapshot { + seq: 0, + mode: BootstrapMode::ColdStart, + phase: BootstrapPhase::Idle, + stage: None, + progress: 0, + failure: None, + diagnostics: BootstrapDiagnostics { + build_id: env!("GA_BUILD_ID").to_string(), + platform: current_platform(), + project_dir: String::new(), + python_path: String::new(), + port_state: PortState::Unknown, + bridge_identity: None, + recent_logs: Vec::new(), + }, + }) +}); + +fn write_e2e_bootstrap_snapshot(snapshot: &BootstrapSnapshot) { + let Some(report_dir) = std::env::var_os("GA_DESKTOP_E2E_REPORT_DIR") else { + return; + }; + let report_dir = PathBuf::from(report_dir); + if report_dir.as_os_str().is_empty() { + return; + } + if std::fs::create_dir_all(&report_dir).is_err() { + return; + } + + let Ok(line) = serde_json::to_string(snapshot) else { + return; + }; + if let Ok(mut file) = OpenOptions::new() + .create(true) + .append(true) + .open(report_dir.join("bootstrap-events.jsonl")) + { + let _ = writeln!(file, "{line}"); + } + + if let Ok(json) = serde_json::to_vec_pretty(snapshot) { + let _ = std::fs::write(report_dir.join("bootstrap-latest.json"), json); + } +} + +fn snapshot_update( + app_handle: Option<&tauri::AppHandle>, + update: impl FnOnce(&mut BootstrapSnapshot), +) -> BootstrapSnapshot { + let snapshot = { + let mut state = BOOTSTRAP_STATE.lock().unwrap(); + update(&mut state); + state.seq = state.seq.saturating_add(1); + state.clone() + }; + if let Some(app_handle) = app_handle { + let _ = app_handle.emit("bootstrap", snapshot.clone()); + } + write_e2e_bootstrap_snapshot(&snapshot); + snapshot +} + +fn begin_bootstrap( + app_handle: &tauri::AppHandle, + mode: BootstrapMode, + python_path: &str, + project_dir: &str, +) { + snapshot_update(Some(app_handle), |snapshot| { + snapshot.mode = mode; + snapshot.phase = BootstrapPhase::Resolving; + snapshot.stage = Some("validate".to_string()); + snapshot.progress = 5; + snapshot.failure = None; + snapshot.diagnostics.project_dir = project_dir.to_string(); + snapshot.diagnostics.python_path = python_path.to_string(); + snapshot.diagnostics.port_state = PortState::Unknown; + snapshot.diagnostics.bridge_identity = None; + snapshot.diagnostics.recent_logs.clear(); + }); +} + +fn set_bootstrap_phase( + app_handle: &tauri::AppHandle, + phase: BootstrapPhase, + stage: Option<&str>, + progress: u8, +) { + snapshot_update(Some(app_handle), |snapshot| { + snapshot.phase = phase; + snapshot.stage = stage.map(str::to_string); + snapshot.progress = progress.min(100); + snapshot.failure = None; + }); +} + +fn record_diagnostic_log(app_handle: &tauri::AppHandle, line: &str) { + if matches!( + BOOTSTRAP_STATE.lock().unwrap().phase, + BootstrapPhase::Ready | BootstrapPhase::Failed + ) { + return; + } + snapshot_update(Some(app_handle), |snapshot| { + let mut logs: VecDeque = snapshot.diagnostics.recent_logs.drain(..).collect(); + push_bounded_log(&mut logs, line); + snapshot.diagnostics.recent_logs = logs.into_iter().collect(); + }); +} + +fn set_port_diagnostics( + app_handle: &tauri::AppHandle, + port_state: PortState, + identity: Option<&serde_json::Value>, +) { + snapshot_update(Some(app_handle), |snapshot| { + snapshot.diagnostics.port_state = port_state; + snapshot.diagnostics.bridge_identity = identity.map(ToString::to_string); + }); +} + +#[tauri::command] +fn get_bootstrap_snapshot() -> BootstrapSnapshot { + BOOTSTRAP_STATE.lock().unwrap().clone() +} /// Get project root (parent of frontends/) fn project_root() -> PathBuf { std::env::current_exe() .expect("cannot get exe path") - .parent().expect("cannot get exe dir") // frontends/ - .parent().expect("cannot get project root") // project root + .parent() + .expect("cannot get exe dir") // frontends/ + .parent() + .expect("cannot get project root") // project root .to_path_buf() } @@ -53,7 +418,12 @@ fn bundle_anchor_dir() -> Option { while let Some(dir) = d { if dir.extension().and_then(|s| s.to_str()) == Some("app") { let resources = dir.join("Contents").join("Resources"); - if resources.join("runtime").join("app").join("agentmain.py").exists() { + if resources + .join("runtime") + .join("app") + .join("agentmain.py") + .exists() + { return Some(resources); } if let Some(parent) = dir.parent() { @@ -74,7 +444,11 @@ fn bundle_python() -> Option { let p = root.join("python").join("python.exe"); #[cfg(not(windows))] let p = root.join("python").join("bin").join("python3"); - if p.exists() { Some(p) } else { None } + if p.exists() { + Some(p) + } else { + None + } } /// Find python executable: @@ -118,9 +492,54 @@ fn find_python() -> String { // Fallback: system PATH #[cfg(windows)] - { "python".to_string() } + { + "python".to_string() + } #[cfg(not(windows))] - { "python3".to_string() } + { + "python3".to_string() + } +} + +fn python_interpreter_resolves(python_path: &str) -> bool { + let python_path = python_path.trim(); + if python_path.is_empty() { + return false; + } + + let explicit_path = python_path.contains('/') || python_path.contains('\\'); + if explicit_path { + return PathBuf::from(python_path).is_file(); + } + + let Some(path_entries) = std::env::var_os("PATH") else { + return false; + }; + for directory in std::env::split_paths(&path_entries) { + if directory.join(python_path).is_file() { + return true; + } + #[cfg(windows)] + { + let extensions = + std::env::var("PATHEXT").unwrap_or_else(|_| ".EXE;.CMD;.BAT".to_string()); + for extension in extensions + .split(';') + .filter(|extension| !extension.is_empty()) + { + if directory + .join(format!("{python_path}{extension}")) + .is_file() + || directory + .join(format!("{python_path}{}", extension.to_ascii_lowercase())) + .is_file() + { + return true; + } + } + } + } + false } /// Find the project directory (folder containing agentmain.py). @@ -151,13 +570,33 @@ fn find_project_dir() -> Option { None } -/// Settings file path: ~/.ga_desktop_settings.json -fn settings_path() -> PathBuf { - dirs::home_dir() +fn resolve_settings_path(home_dir: Option, e2e_override: Option<&str>) -> PathBuf { + if let Some(path) = e2e_override.filter(|path| !path.trim().is_empty()) { + return PathBuf::from(path); + } + home_dir .unwrap_or_else(|| PathBuf::from(".")) .join(".ga_desktop_settings.json") } +/// Settings file path: ~/.ga_desktop_settings.json. +/// +/// Windows resolves the home directory through Known Folders and ignores an overridden +/// USERPROFILE. E2E builds therefore accept an explicit sandbox-owned settings file; the +/// production feature set never reads this override. +fn settings_path() -> PathBuf { + #[cfg(feature = "e2e")] + let e2e_override = if std::env::var("GA_E2E").ok().as_deref() == Some("1") { + std::env::var("GA_E2E_SETTINGS_PATH").ok() + } else { + None + }; + #[cfg(not(feature = "e2e"))] + let e2e_override: Option = None; + + resolve_settings_path(dirs::home_dir(), e2e_override.as_deref()) +} + /// Read the settings file as a JSON object (empty object when missing/unparseable). fn read_settings() -> serde_json::Map { let path = settings_path(); @@ -189,7 +628,9 @@ fn merge_settings(updates: serde_json::Value) { /// None = never asked (first run) /// Some(true)/Some(false) = user's remembered choice. fn read_shortcut_pref() -> Option { - read_settings().get("desktop_shortcut").and_then(|v| v.as_bool()) + read_settings() + .get("desktop_shortcut") + .and_then(|v| v.as_bool()) } fn write_shortcut_pref(enabled: bool) { @@ -201,10 +642,17 @@ fn write_shortcut_pref(enabled: bool) { /// the shortcut is rewritten to the new path. Windows-only (uses a .lnk via WScript.Shell). #[cfg(windows)] fn ensure_desktop_shortcut() { - let Ok(exe) = std::env::current_exe() else { return; }; - let Some(desktop) = dirs::desktop_dir() else { return; }; + let Ok(exe) = std::env::current_exe() else { + return; + }; + let Some(desktop) = dirs::desktop_dir() else { + return; + }; let lnk = desktop.join("GenericAgent.lnk"); - let work_dir = exe.parent().map(|p| p.to_path_buf()).unwrap_or_else(|| exe.clone()); + let work_dir = exe + .parent() + .map(|p| p.to_path_buf()) + .unwrap_or_else(|| exe.clone()); let exe_s = exe.to_string_lossy().replace('\'', "''"); let lnk_s = lnk.to_string_lossy().replace('\'', "''"); @@ -219,11 +667,19 @@ fn ensure_desktop_shortcut() { $sc.WorkingDirectory = '{work}'; \ $sc.IconLocation = '{exe}'; \ $sc.Save()", - lnk = lnk_s, exe = exe_s, work = work_s + lnk = lnk_s, + exe = exe_s, + work = work_s ); let mut cmd = Command::new("powershell.exe"); - cmd.args(["-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", &script]); + cmd.args([ + "-NoProfile", + "-ExecutionPolicy", + "Bypass", + "-Command", + &script, + ]); cmd.creation_flags(0x08000000); // CREATE_NO_WINDOW let _ = cmd.status(); } @@ -232,8 +688,12 @@ fn ensure_desktop_shortcut() { fn ensure_desktop_shortcut() { // Launch target: the AppImage path when running as one, else the current exe. Writing the // current path on every enabled launch keeps a relocated bundle's launcher valid. - let Some(target) = std::env::var_os("APPIMAGE").map(PathBuf::from) - .or_else(|| std::env::current_exe().ok()) else { return; }; + let Some(target) = std::env::var_os("APPIMAGE") + .map(PathBuf::from) + .or_else(|| std::env::current_exe().ok()) + else { + return; + }; let exec = target.to_string_lossy().replace('"', ""); // Linux .desktop Icon= needs an image file (or themed name), not the AppImage path. The CI // ships GenericAgent.png next to the AppImage; fall back to a generic themed icon otherwise. @@ -245,7 +705,8 @@ fn ensure_desktop_shortcut() { let entry = format!( "[Desktop Entry]\nType=Application\nName=GenericAgent\nComment=GenericAgent Desktop\n\ Exec=\"{exec}\"\nIcon={icon}\nTerminal=false\nCategories=Utility;Development;\n", - exec = exec, icon = icon + exec = exec, + icon = icon ); let write_desktop = |path: &std::path::Path| { if std::fs::write(path, &entry).is_ok() { @@ -272,14 +733,21 @@ fn ensure_desktop_shortcut() { #[cfg(target_os = "macos")] fn ensure_desktop_shortcut() { // The .app is the launchable unit; drop a symlink to it on the Desktop. - let Ok(exe) = std::env::current_exe() else { return; }; + let Ok(exe) = std::env::current_exe() else { + return; + }; let mut app: Option = None; let mut d = exe.parent(); while let Some(dir) = d { - if dir.extension().and_then(|s| s.to_str()) == Some("app") { app = Some(dir.to_path_buf()); break; } + if dir.extension().and_then(|s| s.to_str()) == Some("app") { + app = Some(dir.to_path_buf()); + break; + } d = dir.parent(); } - let (Some(app), Some(desktop)) = (app, dirs::desktop_dir()) else { return; }; + let (Some(app), Some(desktop)) = (app, dirs::desktop_dir()) else { + return; + }; let link = desktop.join("GenericAgent.app"); let _ = std::fs::remove_file(&link); let _ = std::os::unix::fs::symlink(&app, &link); @@ -310,12 +778,6 @@ fn shortcut_should_ask() -> bool { bundle_root().is_some() && read_shortcut_pref().is_none() } -/// Returns the last first-run prepare error (if any) so the setup window can display it. -#[tauri::command] -fn get_prepare_error() -> Option { - PREPARE_ERROR.lock().unwrap().clone() -} - /// Frontend reports the user's choice. Persists it and creates the shortcut when enabled. #[tauri::command] fn shortcut_decide(create: bool) { @@ -325,25 +787,19 @@ fn shortcut_decide(create: bool) { } } -/// True when this binary is running from inside a macOS .app bundle (packaged build). -/// Used to refuse stale ~/.ga_desktop_settings.json that could point at an old checkout -/// when App Translocation hides our own runtime/ from current_exe(). #[cfg(target_os = "macos")] fn running_inside_app_bundle() -> bool { std::env::current_exe() .ok() - .map(|p| { - p.components().any(|c| { - c.as_os_str().to_string_lossy().ends_with(".app") - }) + .map(|path| { + path.components() + .any(|component| component.as_os_str().to_string_lossy().ends_with(".app")) }) .unwrap_or(false) } -/// User-set external GenericAgent source directory (方案三: bundle shell + external core). -/// Returns the path only when it still looks like a GA core checkout (agentmain.py exists). -/// The bundle's own bridge/frontend/conductor are used; the saved source only becomes GA_ROOT. -/// An invalid/missing override returns None so callers fall back to the bundle runtime/app. +/// User-set external GenericAgent core. The desktop bridge and conductor remain package-owned; +/// this path is only injected as GA_ROOT. A moved or deleted core falls back to the bundled one. fn valid_ga_source_override() -> Option { let s = read_settings() .get("ga_source_override") @@ -374,28 +830,30 @@ fn remove_setting(key: &str) { fn restore_setting(key: &str, value: Option) { match value { - Some(v) => merge_settings(serde_json::json!({ key: v })), + Some(value) => merge_settings(serde_json::json!({ key: value })), None => remove_setting(key), } } fn copy_dir_replace(src: &Path, dst: &Path) -> Result<(), String> { - std::fs::create_dir_all(dst).map_err(|e| format!("create {:?}: {}", dst, e))?; - for entry in std::fs::read_dir(src).map_err(|e| format!("read {:?}: {}", src, e))? { - let entry = entry.map_err(|e| e.to_string())?; - let sp = entry.path(); - let dp = dst.join(entry.file_name()); - let ft = entry.file_type().map_err(|e| e.to_string())?; - if ft.is_dir() { - if dp.exists() && !dp.is_dir() { - std::fs::remove_file(&dp).map_err(|e| format!("remove {:?}: {}", dp, e))?; + std::fs::create_dir_all(dst).map_err(|error| format!("create {:?}: {error}", dst))?; + for entry in std::fs::read_dir(src).map_err(|error| format!("read {:?}: {error}", src))? { + let entry = entry.map_err(|error| error.to_string())?; + let source = entry.path(); + let destination = dst.join(entry.file_name()); + let file_type = entry.file_type().map_err(|error| error.to_string())?; + if file_type.is_dir() { + if destination.exists() && !destination.is_dir() { + std::fs::remove_file(&destination) + .map_err(|error| format!("remove {:?}: {error}", destination))?; } - copy_dir_replace(&sp, &dp)?; - } else if ft.is_file() { - if let Some(parent) = dp.parent() { - std::fs::create_dir_all(parent).map_err(|e| e.to_string())?; + copy_dir_replace(&source, &destination)?; + } else if file_type.is_file() { + if let Some(parent) = destination.parent() { + std::fs::create_dir_all(parent).map_err(|error| error.to_string())?; } - std::fs::copy(&sp, &dp).map_err(|e| format!("copy {:?} -> {:?}: {}", sp, dp, e))?; + std::fs::copy(&source, &destination) + .map_err(|error| format!("copy {:?} -> {:?}: {error}", source, destination))?; } } Ok(()) @@ -403,27 +861,86 @@ fn copy_dir_replace(src: &Path, dst: &Path) -> Result<(), String> { fn bundled_project_dir() -> Option { let app = bundle_root()?.join("app"); - if app.join("agentmain.py").exists() { Some(app) } else { None } + app.join("agentmain.py").exists().then_some(app) +} + +fn builtin_ga_root(project_dir: &str) -> PathBuf { + #[cfg(target_os = "macos")] + { + if running_inside_app_bundle() { + if let Some(data_dir) = dirs::data_dir() { + return data_dir + .join("GenericAgent") + .join("runtime") + .join(env!("CARGO_PKG_VERSION")) + .join("app"); + } + } + } + PathBuf::from(project_dir) +} + +fn ensure_builtin_ga_root(project_dir: &str) -> Result<(), String> { + if valid_ga_source_override().is_some() { + return Ok(()); + } + let source = PathBuf::from(project_dir); + let destination = builtin_ga_root(project_dir); + if same_path(&source, &destination) || destination.join("agentmain.py").exists() { + return Ok(()); + } + if !source.join("agentmain.py").exists() { + return Err(format!( + "bundled core is missing at {}", + display_path(&source) + )); + } + let parent = destination + .parent() + .ok_or_else(|| "writable runtime has no parent directory".to_string())?; + std::fs::create_dir_all(parent) + .map_err(|error| format!("create writable runtime parent: {error}"))?; + let staging = parent.join(format!(".app-staging-{}", std::process::id())); + if staging.exists() { + std::fs::remove_dir_all(&staging) + .map_err(|error| format!("remove stale writable runtime staging dir: {error}"))?; + } + copy_dir_replace(&source, &staging)?; + match std::fs::rename(&staging, &destination) { + Ok(()) => Ok(()), + Err(_error) if destination.join("agentmain.py").exists() => { + let _ = std::fs::remove_dir_all(&staging); + Ok(()) + } + Err(error) => { + let _ = std::fs::remove_dir_all(&staging); + Err(format!("activate writable runtime: {error}")) + } + } } fn same_path(a: &Path, b: &Path) -> bool { - let aa = a.canonicalize().unwrap_or_else(|_| a.to_path_buf()); - let bb = b.canonicalize().unwrap_or_else(|_| b.to_path_buf()); + let a = a.canonicalize().unwrap_or_else(|_| a.to_path_buf()); + let b = b.canonicalize().unwrap_or_else(|_| b.to_path_buf()); #[cfg(windows)] - { display_path(&aa).eq_ignore_ascii_case(&display_path(&bb)) } + { + display_path(&a).eq_ignore_ascii_case(&display_path(&b)) + } #[cfg(not(windows))] - { aa == bb } + { + a == b + } } fn display_path(path: &Path) -> String { - let s = path.to_string_lossy().to_string(); + let value = path.to_string_lossy().to_string(); #[cfg(windows)] { - if let Some(rest) = s.strip_prefix("\\\\?\\") { + if let Some(rest) = value.strip_prefix("\\\\?\\") { return rest.to_string(); } } - s + value } /// Read config from settings file, or auto-discover and save. @@ -432,10 +949,8 @@ fn display_path(path: &Path) -> String { pub fn get_or_discover_config() -> (String, String) { let path = settings_path(); - // NOTE: the external GA source override does NOT change which project_dir/bridge we run. - // 方案三: we always run the bundle's own bridge + frontend, and inject the external核 via - // the GA_ROOT env (see sanitize_bundle_env). So project_dir stays the bundle here. - + // An external core never replaces project_dir: project_dir locates the package-owned bridge, + // while sanitize_bundle_env injects the selected core as GA_ROOT. if bundle_root().is_some() { let python = find_python(); let project = find_project_dir().unwrap_or_default(); @@ -448,29 +963,32 @@ pub fn get_or_discover_config() -> (String, String) { } } - // Try reading existing settings. - // On macOS, a packaged .app must never trust ~/.ga_desktop_settings.json: App - // Translocation can run the bundle from a random read-only copy where bundle_root() - // fails to see our own runtime/, and an old settings file would then silently point - // the bridge at a previously installed checkout. In that case fall through to - // auto-discovery (which still resolves the bundle via .app-relative search below). #[cfg(target_os = "macos")] let trust_settings = !running_inside_app_bundle(); #[cfg(not(target_os = "macos"))] let trust_settings = true; + // A packaged macOS app never trusts a stale path from a previous install/translocation. if trust_settings && path.exists() { if let Ok(content) = std::fs::read_to_string(&path) { if let Ok(val) = serde_json::from_str::(&content) { - let python = val.get("python_path") + let python = val + .get("python_path") .and_then(|v| v.as_str()) .unwrap_or("") .to_string(); - let project = val.get("project_dir") + let project = val + .get("project_dir") .and_then(|v| v.as_str()) .unwrap_or("") .to_string(); - if !python.is_empty() && !project.is_empty() { + if !python.is_empty() + && !project.is_empty() + && PathBuf::from(&project) + .join("frontends") + .join("desktop_bridge.py") + .exists() + { return (python, project); } } @@ -513,33 +1031,42 @@ fn prepared_marker() -> Option { /// True when this is a self-contained bundle whose python env has not been prepared yet /// (embedded python present but deps not yet installed into it). fn needs_first_run_prepare(project_dir: &str) -> bool { - if project_dir.is_empty() { return false; } + if project_dir.is_empty() { + return false; + } bundle_python().is_some() && prepared_marker().map(|m| !m.exists()).unwrap_or(false) } /// Clear env vars a host launcher injects pointing at its own runtime. The Linux AppImage exports /// PYTHONHOME/PYTHONPATH (-> bundled python crashes with "No module named 'encodings'") and /// LD_LIBRARY_PATH (-> wrong shared libs). Our bundled python / prepare / bridge must run clean. -fn sanitize_bundle_env(cmd: &mut Command) { +fn sanitize_bundle_env(cmd: &mut Command, project_dir: &str) { cmd.env_remove("PYTHONHOME"); cmd.env_remove("PYTHONPATH"); cmd.env_remove("LD_LIBRARY_PATH"); + cmd.env("PYTHONDONTWRITEBYTECODE", "1"); // Stamp the bridge we spawn with this build's id so a later app launch can tell whether the // bridge holding :14168 is ours (see bridge_identity_matches / GET /services/identity). cmd.env("GA_BUILD_ID", env!("GA_BUILD_ID")); - // 方案三: when the user has set a valid external GA source, inject it as GA_ROOT so the - // (bundle's own) bridge + conductor import the external核 and read/write its data. When - // unset/invalid we leave GA_ROOT unset → the bridge falls back to its own bundle runtime. - match valid_ga_source_override() { - Some(src) => { cmd.env("GA_ROOT", src); } - None => { cmd.env_remove("GA_ROOT"); } + let ga_root = effective_ga_root(project_dir); + if ga_root.is_empty() { + cmd.env_remove("GA_ROOT"); + } else { + cmd.env("GA_ROOT", ga_root); } + let endpoint = bridge_endpoint(); + cmd.env("BRIDGE_HOST", &endpoint.host); + cmd.env("BRIDGE_PORT", endpoint.port.to_string()); } /// Run the offline prepare (install_windows.ps1 -Mode PrepareOnly) using bundled python + wheels. /// Streams the script's stdout and forwards GAPROGRESS markers to `report(pct, message)`. /// Blocking; intended to run on a background thread. Writes ~/.ga_desktop_settings.json. -fn run_offline_prepare(project_dir: &str, report: &dyn Fn(i32, &str)) -> Result<(), String> { +fn run_offline_prepare( + project_dir: &str, + report: &dyn Fn(i32, &str), + log: &dyn Fn(&str), +) -> Result<(), String> { let root = bundle_root().ok_or("cannot locate bundle root")?; let wheels = root.join("wheels"); @@ -568,10 +1095,14 @@ fn run_offline_prepare(project_dir: &str, report: &dyn Fn(i32, &str)) -> Result< let mut c = Command::new("powershell.exe"); c.args(["-NoProfile", "-ExecutionPolicy", "Bypass", "-File"]) .arg(&script) - .arg("-PythonPath").arg(&py) - .arg("-ProjectDir").arg(project_dir) - .arg("-WheelDir").arg(&wheels) - .arg("-ExtraPipPackages").arg("fastapi uvicorn websockets") + .arg("-PythonPath") + .arg(&py) + .arg("-ProjectDir") + .arg(project_dir) + .arg("-WheelDir") + .arg(&wheels) + .arg("-ExtraPipPackages") + .arg("fastapi uvicorn websockets") // -NoVenv: install deps straight into the embedded python (no venv) so the // bundle is relocatable. See prepared_marker / find_python. .args(["-Mode", "PrepareOnly", "-SkipNpmInstall", "-NoVenv"]); @@ -581,10 +1112,14 @@ fn run_offline_prepare(project_dir: &str, report: &dyn Fn(i32, &str)) -> Result< let mut cmd = { let mut c = Command::new("bash"); c.arg(&script) - .arg("--python-path").arg(&py) - .arg("--project-dir").arg(project_dir) - .arg("--wheel-dir").arg(&wheels) - .arg("--extra-packages").arg("fastapi uvicorn websockets") + .arg("--python-path") + .arg(&py) + .arg("--project-dir") + .arg(project_dir) + .arg("--wheel-dir") + .arg(&wheels) + .arg("--extra-packages") + .arg("fastapi uvicorn websockets") // --no-venv: install deps straight into the embedded python (no venv) so the // bundle is relocatable. See prepared_marker / find_python. .args(["--mode", "PrepareOnly", "--no-venv"]); @@ -592,70 +1127,64 @@ fn run_offline_prepare(project_dir: &str, report: &dyn Fn(i32, &str)) -> Result< }; cmd.stdout(Stdio::piped()).stderr(Stdio::piped()); - sanitize_bundle_env(&mut cmd); + sanitize_bundle_env(&mut cmd, project_dir); #[cfg(windows)] cmd.creation_flags(0x08000000); // CREATE_NO_WINDOW - let mut child = cmd.spawn().map_err(|e| format!("failed to launch prepare: {}", e))?; - - // Keep only the last N lines of a stream (pip errors are at the end; a full capture - // could be huge and the setup window only needs the tail to explain the failure). - const TAIL: usize = 40; - fn push_tail(buf: &mut Vec, line: String) { - if buf.len() >= TAIL { - buf.remove(0); - } - buf.push(line); + let mut child = cmd + .spawn() + .map_err(|e| format!("failed to launch prepare: {}", e))?; + + // Drain both streams concurrently so a verbose prepare cannot deadlock on a full pipe. + // Only stable stage keys reach the main copy; raw output is retained in diagnostics. + let (sender, receiver) = std::sync::mpsc::channel::>(); + let mut stream_count = 0; + if let Some(stdout) = child.stdout.take() { + stream_count += 1; + let sender = sender.clone(); + thread::spawn(move || { + for line in BufReader::new(stdout).lines().map_while(Result::ok) { + let _ = sender.send(Some(line)); + } + let _ = sender.send(None); + }); } - - // Drain stderr on a helper thread (both pipes must be drained concurrently or the child - // can deadlock on a full pipe buffer). pip/install errors land here. - let stderr_tail = std::sync::Arc::new(Mutex::new(Vec::::new())); - let stderr_thread = child.stderr.take().map(|err| { - let tail = std::sync::Arc::clone(&stderr_tail); + if let Some(stderr) = child.stderr.take() { + stream_count += 1; + let sender = sender.clone(); thread::spawn(move || { - for line in BufReader::new(err).lines().flatten() { - push_tail(&mut tail.lock().unwrap(), line); + for line in BufReader::new(stderr).lines().map_while(Result::ok) { + let _ = sender.send(Some(line)); } - }) - }); - - // Forward the script's ASCII progress keys to the loading window, which localizes them - // (window.gaProgress maps key -> zh/en by navigator.language). Non-progress stdout is - // kept (tail only) so a failure can show what the script was doing when it died. - let mut stdout_tail: Vec = Vec::new(); - if let Some(out) = child.stdout.take() { - for line in BufReader::new(out).lines().flatten() { - if let Some(key) = line.trim().strip_prefix("GAPROGRESS|") { - match key.trim() { - "venv" => report(15, "venv"), - "deps" => report(45, "deps"), - "done" => report(90, "done"), - _ => {} + let _ = sender.send(None); + }); + } + drop(sender); + + let mut completed_streams = 0; + while completed_streams < stream_count { + match receiver.recv() { + Ok(Some(line)) => { + if let Some(key) = line.trim().strip_prefix("GAPROGRESS|") { + match key.trim() { + "venv" => report(25, "python"), + "deps" => report(50, "dependencies"), + "done" => report(75, "dependencies"), + _ => {} + } + } else { + log(&line); } - } else if !line.trim().is_empty() { - push_tail(&mut stdout_tail, line); } + Ok(None) => completed_streams += 1, + Err(_) => break, } } - let status = child.wait().map_err(|e| format!("prepare wait failed: {}", e))?; - if let Some(h) = stderr_thread { - let _ = h.join(); - } + let status = child + .wait() + .map_err(|e| format!("prepare wait failed: {}", e))?; if !status.success() { - // Surface the real installer output, not just the exit code (shown in the setup - // window via get_prepare_error and written to prepare_error.log). - let mut msg = format!("prepare exited with status {:?}", status.code()); - let err_lines = stderr_tail.lock().unwrap(); - if !err_lines.is_empty() { - msg.push_str("\n\n--- stderr (tail) ---\n"); - msg.push_str(&err_lines.join("\n")); - } - if !stdout_tail.is_empty() { - msg.push_str("\n\n--- output (tail) ---\n"); - msg.push_str(&stdout_tail.join("\n")); - } - return Err(msg); + return Err(format!("prepare exited with status {:?}", status.code())); } // Record success so later launches (and relocated copies) skip the prepare step. if let Some(marker) = prepared_marker() { @@ -664,213 +1193,678 @@ fn run_offline_prepare(project_dir: &str, report: &dyn Fn(i32, &str)) -> Result< Ok(()) } +const MAX_IDENTITY_RESPONSE_BYTES: usize = 32 * 1024; +const MAX_IDENTITY_PATH_BYTES: usize = 2 * 1024; +const MAX_IDENTITY_BUILD_BYTES: usize = 256; + +fn normalize_bridge_identity(identity: serde_json::Value) -> Option { + let ga_root = identity.get("ga_root")?.as_str()?; + let build_id = identity + .get("build_id") + .and_then(|value| value.as_str()) + .unwrap_or(""); + let pid = identity.get("pid")?.as_u64()?; + if ga_root.is_empty() + || ga_root.len() > MAX_IDENTITY_PATH_BYTES + || build_id.len() > MAX_IDENTITY_BUILD_BYTES + || pid == 0 + { + return None; + } + Some(serde_json::json!({ + "ga_root": ga_root, + "build_id": build_id, + "pid": pid + })) +} + /// GET /services/identity from a running bridge; returns the parsed JSON (or None when the /// endpoint is absent — i.e. an older/foreign bridge). fn bridge_reported_identity() -> Option { use std::io::{Read, Write}; - let mut stream = TcpStream::connect_timeout( - &"127.0.0.1:14168".parse().unwrap(), - Duration::from_millis(800), - ).ok()?; + let endpoint = bridge_endpoint(); + let addr = endpoint.tcp_addr()?; + let mut stream = TcpStream::connect_timeout(&addr, Duration::from_millis(800)).ok()?; let _ = stream.set_read_timeout(Some(Duration::from_millis(800))); let _ = stream.set_write_timeout(Some(Duration::from_millis(600))); - let req = b"GET /services/identity HTTP/1.1\r\nHost: 127.0.0.1\r\nConnection: close\r\n\r\n"; - stream.write_all(req).ok()?; + let req = format!( + "GET /services/identity HTTP/1.1\r\nHost: {}\r\nConnection: close\r\n\r\n", + endpoint.socket_addr(), + ); + stream.write_all(req.as_bytes()).ok()?; let mut buf = Vec::new(); - let _ = stream.read_to_end(&mut buf); + stream + .take((MAX_IDENTITY_RESPONSE_BYTES + 1) as u64) + .read_to_end(&mut buf) + .ok()?; + if buf.len() > MAX_IDENTITY_RESPONSE_BYTES { + return None; + } let text = String::from_utf8_lossy(&buf); - let body = text.split("\r\n\r\n").nth(1)?; - serde_json::from_str(body.trim()).ok() + let mut response = text.splitn(2, "\r\n\r\n"); + let headers = response.next()?; + let status = headers.lines().next()?; + if !(status.starts_with("HTTP/1.1 200 ") || status.starts_with("HTTP/1.0 200 ")) { + return None; + } + let body = response.next()?; + normalize_bridge_identity(serde_json::from_str(body.trim()).ok()?) } fn norm_path(p: &str) -> String { std::fs::canonicalize(p) - .map(|c| display_path(&c)) + .map(|c| c.to_string_lossy().to_string()) .unwrap_or_else(|_| p.to_string()) } -/// A running bridge is "ours" only when it serves the same install path AND was spawned by the -/// same build. The build id (commit+timestamp, see build.rs) changes on every build, so an -/// in-place upgrade or a same-version re-publish still counts as a different bridge → take over. -/// An old bridge with no /identity (None) or no build_id field ("") never matches → taken over. -fn bridge_identity_matches(project_dir: &str) -> bool { - let Some(id) = bridge_reported_identity() else { return false; }; - let reported_root = id.get("ga_root").and_then(|v| v.as_str()).unwrap_or(""); - let reported_build = id.get("build_id").and_then(|v| v.as_str()).unwrap_or(""); - if reported_build != env!("GA_BUILD_ID") { - return false; - } - path_matches(reported_root, project_dir) +fn effective_ga_root(project_dir: &str) -> String { + valid_ga_source_override().unwrap_or_else(|| display_path(&builtin_ga_root(project_dir))) } -/// Last resort when a stale bridge ignores POST /services/bridge/exit (e.g. an old build with -/// no such endpoint): force-kill whatever process is listening on :14168 so the new bridge can -/// bind it. Only called after an identity mismatch, so we never kill a bridge that is ours. -fn force_free_bridge_port() { - #[cfg(windows)] - { - // netstat -ano: last column is the PID for the :14168 LISTENING row. - if let Ok(out) = Command::new("netstat").args(["-ano", "-p", "tcp"]).output() { - let text = String::from_utf8_lossy(&out.stdout); - for line in text.lines() { - if line.contains(":14168") && line.to_uppercase().contains("LISTENING") { - if let Some(pid) = line.split_whitespace().last() { - let mut c = Command::new("taskkill"); - c.args(["/F", "/PID", pid]); - c.creation_flags(0x08000000); - let _ = c.status(); - } - } - } - } - } - #[cfg(not(windows))] - { - // lsof prints the listening PIDs; kill -9 each. - if let Ok(out) = Command::new("lsof").args(["-ti", "tcp:14168", "-sTCP:LISTEN"]).output() { - for pid in String::from_utf8_lossy(&out.stdout).split_whitespace() { - let _ = Command::new("kill").args(["-9", pid]).status(); - } - } +fn bootstrap_failure(code: BootstrapFailureCode, detail: impl AsRef) -> BootstrapFailure { + BootstrapFailure { + code, + detail: sanitize_diagnostic_line(detail.as_ref()), } } fn request_bridge_shutdown() { use std::io::{Read, Write}; - let Ok(mut stream) = TcpStream::connect_timeout( - &"127.0.0.1:14168".parse().unwrap(), - Duration::from_millis(800), - ) else { + let endpoint = bridge_endpoint(); + let Some(addr) = endpoint.tcp_addr() else { + return; + }; + let Ok(mut stream) = TcpStream::connect_timeout(&addr, Duration::from_millis(800)) else { return; }; let _ = stream.set_read_timeout(Some(Duration::from_millis(600))); let _ = stream.set_write_timeout(Some(Duration::from_millis(600))); - let req = b"POST /services/bridge/exit HTTP/1.1\r\nHost: 127.0.0.1\r\nContent-Length: 0\r\nConnection: close\r\n\r\n"; - let _ = stream.write_all(req); + let req = format!( + "POST /services/bridge/exit HTTP/1.1\r\nHost: {}\r\nContent-Length: 0\r\nConnection: close\r\n\r\n", + endpoint.socket_addr(), + ); + let _ = stream.write_all(req.as_bytes()); let _ = stream.read(&mut [0u8; 512]); } -fn takeover_stale_bridge(project_dir: &str) { - if project_dir.is_empty() || !is_bridge_running() { - return; - } - if bridge_identity_matches(project_dir) { - return; - } - eprintln!("[tauri] a different/stale bridge holds 127.0.0.1:14168; taking over"); - request_bridge_shutdown(); - let start = Instant::now(); - while is_bridge_running() && start.elapsed() < Duration::from_secs(10) { - thread::sleep(Duration::from_millis(200)); +fn is_bridge_running() -> bool { + bridge_endpoint() + .tcp_addr() + .is_some_and(|addr| TcpStream::connect(addr).is_ok()) +} + +fn resolve_existing_listener( + app_handle: &tauri::AppHandle, + project_dir: &str, +) -> Result { + if !is_bridge_running() { + if BRIDGE_PROCESS.lock().unwrap().is_some() { + record_diagnostic_log( + app_handle, + "A tracked bridge process no longer owns the local listener; stopping it before retry.", + ); + stop_tracked_bridge(); + } + set_port_diagnostics(app_handle, PortState::Free, None); + return Ok(false); } - // Old bridges have no /services/bridge/exit endpoint and ignore the request above — if the - // port is still held, force-kill the listener so our fresh bridge can bind it. - if is_bridge_running() { - eprintln!("[tauri] stale bridge did not exit; force-freeing :14168"); - force_free_bridge_port(); - let start = Instant::now(); - while is_bridge_running() && start.elapsed() < Duration::from_secs(5) { - thread::sleep(Duration::from_millis(200)); + + let identity = bridge_reported_identity(); + match classify_listener_identity(identity.as_ref(), project_dir) { + ListenerIdentity::Owned => { + set_port_diagnostics(app_handle, PortState::Owned, identity.as_ref()); + Ok(true) + } + ListenerIdentity::Foreign => { + set_port_diagnostics(app_handle, PortState::Foreign, None); + Err(bootstrap_failure( + BootstrapFailureCode::PortConflict, + format!( + "{} is held by an unidentified process", + bridge_endpoint().socket_addr() + ), + )) + } + ListenerIdentity::KnownGenericAgent => { + set_port_diagnostics(app_handle, PortState::Foreign, identity.as_ref()); + record_diagnostic_log( + app_handle, + "A previous GenericAgent bridge was found; requesting graceful shutdown.", + ); + request_bridge_shutdown(); + let start = Instant::now(); + while is_bridge_running() && start.elapsed() < Duration::from_secs(10) { + thread::sleep(Duration::from_millis(200)); + } + + if is_bridge_running() { + let remaining_identity = bridge_reported_identity(); + if classify_listener_identity(remaining_identity.as_ref(), project_dir) + != ListenerIdentity::KnownGenericAgent + { + set_port_diagnostics( + app_handle, + PortState::Foreign, + remaining_identity.as_ref(), + ); + return Err(bootstrap_failure( + BootstrapFailureCode::PortConflict, + "the local listener changed identity while waiting for shutdown", + )); + } + record_diagnostic_log( + app_handle, + "The identified old bridge ignored graceful shutdown; it will not be force-stopped.", + ); + return Err(bootstrap_failure( + BootstrapFailureCode::PortConflict, + format!( + "the identified old bridge did not release {}", + bridge_endpoint().socket_addr() + ), + )); + } + + if is_bridge_running() { + set_port_diagnostics( + app_handle, + PortState::Foreign, + bridge_reported_identity().as_ref(), + ); + Err(bootstrap_failure( + BootstrapFailureCode::PortConflict, + format!( + "the identified old bridge did not release {}", + bridge_endpoint().socket_addr() + ), + )) + } else { + // A bridge spawned by this desktop process may release the socket slightly + // before its process and pipe readers finish. Reap only that tracked child; + // an untracked bridge that exited gracefully is left untouched. + let tracked_child = BRIDGE_PROCESS.lock().unwrap().is_some(); + if tracked_child { + stop_tracked_bridge(); + } + set_port_diagnostics(app_handle, PortState::Free, None); + Ok(false) + } } } } -fn is_bridge_running() -> bool { - TcpStream::connect(("127.0.0.1", 14168)).is_ok() +fn bridge_command(python_path: &str, project_dir: &str) -> Result { + if python_path.trim().is_empty() { + return Err(bootstrap_failure( + BootstrapFailureCode::SpawnFailed, + "Python interpreter path is empty", + )); + } + let dir = PathBuf::from(project_dir); + let script = dir.join("frontends").join("desktop_bridge.py"); + if !script.exists() { + return Err(bootstrap_failure( + BootstrapFailureCode::ConfigUnresolved, + format!("desktop bridge not found under {}", dir.display()), + )); + } + + let mut cmd = Command::new(python_path); + cmd.arg(&script).current_dir(&dir); + cmd.stdout(Stdio::piped()).stderr(Stdio::piped()); + sanitize_bundle_env(&mut cmd, project_dir); + Ok(cmd) } -fn wait_for_port(port: u16, timeout: Duration) -> bool { - let start = Instant::now(); - while start.elapsed() < timeout { - if TcpStream::connect(("127.0.0.1", port)).is_ok() { - return true; +fn capture_bridge_output( + app_handle: tauri::AppHandle, + stream_name: &'static str, + stream: R, +) -> thread::JoinHandle<()> { + thread::spawn(move || { + for line in BufReader::new(stream).lines().map_while(Result::ok) { + record_diagnostic_log(&app_handle, &format!("{stream_name}: {line}")); } - thread::sleep(Duration::from_millis(100)); + }) +} + +fn join_bridge_log_readers() { + let readers = std::mem::take(&mut *BRIDGE_LOG_READERS.lock().unwrap()); + for reader in readers { + let _ = reader.join(); } - false } -fn path_matches(a: &str, b: &str) -> bool { - let (a, b) = (norm_path(a), norm_path(b)); +fn spawn_bridge_process( + app_handle: &tauri::AppHandle, + python_path: &str, + project_dir: &str, +) -> Result<(), BootstrapFailure> { + if is_bridge_running() { + return Err(bootstrap_failure( + BootstrapFailureCode::PortConflict, + format!( + "cannot spawn while {} is already in use", + bridge_endpoint().socket_addr() + ), + )); + } + + let mut command = bridge_command(python_path, project_dir)?; + #[cfg(windows)] + command.creation_flags(0x08000000 | 0x01000000); // CREATE_NO_WINDOW | CREATE_BREAKAWAY_FROM_JOB + + let spawn_result = command.spawn(); #[cfg(windows)] - { a.eq_ignore_ascii_case(&b) } + let mut child = match spawn_result { + Ok(child) => child, + Err(error) if should_retry_without_breakaway(error.raw_os_error()) => { + record_diagnostic_log( + app_handle, + "Windows denied CREATE_BREAKAWAY_FROM_JOB; retrying with CREATE_NO_WINDOW.", + ); + let mut fallback = bridge_command(python_path, project_dir)?; + fallback.creation_flags(0x08000000); // CREATE_NO_WINDOW + fallback.spawn().map_err(|fallback_error| { + bootstrap_failure( + BootstrapFailureCode::SpawnFailed, + format!("bridge spawn fallback failed: {fallback_error}"), + ) + })? + } + Err(error) => { + return Err(bootstrap_failure( + BootstrapFailureCode::SpawnFailed, + format!("bridge spawn failed: {error}"), + )); + } + }; #[cfg(not(windows))] - { a == b } + let mut child = spawn_result.map_err(|error| { + bootstrap_failure( + BootstrapFailureCode::SpawnFailed, + format!("bridge spawn failed: {error}"), + ) + })?; + + let mut readers = Vec::new(); + if let Some(stdout) = child.stdout.take() { + readers.push(capture_bridge_output(app_handle.clone(), "stdout", stdout)); + } + if let Some(stderr) = child.stderr.take() { + readers.push(capture_bridge_output(app_handle.clone(), "stderr", stderr)); + } + *BRIDGE_LOG_READERS.lock().unwrap() = readers; + *BRIDGE_PROCESS.lock().unwrap() = Some(child); + Ok(()) +} + +fn bridge_exit_status() -> Result, BootstrapFailure> { + let result = { + let mut process = BRIDGE_PROCESS.lock().unwrap(); + let result = match process.as_mut() { + Some(child) => child.try_wait().map_err(|error| { + bootstrap_failure( + BootstrapFailureCode::ServiceExited, + format!("failed to inspect bridge process: {error}"), + ) + })?, + None => None, + }; + if result.is_some() { + *process = None; + } + result + }; + if let Some(status) = result { + join_bridge_log_readers(); + return Ok(Some(format!("bridge exited with status {status}"))); + } + Ok(None) +} + +fn stop_tracked_bridge() { + if let Some(mut child) = BRIDGE_PROCESS.lock().unwrap().take() { + let _ = child.kill(); + let _ = child.wait(); + } + join_bridge_log_readers(); } -fn wait_for_bridge_identity(expected_ga_root: &str, timeout: Duration) -> bool { +fn wait_for_owned_bridge( + app_handle: &tauri::AppHandle, + project_dir: &str, + timeout: Duration, +) -> Result<(), BootstrapFailure> { let start = Instant::now(); + let mut unidentified_since: Option = None; while start.elapsed() < timeout { - if let Some(id) = bridge_reported_identity() { - let reported_root = id.get("ga_root").and_then(|v| v.as_str()).unwrap_or(""); - let reported_build = id.get("build_id").and_then(|v| v.as_str()).unwrap_or(""); - if reported_build == env!("GA_BUILD_ID") && path_matches(reported_root, expected_ga_root) { - return true; + if let Some(detail) = bridge_exit_status()? { + return Err(bootstrap_failure( + BootstrapFailureCode::ServiceExited, + detail, + )); + } + + if let Some(identity) = bridge_reported_identity() { + match classify_listener_identity(Some(&identity), project_dir) { + ListenerIdentity::Owned => { + set_port_diagnostics(app_handle, PortState::Owned, Some(&identity)); + return Ok(()); + } + ListenerIdentity::KnownGenericAgent => { + set_port_diagnostics(app_handle, PortState::Foreign, Some(&identity)); + return Err(bootstrap_failure( + BootstrapFailureCode::PortConflict, + "a different GenericAgent bridge answered during readiness", + )); + } + ListenerIdentity::Foreign => { + set_port_diagnostics(app_handle, PortState::Foreign, None); + return Err(bootstrap_failure( + BootstrapFailureCode::PortConflict, + "a foreign identity response answered during readiness", + )); + } + } + } + + if is_bridge_running() { + let since = unidentified_since.get_or_insert_with(Instant::now); + if BRIDGE_PROCESS.lock().unwrap().is_none() || since.elapsed() >= Duration::from_secs(2) + { + set_port_diagnostics(app_handle, PortState::Foreign, None); + return Err(bootstrap_failure( + BootstrapFailureCode::PortConflict, + "an unidentified process answered during readiness", + )); } + } else { + unidentified_since = None; } thread::sleep(Duration::from_millis(150)); } - false + + Err(bootstrap_failure( + BootstrapFailureCode::ServiceTimeout, + format!( + "bridge identity did not become ready within {} seconds", + timeout.as_secs() + ), + )) } -fn spawn_bridge_process(python_path: &str, project_dir: &str) -> Result<(), String> { - if is_bridge_running() { - return Ok(()); +fn main_ui_url_from_current(mut current_url: tauri::Url) -> Result { + if current_url.cannot_be_a_base() { + return Err("current main window URL cannot resolve an application asset".to_string()); } - let py = PathBuf::from(python_path); - let dir = PathBuf::from(project_dir); - let script = dir.join("frontends").join("desktop_bridge.py"); - if !script.exists() { - return Err(format!("desktop_bridge.py not found at {:?}", script)); + current_url.set_path("/index.html"); + current_url.set_query(None); + current_url.set_fragment(None); + Ok(current_url) +} + +fn open_main_window(app_handle: &tauri::AppHandle, dev_mode: bool) -> Result<(), BootstrapFailure> { + let main_window = app_handle.get_webview_window("main").ok_or_else(|| { + bootstrap_failure( + BootstrapFailureCode::UiNavigationFailed, + "main window is unavailable", + ) + })?; + // Derive the target from the webview's current loading.html URL so each + // platform keeps the asset scheme Tauri selected for it. WebView2 uses + // http://tauri.localhost while WKWebView uses tauri://localhost. + let current_url = main_window.url().map_err(|error| { + bootstrap_failure( + BootstrapFailureCode::UiNavigationFailed, + format!("main window URL could not be read: {error}"), + ) + })?; + let url = main_ui_url_from_current(current_url.clone()) + .map_err(|error| bootstrap_failure(BootstrapFailureCode::UiNavigationFailed, error))?; + // Source switches are invoked from index.html. Navigating that same webview while its + // Tauri command is in flight destroys the JavaScript callback, so the caller never sees + // the command resolve and a subsequent clear_ga_source can remain blocked. Initial + // bootstrap still moves loading.html to index.html; hot restarts keep the current page. + if current_url != url { + main_window.navigate(url).map_err(|error| { + bootstrap_failure( + BootstrapFailureCode::UiNavigationFailed, + format!("main window navigation failed: {error}"), + ) + })?; + } + main_window.show().map_err(|error| { + bootstrap_failure( + BootstrapFailureCode::UiNavigationFailed, + format!("main window could not be shown: {error}"), + ) + })?; + main_window.set_focus().map_err(|error| { + bootstrap_failure( + BootstrapFailureCode::UiNavigationFailed, + format!("main window could not be focused: {error}"), + ) + })?; + + if dev_mode { + main_window.open_devtools(); + } else { + let _ = main_window.eval( + r#" + document.addEventListener('keydown', function(e) { + if (e.key === 'F12' || e.key === 'F5' || + (e.ctrlKey && e.key === 'r') || + (e.ctrlKey && e.shiftKey && e.key === 'I')) { + e.preventDefault(); + } + }); + document.addEventListener('contextmenu', function(e) { + e.preventDefault(); + }); + "#, + ); } - let mut cmd = Command::new(&py); - cmd.arg(&script).current_dir(&dir); - sanitize_bundle_env(&mut cmd); - #[cfg(windows)] - cmd.creation_flags(0x08000000); // CREATE_NO_WINDOW - let child = cmd.spawn().map_err(|e| format!("Failed to spawn: {}", e))?; - *BRIDGE_PROCESS.lock().unwrap() = Some(child); + if let Some(setup_window) = app_handle.get_webview_window("setup") { + let _ = setup_window.hide(); + } Ok(()) } -fn show_bridge_window(app_handle: &tauri::AppHandle) { - if let Some(main_win) = app_handle.get_webview_window("main") { - let url = tauri::Url::parse("http://127.0.0.1:14168/").unwrap(); - let _ = main_win.navigate(url); - let _ = main_win.show(); - let _ = main_win.set_focus(); +fn show_bootstrap_recovery(app_handle: &tauri::AppHandle) { + if let Some(main_window) = app_handle.get_webview_window("main") { + let _ = main_window.hide(); } - if let Some(setup_win) = app_handle.get_webview_window("setup") { - let _ = setup_win.hide(); + if let Some(setup_window) = app_handle.get_webview_window("setup") { + let _ = setup_window.show(); + let _ = setup_window.set_focus(); } } -#[tauri::command] -fn start_bridge_with_config(app_handle: tauri::AppHandle, python_path: String, project_dir: String) -> Result<(), String> { - // Save to settings (merge so sibling keys like desktop_shortcut survive). - merge_settings(serde_json::json!({"python_path": python_path, "project_dir": project_dir})); - - spawn_bridge_process(&python_path, &project_dir)?; +static BOOTSTRAP_RUN_LOCK: Mutex<()> = Mutex::new(()); + +fn bootstrap_inner( + app_handle: &tauri::AppHandle, + python_path: &str, + project_dir: &str, + dev_mode: bool, +) -> Result<(), BootstrapFailure> { + let project = PathBuf::from(project_dir); + if project_dir.trim().is_empty() + || !project.join("agentmain.py").exists() + || !project.join("frontends").join("desktop_bridge.py").exists() + { + return Err(bootstrap_failure( + BootstrapFailureCode::ConfigUnresolved, + format!("GenericAgent source was not found at {}", project.display()), + )); + } + if !python_interpreter_resolves(python_path) { + return Err(bootstrap_failure( + BootstrapFailureCode::SpawnFailed, + format!("Python interpreter was not found at {python_path}"), + )); + } + + ensure_builtin_ga_root(project_dir) + .map_err(|detail| bootstrap_failure(BootstrapFailureCode::PrepareFailed, detail))?; + + set_bootstrap_phase(app_handle, BootstrapPhase::Resolving, Some("validate"), 10); + let expected_ga_root = effective_ga_root(project_dir); + let prepare_needed = needs_first_run_prepare(project_dir); + let already_ready = resolve_existing_listener(app_handle, &expected_ga_root)?; + if already_ready { + snapshot_update(Some(app_handle), |snapshot| { + snapshot.mode = BootstrapMode::HotStart + }); + } else { + snapshot_update(Some(app_handle), |snapshot| { + snapshot.mode = if prepare_needed { + BootstrapMode::Prepare + } else { + BootstrapMode::ColdStart + }; + }); + if prepare_needed { + set_bootstrap_phase(app_handle, BootstrapPhase::Preparing, Some("validate"), 15); + let report = |progress: i32, stage: &str| { + set_bootstrap_phase( + app_handle, + BootstrapPhase::Preparing, + Some(stage), + progress.clamp(0, 100) as u8, + ); + }; + let log = |line: &str| record_diagnostic_log(app_handle, line); + run_offline_prepare(project_dir, &report, &log) + .map_err(|detail| bootstrap_failure(BootstrapFailureCode::PrepareFailed, detail))?; + } - // Wait for port - if !wait_for_port(14168, Duration::from_secs(20)) { - return Err("Bridge did not become ready within 20s".into()); + set_bootstrap_phase( + app_handle, + BootstrapPhase::StartingService, + Some("service"), + 82, + ); + spawn_bridge_process(app_handle, python_path, project_dir)?; } - show_bridge_window(&app_handle); + set_bootstrap_phase( + app_handle, + BootstrapPhase::StartingService, + Some("service"), + 90, + ); + let timeout = if prepare_needed && !already_ready { + Duration::from_secs(60) + } else { + Duration::from_secs(30) + }; + wait_for_owned_bridge(app_handle, &expected_ga_root, timeout)?; + + set_bootstrap_phase(app_handle, BootstrapPhase::OpeningUi, Some("ui"), 98); + open_main_window(app_handle, dev_mode)?; + set_bootstrap_phase(app_handle, BootstrapPhase::Ready, None, 100); + maybe_setup_shortcut(); Ok(()) } +fn execute_bootstrap( + app_handle: &tauri::AppHandle, + python_path: String, + project_dir: String, + dev_mode: bool, +) -> Result<(), String> { + let _run_guard = BOOTSTRAP_RUN_LOCK + .lock() + .map_err(|_| "bootstrap lock poisoned".to_string())?; + let initial_mode = if needs_first_run_prepare(&project_dir) { + BootstrapMode::Prepare + } else { + BootstrapMode::ColdStart + }; + begin_bootstrap(app_handle, initial_mode, &python_path, &project_dir); + + match bootstrap_inner(app_handle, &python_path, &project_dir, dev_mode) { + Ok(()) => Ok(()), + Err(failure) => { + if matches!( + failure.code, + BootstrapFailureCode::ServiceTimeout | BootstrapFailureCode::PortConflict + ) { + // This handle only ever refers to a child spawned by this desktop process. + // It is safe to stop; the unidentified listener itself is never targeted. + stop_tracked_bridge(); + } + record_diagnostic_log(app_handle, &failure.detail); + snapshot_update(Some(app_handle), |snapshot| { + snapshot.phase = BootstrapPhase::Failed; + snapshot.progress = snapshot.progress.min(99); + snapshot.failure = Some(failure.clone()); + }); + show_bootstrap_recovery(app_handle); + Err(failure.detail) + } + } +} + +async fn execute_bootstrap_async( + app_handle: tauri::AppHandle, + python_path: String, + project_dir: String, + dev_mode: bool, +) -> Result<(), String> { + tauri::async_runtime::spawn_blocking(move || { + execute_bootstrap(&app_handle, python_path, project_dir, dev_mode) + }) + .await + .map_err(|error| format!("bootstrap task failed: {error}"))? +} + +fn resolve_requested_bootstrap_config( + requested_python: String, + requested_project: String, +) -> (String, String) { + if bundle_root().is_some() { + return get_or_discover_config(); + } + let python = if requested_python.trim().is_empty() { + find_python() + } else { + requested_python + }; + merge_settings(serde_json::json!({ + "python_path": python, + "project_dir": requested_project + })); + (python, requested_project) +} + +#[tauri::command] +async fn retry_bootstrap( + app_handle: tauri::AppHandle, + python_path: String, + project_dir: String, +) -> Result<(), String> { + let (python_path, project_dir) = resolve_requested_bootstrap_config(python_path, project_dir); + execute_bootstrap_async(app_handle, python_path, project_dir, false).await +} + +#[tauri::command] +async fn start_bridge_with_config( + app_handle: tauri::AppHandle, + python_path: String, + project_dir: String, +) -> Result<(), String> { + let (python_path, project_dir) = resolve_requested_bootstrap_config(python_path, project_dir); + execute_bootstrap_async(app_handle, python_path, project_dir, false).await +} + #[tauri::command] -fn start_bridge(app_handle: tauri::AppHandle) -> Result<(), String> { +async fn start_bridge(app_handle: tauri::AppHandle) -> Result<(), String> { let (python_path, project_dir) = get_or_discover_config(); - spawn_bridge_process(&python_path, &project_dir)?; - if !wait_for_port(14168, Duration::from_secs(20)) { - return Err("Bridge did not become ready within 20s".into()); - } - show_bridge_window(&app_handle); - Ok(()) + execute_bootstrap_async(app_handle, python_path, project_dir, false).await } #[tauri::command] @@ -904,173 +1898,242 @@ fn pick_directory(title: Option) -> Option { dlg.pick_folder().map(|p| p.to_string_lossy().into_owned()) } -/// Stop the current bridge (ours or a stale one) and free :14168 before respawning. -fn stop_current_bridge() { - request_bridge_shutdown(); - if let Some(mut child) = BRIDGE_PROCESS.lock().unwrap().take() { - let _ = child.kill(); - let _ = child.wait(); - } - let start = Instant::now(); - while is_bridge_running() && start.elapsed() < Duration::from_secs(6) { - thread::sleep(Duration::from_millis(150)); - } - if is_bridge_running() { - force_free_bridge_port(); - let start = Instant::now(); - while is_bridge_running() && start.elapsed() < Duration::from_secs(5) { - thread::sleep(Duration::from_millis(150)); - } - } -} - -/// Restart the bridge with whatever get_or_discover_config() now resolves to, then reload the -/// webview so it reconnects. Shared by set_ga_source / clear_ga_source. -fn switch_bridge(app_handle: &tauri::AppHandle) -> Result { - stop_current_bridge(); - let (py, project) = get_or_discover_config(); - if project.is_empty() { - return Err("no GenericAgent source resolved".into()); - } - let expected_ga_root = valid_ga_source_override().unwrap_or_else(|| project.clone()); - spawn_bridge_process(&py, &project)?; - if !wait_for_port(14168, Duration::from_secs(20)) { - return Err("bridge did not become ready within 20s".into()); - } - if !wait_for_bridge_identity(&expected_ga_root, Duration::from_secs(10)) { - return Err(format!("bridge did not switch to GA workspace: {}", expected_ga_root)); - } - show_bridge_window(app_handle); - Ok(expected_ga_root) -} - #[tauri::command] fn get_ga_source() -> String { - read_settings() - .get("ga_source_override") - .and_then(|v| v.as_str()) - .unwrap_or("") - .to_string() + valid_ga_source_override().unwrap_or_default() } -#[tauri::command] -fn move_ga_runtime(app_handle: tauri::AppHandle, dir: String) -> Result { - let previous_override = read_settings() +fn saved_ga_source_override() -> Option { + read_settings() .get("ga_source_override") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()); - let src_s = valid_ga_source_override().or_else(|| find_project_dir()).unwrap_or_default(); - let src = PathBuf::from(src_s.trim()); - let parent = PathBuf::from(dir.trim()); - if src_s.trim().is_empty() { - return Err("current GA workspace is empty; wait for the bridge to become ready and try again".into()); - } - if dir.trim().is_empty() { - return Err("target parent directory is empty".into()); - } - if !src.is_dir() || !src.join("agentmain.py").exists() { - return Err(format!("current GA workspace is invalid: {}", src.to_string_lossy())); - } - std::fs::create_dir_all(&parent).map_err(|e| format!("cannot create target parent dir: {}", e))?; - let src_c = src.canonicalize().unwrap_or(src.clone()); - let parent_c = parent.canonicalize().unwrap_or(parent.clone()); - let name = src_c.file_name().and_then(|s| s.to_str()).unwrap_or("GenericAgent"); - let folder_name = if name == "app" { "GenericAgent" } else { name }; - let dst = parent_c.join(folder_name); - let dst_c = if dst.exists() { dst.canonicalize().unwrap_or(dst.clone()) } else { dst.clone() }; - if same_path(&src_c, &dst_c) { - merge_settings(serde_json::json!({ "ga_source_override": display_path(&dst_c) })); - return switch_bridge(&app_handle).map_err(|err| { - restore_setting("ga_source_override", previous_override.clone()); - err - }); - } - if dst_c.starts_with(&src_c) { - return Err("target directory cannot be inside the current GA workspace".into()); - } - if dst_c.exists() { - return Err(format!("target GA workspace already exists: {}", display_path(&dst_c))); - } - copy_dir_replace(&src_c, &dst_c)?; - merge_settings(serde_json::json!({ "ga_source_override": display_path(&dst_c) })); - if let Err(err) = switch_bridge(&app_handle) { - restore_setting("ga_source_override", previous_override); - return Err(err); - } - - // The packaged bundle's own runtime/app is still needed by the desktop shell and - // bridge. Only remove the old source when it is already a user-selected external copy. - let bundled = bundled_project_dir(); - if !bundled.as_ref().map(|p| same_path(&src_c, p)).unwrap_or(false) { - if let Err(e) = std::fs::remove_dir_all(&src_c) { - eprintln!("remove old runtime {:?}: {}", src_c, e); - } - } - Ok(display_path(&dst_c)) + .and_then(|value| value.as_str()) + .map(str::to_string) } -/// Run the contract probe (frontends/ga_contract_probe.py, shipped with the bundle) against a -/// target ga_root using the bundle python. Returns Ok(()) if the核 satisfies the bridge/conductor -/// contract, or Err(message) listing what's missing / why it's incompatible. fn probe_ga_source(dir: &str) -> Result<(), String> { - let (py, bundle_project) = get_or_discover_config(); - if py.is_empty() { - return Err("no python available to run the compatibility probe".into()); + let (python, bundle_project) = get_or_discover_config(); + if python.is_empty() { + return Err("no python available to run the compatibility probe".to_string()); } - let probe = PathBuf::from(&bundle_project).join("frontends").join("ga_contract_probe.py"); + let probe = PathBuf::from(&bundle_project) + .join("frontends") + .join("ga_contract_probe.py"); if !probe.exists() { - // No probe shipped → skip the check rather than block (backward compatible). - return Ok(()); + return Err("the packaged compatibility probe is missing".to_string()); } - let mut cmd = Command::new(&py); - cmd.arg(&probe).arg(dir); - sanitize_bundle_env(&mut cmd); - // If switching from one external core to another, validate the candidate core, not the - // previously saved GA_ROOT that sanitize_bundle_env may have injected. - cmd.env("GA_ROOT", dir); + + let mut command = Command::new(python); + command.arg(probe).arg(dir); + sanitize_bundle_env(&mut command, &bundle_project); + command.env("GA_ROOT", dir); #[cfg(windows)] - cmd.creation_flags(0x08000000); - let out = cmd.output().map_err(|e| format!("probe failed to run: {}", e))?; - let stdout = String::from_utf8_lossy(&out.stdout); - // The probe prints a JSON line: {"ok":bool,"missing":[..],"error":".."}. - if let Some(line) = stdout.lines().rev().find(|l| l.trim_start().starts_with('{')) { - if let Ok(v) = serde_json::from_str::(line.trim()) { - if v.get("ok").and_then(|b| b.as_bool()).unwrap_or(false) { + command.creation_flags(0x08000000); + let output = command + .output() + .map_err(|error| format!("compatibility probe failed to run: {error}"))?; + let stdout = String::from_utf8_lossy(&output.stdout); + if let Some(line) = stdout + .lines() + .rev() + .find(|line| line.trim_start().starts_with('{')) + { + if let Ok(verdict) = serde_json::from_str::(line.trim()) { + if verdict.get("ok").and_then(|value| value.as_bool()) == Some(true) { return Ok(()); } - let missing = v.get("missing") - .and_then(|m| m.as_array()) - .map(|a| a.iter().filter_map(|x| x.as_str()).collect::>().join(", ")) + let missing = verdict + .get("missing") + .and_then(|value| value.as_array()) + .map(|items| { + items + .iter() + .filter_map(|item| item.as_str()) + .collect::>() + .join(", ") + }) .unwrap_or_default(); - let err = v.get("error").and_then(|e| e.as_str()).unwrap_or(""); - let mut msg = String::from("this GenericAgent core is not compatible"); - if !missing.is_empty() { msg = format!("{}: missing {}", msg, missing); } - if !err.is_empty() { msg = format!("{} ({})", msg, err); } - return Err(msg); + let detail = verdict + .get("error") + .and_then(|value| value.as_str()) + .unwrap_or(""); + let mut message = "this GenericAgent core is not compatible".to_string(); + if !missing.is_empty() { + message.push_str(&format!(": missing {missing}")); + } + if !detail.is_empty() { + message.push_str(&format!(" ({detail})")); + } + return Err(message); } } - Err(format!("compatibility probe returned no verdict: {}", - String::from_utf8_lossy(&out.stderr).lines().last().unwrap_or(""))) + let stderr = String::from_utf8_lossy(&output.stderr); + Err(format!( + "compatibility probe returned no verdict: {}", + stderr.lines().last().unwrap_or("") + )) } -#[tauri::command] -fn set_ga_source(app_handle: tauri::AppHandle, dir: String) -> Result { - let p = PathBuf::from(&dir); - if !p.join("agentmain.py").exists() { - return Err("not a GenericAgent source: agentmain.py not found".into()); +async fn restart_for_current_source(app_handle: tauri::AppHandle) -> Result { + let (python_path, project_dir) = get_or_discover_config(); + let expected_ga_root = effective_ga_root(&project_dir); + execute_bootstrap_async(app_handle, python_path, project_dir, false).await?; + Ok(expected_ga_root) +} + +async fn apply_ga_source_with_rollback( + app_handle: tauri::AppHandle, + next_override: Option, + previous_override: Option, +) -> Result { + restore_setting("ga_source_override", next_override); + match restart_for_current_source(app_handle.clone()).await { + Ok(root) => Ok(root), + Err(error) => { + restore_setting("ga_source_override", previous_override); + match restart_for_current_source(app_handle).await { + Ok(_) => Err(error), + Err(rollback_error) => Err(format!( + "{error}; restoring the previous workspace also failed: {rollback_error}" + )), + } + } + } +} + +#[derive(Debug)] +struct RuntimeMovePlan { + previous_override: Option, + source: PathBuf, + destination: PathBuf, + remove_source_after_switch: bool, +} + +fn should_remove_source_after_switch( + source: &Path, + destination: &Path, + bundled: Option<&Path>, +) -> bool { + !same_path(source, destination) + && !bundled + .map(|bundled| same_path(source, bundled)) + .unwrap_or(false) +} + +fn prepare_runtime_move(target_parent: &str) -> Result { + let previous_override = saved_ga_source_override(); + let external_source = valid_ga_source_override(); + let (_, project_dir) = get_or_discover_config(); + let source_text = external_source + .clone() + .unwrap_or_else(|| effective_ga_root(&project_dir)); + if source_text.trim().is_empty() { + return Err( + "current GA workspace is empty; wait for the bridge to become ready and try again" + .to_string(), + ); + } + if target_parent.trim().is_empty() { + return Err("target parent directory is empty".to_string()); + } + + let source = PathBuf::from(source_text.trim()); + if !source.is_dir() || !source.join("agentmain.py").exists() { + return Err(format!( + "current GA workspace is invalid: {}", + source.to_string_lossy() + )); + } + let parent = PathBuf::from(target_parent.trim()); + std::fs::create_dir_all(&parent) + .map_err(|error| format!("cannot create target parent dir: {error}"))?; + let source = source.canonicalize().unwrap_or(source); + let parent = parent.canonicalize().unwrap_or(parent); + let source_name = source + .file_name() + .and_then(|name| name.to_str()) + .unwrap_or("GenericAgent"); + let folder_name = if source_name == "app" { + "GenericAgent" + } else { + source_name + }; + let destination = parent.join(folder_name); + let destination = if destination.exists() { + destination.canonicalize().unwrap_or(destination) + } else { + destination + }; + + if destination.starts_with(&source) && !same_path(&source, &destination) { + return Err("target directory cannot be inside the current GA workspace".to_string()); } - // 方案三: we do NOT copy files into 本体. We run the bundle's own bridge/frontend and point - // its ga_root at this external核 via GA_ROOT. Verify the核 satisfies the contract first so a - // stale/incompatible核 fails up front with a clear message instead of a runtime crash. - probe_ga_source(&dir)?; - merge_settings(serde_json::json!({ "ga_source_override": dir })); - switch_bridge(&app_handle) + if !same_path(&source, &destination) { + if destination.exists() { + return Err(format!( + "target GA workspace already exists: {}", + display_path(&destination) + )); + } + copy_dir_replace(&source, &destination)?; + } + + let bundled = bundled_project_dir(); + let remove_source_after_switch = external_source.is_some() + && should_remove_source_after_switch(&source, &destination, bundled.as_deref()); + Ok(RuntimeMovePlan { + previous_override, + source, + destination, + remove_source_after_switch, + }) +} + +#[tauri::command] +async fn set_ga_source(app_handle: tauri::AppHandle, dir: String) -> Result { + let source = PathBuf::from(dir.trim()); + if !source.join("agentmain.py").exists() { + return Err("not a GenericAgent source: agentmain.py not found".to_string()); + } + let source = source.canonicalize().unwrap_or(source); + let source_text = display_path(&source); + let probe_source = source_text.clone(); + tauri::async_runtime::spawn_blocking(move || probe_ga_source(&probe_source)) + .await + .map_err(|error| format!("compatibility probe task failed: {error}"))??; + let previous_override = saved_ga_source_override(); + apply_ga_source_with_rollback(app_handle, Some(source_text), previous_override).await } #[tauri::command] -fn clear_ga_source(app_handle: tauri::AppHandle) -> Result { - remove_setting("ga_source_override"); - switch_bridge(&app_handle) +async fn clear_ga_source(app_handle: tauri::AppHandle) -> Result { + let previous_override = saved_ga_source_override(); + apply_ga_source_with_rollback(app_handle, None, previous_override).await +} + +#[tauri::command] +async fn move_ga_runtime(app_handle: tauri::AppHandle, dir: String) -> Result { + let plan = tauri::async_runtime::spawn_blocking(move || prepare_runtime_move(&dir)) + .await + .map_err(|error| format!("runtime copy task failed: {error}"))??; + let destination_text = display_path(&plan.destination); + apply_ga_source_with_rollback( + app_handle, + Some(destination_text.clone()), + plan.previous_override, + ) + .await?; + + if plan.remove_source_after_switch { + let source = plan.source; + tauri::async_runtime::spawn_blocking(move || { + if let Err(error) = std::fs::remove_dir_all(&source) { + eprintln!("remove old runtime {:?}: {error}", source); + } + }) + .await + .map_err(|error| format!("old runtime cleanup task failed: {error}"))?; + } + Ok(destination_text) } #[cfg_attr(mobile, tauri::mobile_entry_point)] @@ -1079,174 +2142,149 @@ pub fn run() { let no_autostart = args.iter().any(|a| a == "--no-autostart"); let dev_mode = args.iter().any(|a| a == "--dev"); - // Resolve the effective config once. project_dir is ALWAYS the bundle's own (方案三: we run - // our own bridge/frontend); the external核, if any, is injected via GA_ROOT in - // sanitize_bundle_env. Identity/takeover must compare against the EFFECTIVE ga_root (what the - // bridge will report), not the bundle script dir. let (eff_py, eff_project) = get_or_discover_config(); - let effective_ga_root = valid_ga_source_override().unwrap_or_else(|| eff_project.clone()); - let needs_prepare = needs_first_run_prepare(&eff_project); - - takeover_stale_bridge(&effective_ga_root); - - let bridge_ok = is_bridge_running(); - let mut spawned_bridge = false; - // Skip the early spawn when a first-run prepare is required (no venv yet); - // the setup thread prepares the env first and then starts the bridge. - if !bridge_ok && !no_autostart && !needs_prepare { - let dir = PathBuf::from(&eff_project); - let script = dir.join("frontends").join("desktop_bridge.py"); - if script.exists() { - let mut cmd = Command::new(&eff_py); - cmd.arg(&script).current_dir(&dir); - sanitize_bundle_env(&mut cmd); - #[cfg(windows)] - cmd.creation_flags(0x08000000); - if let Ok(child) = cmd.spawn() { - *BRIDGE_PROCESS.lock().unwrap() = Some(child); - spawned_bridge = true; - } - } - } - tauri::Builder::default() + let builder = tauri::Builder::default() + .plugin(tauri_plugin_opener::init()) .plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| { - if let Some(w) = app.get_webview_window("main") { - let _ = w.unminimize(); - let _ = w.show(); - let _ = w.set_focus(); + let bootstrap_failed = matches!( + BOOTSTRAP_STATE.lock().unwrap().phase, + BootstrapPhase::Failed + ); + if bootstrap_failed { + if let Some(window) = app.get_webview_window("setup") { + let _ = window.show(); + let _ = window.set_focus(); + } + } else if let Some(window) = app.get_webview_window("main") { + let _ = window.unminimize(); + let _ = window.show(); + let _ = window.set_focus(); } - })) - .invoke_handler(tauri::generate_handler![start_bridge_with_config, start_bridge, get_config, export_mykey, pick_directory, get_ga_source, set_ga_source, clear_ga_source, move_ga_runtime, shortcut_should_ask, shortcut_decide, get_prepare_error]) + })); + + #[cfg(feature = "e2e")] + let builder = if std::env::var("GA_E2E").ok().as_deref() == Some("1") { + builder + .plugin(tauri_plugin_wdio::init()) + .plugin(tauri_plugin_wdio_webdriver::init()) + } else { + builder + }; + + builder + .invoke_handler(tauri::generate_handler![ + start_bridge_with_config, + start_bridge, + retry_bootstrap, + get_bootstrap_snapshot, + get_config, + export_mykey, + pick_directory, + get_ga_source, + set_ga_source, + clear_ga_source, + move_ga_runtime, + shortcut_should_ask, + shortcut_decide + ]) .setup(move |app| { // Show the loading window immediately so the first-run prepare isn't a blank screen. // The window starts on loading.html (a local page), so no "connection refused" flash. if let Some(w) = app.get_webview_window("main") { + // Windows: remove native decorations at runtime (config keeps them for macOS + // traffic lights). titleBarStyle:"Overlay" is macOS-only in Tauri v2. + #[cfg(windows)] + let _ = w.set_decorations(false); let _ = w.show(); } - let handle = app.handle().clone(); - let project_dir = eff_project.clone(); - thread::spawn(move || { - // Progress reporter: push status into the loading window (window.gaProgress). - let main_win = handle.get_webview_window("main"); - - let report = |pct: i32, msg: &str| { - if let Some(w) = &main_win { - let js = format!( - "window.gaProgress && window.gaProgress({}, {})", - pct, - serde_json::to_string(msg).unwrap_or_else(|_| "\"\"".to_string()) - ); - let _ = w.eval(&js); - } - }; - - // First-run (self-contained bundle): prepare the embedded python env offline, - // then start the bridge with the freshly created venv. - if needs_prepare { - report(5, "start"); - if let Err(e) = run_offline_prepare(&project_dir, &report) { - eprintln!("[tauri] first-run prepare failed: {}", e); - // Persist the error for the setup window and to a log file next to the - // bundle, so the failure is explicit instead of a silent config screen. - *PREPARE_ERROR.lock().unwrap() = Some(e.clone()); - if let Some(root) = bundle_root() { - let _ = std::fs::write(root.join("prepare_error.log"), &e); - } - if let Some(sw) = handle.get_webview_window("setup") { let _ = sw.show(); } - if let Some(mw) = handle.get_webview_window("main") { let _ = mw.hide(); } - return; - } - report(95, "starting"); - if !is_bridge_running() { - let (py_str, dir_str) = get_or_discover_config(); - let dir = PathBuf::from(&dir_str); - let script = dir.join("frontends").join("desktop_bridge.py"); - if script.exists() { - let mut cmd = Command::new(&py_str); - cmd.arg(&script).current_dir(&dir); - sanitize_bundle_env(&mut cmd); - #[cfg(windows)] - cmd.creation_flags(0x08000000); - if let Ok(child) = cmd.spawn() { - *BRIDGE_PROCESS.lock().unwrap() = Some(child); + // Windows: system tray so the app can hide-on-close instead of exiting. + #[cfg(windows)] + { + let show_item = MenuItemBuilder::with_id("show", "显示主窗口").build(app)?; + let quit_item = MenuItemBuilder::with_id("quit", "退出").build(app)?; + let menu = MenuBuilder::new(app) + .item(&show_item) + .separator() + .item(&quit_item) + .build()?; + + let _tray = TrayIconBuilder::new() + .icon(app.default_window_icon().unwrap().clone()) + .tooltip("GenericAgent") + .menu(&menu) + .on_menu_event(|app, event| match event.id().as_ref() { + "show" => { + if let Some(w) = app.get_webview_window("main") { + let _ = w.show(); + let _ = w.unminimize(); + let _ = w.set_focus(); } } - } - } - - // First run (prepare) and cold bridge start may take a while; allow up to 60s. - let wait = if needs_prepare || spawned_bridge { - Duration::from_secs(60) - } else { - Duration::from_secs(2) - }; - let bridge_ready = wait_for_port(14168, wait); - - if bridge_ready { - // The bridge auto-starts conductor + scheduler itself (on_startup), so we do - // NOT probe their ports here: that would self-detect the bridge's own - // just-started extras and falsely report "ports busy". - if !wait_for_port(14168, Duration::from_secs(15)) { - eprintln!("[tauri] bridge not reachable before navigate"); - if let Some(w) = &main_win { - let msg = "无法连接 bridge (127.0.0.1:14168),请关闭程序后重试。"; - let js = format!( - "alert({})", - serde_json::to_string(msg).unwrap_or_else(|_| "\"\"".to_string()) - ); - let _ = w.eval(&js); - } - return; - } - // Navigate to the bridge HTTP only after it is ready. - if let Some(w) = handle.get_webview_window("main") { - if let Ok(url) = tauri::Url::parse("http://127.0.0.1:14168/") { - let _ = w.navigate(url); + "quit" => { + app.exit(0); } - if dev_mode { - w.open_devtools(); - } else { - // Disable F5/F12/Ctrl+R/right-click in production - let _ = w.eval(r#" - document.addEventListener('keydown', function(e) { - if (e.key === 'F12' || e.key === 'F5' || - (e.ctrlKey && e.key === 'r') || - (e.ctrlKey && e.shiftKey && e.key === 'I')) { - e.preventDefault(); - } - }); - document.addEventListener('contextmenu', function(e) { - e.preventDefault(); - }); - "#); + _ => {} + }) + .on_tray_icon_event(|tray, event| { + if let TrayIconEvent::Click { + button: MouseButton::Left, + button_state: MouseButtonState::Up, + .. + } = event + { + if let Some(w) = tray.app_handle().get_webview_window("main") { + let _ = w.show(); + let _ = w.unminimize(); + let _ = w.set_focus(); + } } - let _ = w.show(); - let _ = w.set_focus(); - } - if let Some(sw) = handle.get_webview_window("setup") { let _ = sw.hide(); } - // App is up and reachable: ask-once / self-heal the desktop shortcut. - // Runs last so it never blocks the loading/navigation path. - maybe_setup_shortcut(); + }) + .build(app)?; + } + + let handle = app.handle().clone(); + let python_path = eff_py.clone(); + let project_dir = eff_project.clone(); + thread::spawn(move || { + if no_autostart && !is_bridge_running() { + begin_bootstrap( + &handle, + BootstrapMode::ColdStart, + &python_path, + &project_dir, + ); + let failure = bootstrap_failure( + BootstrapFailureCode::Unknown, + "automatic bridge startup was disabled by --no-autostart", + ); + snapshot_update(Some(&handle), |snapshot| { + snapshot.phase = BootstrapPhase::Failed; + snapshot.failure = Some(failure); + }); + show_bootstrap_recovery(&handle); } else { - // Bridge never came up -> let the user fix paths in the setup window. - if let Some(sw) = handle.get_webview_window("setup") { - if dev_mode { sw.open_devtools(); } - let _ = sw.show(); - } - if let Some(mw) = handle.get_webview_window("main") { let _ = mw.hide(); } + let _ = execute_bootstrap(&handle, python_path, project_dir, dev_mode); } }); Ok(()) }) .on_window_event(|window, event| { - if let tauri::WindowEvent::CloseRequested { .. } = event { + if let tauri::WindowEvent::CloseRequested { api, .. } = event { let label = window.label(); if label == "main" { - // Persistent backend: closing the window does NOT stop the bridge or its - // services, so relaunching attaches to the warm backend on 14168. - window.app_handle().exit(0); + #[cfg(windows)] + { + // Windows: hide to tray instead of exiting. Bridge stays alive. + api.prevent_close(); + let _ = window.hide(); + } + #[cfg(not(windows))] + { + let _ = api; + window.app_handle().exit(0); + } } else if label == "setup" { // Setup closed -> exit if main is not visible if let Some(main_win) = window.app_handle().get_webview_window("main") { @@ -1262,3 +2300,210 @@ pub fn run() { .run(tauri::generate_context!()) .expect("error while running tauri application"); } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn sensitive_diagnostic_lines_are_replaced_and_long_lines_are_bounded() { + assert_eq!( + sanitize_diagnostic_line("Authorization: Bearer super-secret"), + "[redacted sensitive diagnostic line]" + ); + assert_eq!( + sanitize_diagnostic_line("API_KEY=should-not-leak"), + "[redacted sensitive diagnostic line]" + ); + assert_eq!( + sanitize_diagnostic_line("[session] Quarterly planning"), + "[redacted sensitive diagnostic line]" + ); + assert_eq!( + sanitize_diagnostic_line("restored memory entry: personal note"), + "[redacted sensitive diagnostic line]" + ); + assert!(sanitize_diagnostic_line(&"x".repeat(4096)).len() <= MAX_DIAGNOSTIC_LINE_BYTES); + } + + #[test] + fn recent_log_buffer_keeps_only_the_last_hundred_lines() { + let mut logs = VecDeque::new(); + for index in 0..125 { + push_bounded_log(&mut logs, &format!("line-{index}")); + } + assert_eq!(logs.len(), MAX_DIAGNOSTIC_LINES); + assert_eq!(logs.front().map(String::as_str), Some("line-25")); + assert_eq!(logs.back().map(String::as_str), Some("line-124")); + } + + #[test] + fn listener_identity_distinguishes_owned_known_and_foreign_ports() { + let project = std::env::current_dir().unwrap(); + let project_text = project.to_string_lossy(); + let owned = serde_json::json!({ + "ga_root": project_text, + "build_id": env!("GA_BUILD_ID"), + "pid": 100 + }); + let old = serde_json::json!({ + "ga_root": project_text, + "build_id": "older-build", + "pid": 101 + }); + assert_eq!( + classify_listener_identity(Some(&owned), &project_text), + ListenerIdentity::Owned + ); + assert_eq!( + classify_listener_identity(Some(&old), &project_text), + ListenerIdentity::KnownGenericAgent + ); + assert_eq!( + classify_listener_identity(None, &project_text), + ListenerIdentity::Foreign + ); + assert_eq!( + classify_listener_identity(Some(&serde_json::json!({"status": "ok"})), &project_text), + ListenerIdentity::Foreign + ); + } + + #[test] + fn bridge_identity_is_bounded_and_only_keeps_allowlisted_fields() { + let normalized = normalize_bridge_identity(serde_json::json!({ + "ga_root": "/tmp/GenericAgent", + "build_id": "build-1", + "pid": 42, + "authorization": "must-not-survive" + })) + .unwrap(); + assert_eq!( + normalized.get("ga_root").and_then(|value| value.as_str()), + Some("/tmp/GenericAgent") + ); + assert_eq!( + normalized.get("build_id").and_then(|value| value.as_str()), + Some("build-1") + ); + assert_eq!( + normalized.get("pid").and_then(|value| value.as_u64()), + Some(42) + ); + assert!(normalized.get("authorization").is_none()); + + assert!(normalize_bridge_identity(serde_json::json!({ + "ga_root": "x".repeat(MAX_IDENTITY_PATH_BYTES + 1), + "build_id": "build-1", + "pid": 42 + })) + .is_none()); + assert!(normalize_bridge_identity(serde_json::json!({ + "ga_root": "/tmp/GenericAgent", + "build_id": "x".repeat(MAX_IDENTITY_BUILD_BYTES + 1), + "pid": 42 + })) + .is_none()); + } + + #[test] + fn breakaway_fallback_is_limited_to_access_denied() { + assert!(should_retry_without_breakaway(Some(5))); + assert!(!should_retry_without_breakaway(Some(2))); + assert!(!should_retry_without_breakaway(None)); + } + + #[test] + fn python_validation_rejects_an_unresolvable_explicit_path() { + let current_exe = std::env::current_exe().unwrap(); + assert!(python_interpreter_resolves(¤t_exe.to_string_lossy())); + assert!(!python_interpreter_resolves( + "/definitely/missing/genericagent-python" + )); + } + + #[test] + fn bridge_endpoint_uses_defaults_and_validates_overrides() { + let default = bridge_endpoint_from_values(None, None).unwrap(); + assert_eq!(default.host, "127.0.0.1"); + assert_eq!(default.port, 14168); + assert_eq!(default.socket_addr(), "127.0.0.1:14168"); + + let custom = bridge_endpoint_from_values(Some("localhost"), Some("24168")).unwrap(); + assert_eq!(custom.host, "localhost"); + assert_eq!(custom.port, 24168); + + assert!(bridge_endpoint_from_values(Some("0.0.0.0"), Some("24168")).is_err()); + assert!(bridge_endpoint_from_values(Some("127.0.0.1"), Some("0")).is_err()); + assert!(bridge_endpoint_from_values(Some("127.0.0.1"), Some("bad")).is_err()); + } + + #[test] + fn main_ui_url_keeps_the_platform_asset_origin() { + let windows = main_ui_url_from_current( + tauri::Url::parse("http://tauri.localhost/loading.html?phase=ready#status").unwrap(), + ) + .unwrap(); + assert_eq!(windows.as_str(), "http://tauri.localhost/index.html"); + + let macos = + main_ui_url_from_current(tauri::Url::parse("tauri://localhost/loading.html").unwrap()) + .unwrap(); + assert_eq!(macos.as_str(), "tauri://localhost/index.html"); + + let dev = main_ui_url_from_current( + tauri::Url::parse("http://localhost:5173/loading.html").unwrap(), + ) + .unwrap(); + assert_eq!(dev.as_str(), "http://localhost:5173/index.html"); + + let current = tauri::Url::parse("tauri://localhost/index.html").unwrap(); + assert_eq!(main_ui_url_from_current(current.clone()).unwrap(), current); + } + + #[test] + fn main_ui_url_rejects_non_hierarchical_urls() { + let data_url = tauri::Url::parse("data:text/plain,loading").unwrap(); + assert!(main_ui_url_from_current(data_url).is_err()); + } + + #[test] + fn explicit_e2e_settings_path_wins_over_platform_home_resolution() { + let resolved = resolve_settings_path( + Some(PathBuf::from("C:\\Users\\runneradmin")), + Some("C:\\sandbox\\home\\.ga_desktop_settings.json"), + ); + assert_eq!( + resolved, + PathBuf::from("C:\\sandbox\\home\\.ga_desktop_settings.json") + ); + + assert_eq!( + resolve_settings_path(Some(PathBuf::from("/home/user")), None), + PathBuf::from("/home/user/.ga_desktop_settings.json") + ); + } + + #[test] + fn runtime_move_never_deletes_the_bundle_or_an_in_place_source() { + let bundled = PathBuf::from("/bundle/runtime/app"); + let external = PathBuf::from("/data/GenericAgent"); + let destination = PathBuf::from("/moved/GenericAgent"); + + assert!(!should_remove_source_after_switch( + &bundled, + &destination, + Some(&bundled), + )); + assert!(!should_remove_source_after_switch( + &external, + &external, + Some(&bundled), + )); + assert!(should_remove_source_after_switch( + &external, + &destination, + Some(&bundled), + )); + } +} diff --git a/frontends/desktop/src-tauri/tauri.conf.json b/frontends/desktop/src-tauri/tauri.conf.json index 6db15a9ee..e0b151a1d 100644 --- a/frontends/desktop/src-tauri/tauri.conf.json +++ b/frontends/desktop/src-tauri/tauri.conf.json @@ -1,28 +1,35 @@ { "productName": "GenericAgent", - "version": "0.1.8", + "version": "0.2.0", "identifier": "com.genericagent.app", "build": { - "frontendDist": "../static" + "beforeBuildCommand": "npm run build", + "beforeDevCommand": "npm run dev", + "frontendDist": "../dist", + "devUrl": "http://localhost:5173" }, "app": { "withGlobalTauri": true, "security": { - "csp": null + "csp": null, + "capabilities": ["default"] }, "windows": [ { - "title": "GenericAgent", + "title": "", "label": "main", "width": 1280, "height": 800, "resizable": true, "maximized": false, "visible": false, + "titleBarStyle": "Overlay", + "trafficLightPosition": { "x": 13, "y": 22 }, + "dragDropEnabled": false, "url": "loading.html" }, { - "title": "GenericAgent — Setup", + "title": "", "label": "setup", "width": 600, "height": 580, @@ -36,6 +43,22 @@ "bundle": { "active": true, "targets": ["nsis", "dmg"], - "icon": ["icons/icon.ico", "icons/icon.png", "icons/32x32.png", "icons/128x128.png", "icons/128x128@2x.png"] + "icon": ["icons/icon.ico", "icons/icon.png", "icons/32x32.png", "icons/128x128.png", "icons/128x128@2x.png"], + "macOS": { + "dmg": { + "windowSize": { + "width": 540, + "height": 380 + }, + "appPosition": { + "x": 140, + "y": 200 + }, + "applicationFolderPosition": { + "x": 400, + "y": 200 + } + } + } } } diff --git a/frontends/desktop/src/App.tsx b/frontends/desktop/src/App.tsx new file mode 100644 index 000000000..88381b58f --- /dev/null +++ b/frontends/desktop/src/App.tsx @@ -0,0 +1,27 @@ +import { useEffect } from 'react'; +import { LocaleProvider } from '@douyinfe/semi-ui'; +import zh_CN from '@douyinfe/semi-ui/lib/es/locale/source/zh_CN'; +import en_US from '@douyinfe/semi-ui/lib/es/locale/source/en_US'; +import { useSettingsStore } from './stores/settings'; +import { AppLayout } from './components/layout/AppLayout'; +import { NotificationStack } from './components/layout/NotificationStack'; +import { SettingsModal } from './components/settings/SettingsModal'; + +const SEMI_LOCALES = { zh: zh_CN, en: en_US }; + +export function App() { + const lang = useSettingsStore((s) => s.lang); + const loadFromBridge = useSettingsStore((s) => s.loadFromBridge); + + useEffect(() => { + loadFromBridge(); + }, [loadFromBridge]); + + return ( + + + + + + ); +} diff --git a/frontends/desktop/src/assets/channels/dingtalk.svg b/frontends/desktop/src/assets/channels/dingtalk.svg new file mode 100644 index 000000000..0233b2765 --- /dev/null +++ b/frontends/desktop/src/assets/channels/dingtalk.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontends/desktop/src/assets/channels/discord.svg b/frontends/desktop/src/assets/channels/discord.svg new file mode 100644 index 000000000..9d7796b8a --- /dev/null +++ b/frontends/desktop/src/assets/channels/discord.svg @@ -0,0 +1 @@ +Discord \ No newline at end of file diff --git a/frontends/desktop/src/assets/channels/feishu.svg b/frontends/desktop/src/assets/channels/feishu.svg new file mode 100644 index 000000000..7afdb94f9 --- /dev/null +++ b/frontends/desktop/src/assets/channels/feishu.svg @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file diff --git a/frontends/desktop/src/assets/channels/qq.svg b/frontends/desktop/src/assets/channels/qq.svg new file mode 100644 index 000000000..fc6922dd4 --- /dev/null +++ b/frontends/desktop/src/assets/channels/qq.svg @@ -0,0 +1 @@ +Tencent QQ \ No newline at end of file diff --git a/frontends/desktop/src/assets/channels/telegram.svg b/frontends/desktop/src/assets/channels/telegram.svg new file mode 100644 index 000000000..c46b0ed70 --- /dev/null +++ b/frontends/desktop/src/assets/channels/telegram.svg @@ -0,0 +1 @@ +Telegram \ No newline at end of file diff --git a/frontends/desktop/src/assets/channels/wechat.svg b/frontends/desktop/src/assets/channels/wechat.svg new file mode 100644 index 000000000..c3eb6c4a6 --- /dev/null +++ b/frontends/desktop/src/assets/channels/wechat.svg @@ -0,0 +1 @@ +WeChat \ No newline at end of file diff --git a/frontends/desktop/src/assets/channels/wecom.svg b/frontends/desktop/src/assets/channels/wecom.svg new file mode 100644 index 000000000..d22e115b4 --- /dev/null +++ b/frontends/desktop/src/assets/channels/wecom.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontends/desktop/src/assets/generic-agent-black.svg b/frontends/desktop/src/assets/generic-agent-black.svg new file mode 100644 index 000000000..0f5890473 --- /dev/null +++ b/frontends/desktop/src/assets/generic-agent-black.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontends/desktop/src/assets/generic-agent-white.svg b/frontends/desktop/src/assets/generic-agent-white.svg new file mode 100644 index 000000000..1c4fcc055 --- /dev/null +++ b/frontends/desktop/src/assets/generic-agent-white.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontends/desktop/src/components/chat/ChatView.tsx b/frontends/desktop/src/components/chat/ChatView.tsx new file mode 100644 index 000000000..6fe356dd2 --- /dev/null +++ b/frontends/desktop/src/components/chat/ChatView.tsx @@ -0,0 +1,55 @@ +import { useCallback, useRef } from 'react'; +import { useChatStore, type SendOptions } from '../../stores/chat'; +import { useBridgeStatus } from '../../hooks/useBridgeStatus'; +import { useI18n } from '../../i18n'; +import { Thread } from './Thread'; +import { Composer } from './Composer'; +import { EmptyState } from './EmptyState'; +import type { SkillDef } from './Composer/skills'; +import type { RichEditorHandle } from './Composer/RichEditorInput'; +import './chatView.css'; + +export function ChatView() { + const { t } = useI18n(); + const bridgeStatus = useBridgeStatus(); + const status = useChatStore((s) => s.status); + const messages = useChatStore((s) => s.messages); + const sendMessage = useChatStore((s) => s.sendMessage); + const cancel = useChatStore((s) => s.cancel); + const composerEditorRef = useRef(null); + + const handleSend = useCallback( + (text: string, opts?: SendOptions) => { + if (text || opts) sendMessage(text, opts); + }, + [sendMessage], + ); + + const handlePresetClick = useCallback((skill: SkillDef) => { + composerEditorRef.current?.setSkillChip(skill.id, skill.prompt); + composerEditorRef.current?.focus(); + }, []); + + const isEmpty = messages.length === 0 && status === 'idle'; + const showOffline = isEmpty && bridgeStatus !== 'ready'; + + return ( +
    + {showOffline ? ( +
    + {bridgeStatus === 'connecting' ? t('bridge.connecting') : t('bridge.offline')} +
    + ) : isEmpty ? ( + + ) : ( + + )} + +
    + ); +} diff --git a/frontends/desktop/src/components/chat/Composer/AtRefPopover.tsx b/frontends/desktop/src/components/chat/Composer/AtRefPopover.tsx new file mode 100644 index 000000000..0d8db16c9 --- /dev/null +++ b/frontends/desktop/src/components/chat/Composer/AtRefPopover.tsx @@ -0,0 +1,110 @@ +import { useRef, useEffect, useState, useCallback } from 'react'; + +interface Props { + visible: boolean; + query: string; + onConfirm: (kind: string, value: string) => void; + onClose: () => void; +} + +const KINDS = [ + { id: 'file', label: 'file' }, + { id: 'url', label: 'url' }, + { id: 'image', label: 'image' }, +]; + +export function AtRefPopover({ visible, query, onConfirm, onClose }: Props) { + const inputRef = useRef(null); + const [kind, setKind] = useState('file'); + const [value, setValue] = useState(''); + + useEffect(() => { + if (visible) { + setValue(query); + setKind('file'); + setTimeout(() => inputRef.current?.focus(), 0); + } + }, [visible, query]); + + useEffect(() => { + if (!visible) return; + function onKey(e: KeyboardEvent) { + if (e.key === 'Escape') { + e.preventDefault(); + e.stopPropagation(); + onClose(); + } + } + document.addEventListener('keydown', onKey, true); + return () => document.removeEventListener('keydown', onKey, true); + }, [visible, onClose]); + + const handleSubmit = useCallback((e: React.FormEvent) => { + e.preventDefault(); + const trimmed = value.trim(); + if (!trimmed) return; + onConfirm(kind, trimmed); + }, [kind, value, onConfirm]); + + if (!visible) return null; + + return ( +
    +
    +
    + {KINDS.map((k) => ( + + ))} +
    + setValue(e.target.value)} + placeholder={kind === 'url' ? 'https://...' : 'path/to/file'} + /> + +
    +
    + ); +} + +function KindIcon({ kind }: { kind: string }) { + switch (kind) { + case 'file': + return ( + + + + + ); + case 'url': + return ( + + + + ); + case 'image': + return ( + + + + + + ); + default: + return null; + } +} diff --git a/frontends/desktop/src/components/chat/Composer/AttachmentStrip.tsx b/frontends/desktop/src/components/chat/Composer/AttachmentStrip.tsx new file mode 100644 index 000000000..a1c522c92 --- /dev/null +++ b/frontends/desktop/src/components/chat/Composer/AttachmentStrip.tsx @@ -0,0 +1,125 @@ +import { useCallback } from 'react'; + +export type AttachmentStatus = 'uploading' | 'ready' | 'error'; + +export interface AttachmentFile { + id: string; + name: string; + size: number; + type: 'image' | 'file' | 'url'; + status: AttachmentStatus; + preview?: string; + path?: string; + url?: string; + errorMsg?: string; +} + +interface Props { + files: AttachmentFile[]; + onRemove: (id: string) => void; + onRetry?: (id: string) => void; +} + +const FILE_ICONS: Record = { + pdf: { char: '📄', color: '#E53E3E' }, + doc: { char: '📝', color: '#2B6CB0' }, + docx: { char: '📝', color: '#2B6CB0' }, + xls: { char: '📊', color: '#276749' }, + xlsx: { char: '📊', color: '#276749' }, + csv: { char: '📊', color: '#276749' }, + zip: { char: '📦', color: '#744210' }, + rar: { char: '📦', color: '#744210' }, + py: { char: '🐍', color: '#3182CE' }, + js: { char: '⚡', color: '#D69E2E' }, + ts: { char: '⚡', color: '#3182CE' }, + md: { char: '📋', color: '#4A5568' }, + txt: { char: '📋', color: '#4A5568' }, + json: { char: '{ }', color: '#6366F1' }, +}; + +function getFileIcon(name: string): { char: string; color: string } { + const ext = name.split('.').pop()?.toLowerCase() || ''; + return FILE_ICONS[ext] || { char: '📎', color: 'var(--semi-color-text-3, #8f959e)' }; +} + +function fmtSize(bytes: number): string { + if (!bytes || bytes < 0) return ''; + if (bytes < 1024) return bytes + ' B'; + if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB'; + return (bytes / 1048576).toFixed(1) + ' MB'; +} + +function hostname(url: string): string { + try { return new URL(url).hostname; } + catch { return url.slice(0, 30); } +} + +export function AttachmentStrip({ files, onRemove, onRetry }: Props) { + const handleRemove = useCallback((id: string) => (e: React.MouseEvent) => { + e.stopPropagation(); + onRemove(id); + }, [onRemove]); + + const handleRetry = useCallback((id: string) => (e: React.MouseEvent) => { + e.stopPropagation(); + onRetry?.(id); + }, [onRetry]); + + if (files.length === 0) return null; + + return ( +
    + {files.map((f) => { + if (f.type === 'image' && f.preview) { + return ( +
    + {f.name} + {f.status === 'uploading' && } + {f.status === 'error' && ( + + )} + {f.status !== 'uploading' && ( + + )} +
    + ); + } + if (f.type === 'url') { + return ( +
    + 🔗 + + {f.url ? hostname(f.url) : f.name} + + +
    + ); + } + const icon = getFileIcon(f.name); + return ( +
    + {f.status === 'uploading' ? ( + + ) : f.status === 'error' ? ( + + ) : ( + {icon.char} + )} + + {f.name} + {f.status === 'error' && f.errorMsg && ( + {f.errorMsg} + )} + {f.status !== 'error' && f.size > 0 && ( + {fmtSize(f.size)} + )} + + {f.status !== 'uploading' && ( + + )} +
    + ); + })} +
    + ); +} diff --git a/frontends/desktop/src/components/chat/Composer/CompletionDrawer.tsx b/frontends/desktop/src/components/chat/Composer/CompletionDrawer.tsx new file mode 100644 index 000000000..33223f4fe --- /dev/null +++ b/frontends/desktop/src/components/chat/Composer/CompletionDrawer.tsx @@ -0,0 +1,90 @@ +import { useRef, useEffect, useState } from 'react'; +import { useSettingsStore } from '../../../stores/settings'; +import { BUILTIN_SKILLS, type SkillDef } from './skills'; + +interface Props { + visible: boolean; + query: string; + onSelect: (id: string, prompt: string) => void; + onClose: () => void; +} + +function getCustomCompletions(): SkillDef[] { + try { + const raw = localStorage.getItem('ga_custom_presets'); + if (!raw) return []; + return JSON.parse(raw); + } catch { + return []; + } +} + +export function CompletionDrawer({ visible, query, onSelect, onClose }: Props) { + const lang = useSettingsStore((s) => s.lang); + const [focusIdx, setFocusIdx] = useState(0); + const panelRef = useRef(null); + + const customs = getCustomCompletions(); + const allItems = [...BUILTIN_SKILLS, ...customs]; + + const filtered = query + ? allItems.filter((item) => + item.id.startsWith(query.toLowerCase()) || + item.title.toLowerCase().includes(query.toLowerCase()) + ) + : allItems; + + useEffect(() => { + setFocusIdx(0); + }, [query]); + + useEffect(() => { + if (!visible) return; + function onKey(e: KeyboardEvent) { + if (e.key === 'ArrowDown') { + e.preventDefault(); + setFocusIdx((v) => Math.min(v + 1, filtered.length - 1)); + } else if (e.key === 'ArrowUp') { + e.preventDefault(); + setFocusIdx((v) => Math.max(v - 1, 0)); + } else if (e.key === 'Enter') { + e.preventDefault(); + if (filtered[focusIdx]) { + onSelect(filtered[focusIdx].id, filtered[focusIdx].prompt); + } + } else if (e.key === 'Escape') { + e.preventDefault(); + onClose(); + } + } + document.addEventListener('keydown', onKey, true); + return () => document.removeEventListener('keydown', onKey, true); + }, [visible, focusIdx, filtered, onSelect, onClose]); + + useEffect(() => { + if (!panelRef.current) return; + const focused = panelRef.current.querySelector('[data-focused]'); + focused?.scrollIntoView({ block: 'nearest' }); + }, [focusIdx]); + + if (!visible || filtered.length === 0) return null; + + return ( +
    + {filtered.map((item, i) => ( + + ))} +
    + ); +} diff --git a/frontends/desktop/src/components/chat/Composer/ContextMenu.tsx b/frontends/desktop/src/components/chat/Composer/ContextMenu.tsx new file mode 100644 index 000000000..f31bc36ab --- /dev/null +++ b/frontends/desktop/src/components/chat/Composer/ContextMenu.tsx @@ -0,0 +1,120 @@ +import { useState, useRef, useEffect, useCallback } from 'react'; +import { useSettingsStore } from '../../../stores/settings'; + +interface Props { + onUploadFile: () => void; + onUploadImage: () => void; + onPasteImage: () => void; +} + +const LABELS = { + title: { zh: '附加', en: 'Attach' }, + file: { zh: '文件…', en: 'File…' }, + image: { zh: '图片…', en: 'Image…' }, + paste: { zh: '粘贴图片', en: 'Paste image' }, + hint: { zh: '提示:输入 @ 以内联引用文件', en: 'Tip: type @ to reference files inline' }, +}; + +export function ContextMenu({ onUploadFile, onUploadImage, onPasteImage }: Props) { + const [open, setOpen] = useState(false); + const menuRef = useRef(null); + const btnRef = useRef(null); + const lang = useSettingsStore((s) => s.lang); + + const t = (key: keyof typeof LABELS) => LABELS[key][lang] || LABELS[key].en; + + const toggle = useCallback(() => setOpen((v) => !v), []); + + useEffect(() => { + if (!open) return; + function onClickOutside(e: MouseEvent) { + if (menuRef.current && !menuRef.current.contains(e.target as Node) && + btnRef.current && !btnRef.current.contains(e.target as Node)) { + setOpen(false); + } + } + function onEsc(e: KeyboardEvent) { + if (e.key === 'Escape') setOpen(false); + } + document.addEventListener('mousedown', onClickOutside); + document.addEventListener('keydown', onEsc); + return () => { + document.removeEventListener('mousedown', onClickOutside); + document.removeEventListener('keydown', onEsc); + }; + }, [open]); + + const act = useCallback((fn: () => void) => () => { + fn(); + setOpen(false); + }, []); + + return ( +
    + + + {open && ( +
    +
    {t('title')}
    + + + +
    {t('hint')}
    +
    + )} +
    + ); +} + +function PlusIcon() { + return ( + + + + ); +} + +function FileIcon() { + return ( + + + + + ); +} + +function ImageIcon() { + return ( + + + + + + ); +} + +function ClipboardIcon() { + return ( + + + + + ); +} diff --git a/frontends/desktop/src/components/chat/Composer/ModelSelector.tsx b/frontends/desktop/src/components/chat/Composer/ModelSelector.tsx new file mode 100644 index 000000000..ad6c0a46a --- /dev/null +++ b/frontends/desktop/src/components/chat/Composer/ModelSelector.tsx @@ -0,0 +1,415 @@ +import { useState, useRef, useEffect, useCallback, useMemo } from 'react'; +import { useSettingsStore } from '../../../stores/settings'; +import { useChatStore } from '../../../stores/chat'; +import { useI18n } from '../../../i18n'; +import type { ModelProfile } from '../../../services/bridge'; +import { getProviderIcon, providerFromModel } from '../../../data/provider-icons'; + +const PROVIDER_COLORS: Record = { + deepseek: '#4D6BFE', + dashscope: '#615CED', + qwen: '#615CED', + openai: '#10A37F', + anthropic: '#D97706', + openrouter: '#6366F1', + google: '#4285F4', + moonshot: '#7C3AED', + kimi: '#7C3AED', + doubao: '#006EFF', + minimax: '#F23F5D', + zhipu: '#3859FF', + stepfun: '#005AFF', +}; + +function providerColor(apibase: string, model?: string): string { + const lower = (apibase || '').toLowerCase(); + for (const [key, color] of Object.entries(PROVIDER_COLORS)) { + if (lower.includes(key)) return color; + } + const fromModel = providerFromModel(model || ''); + if (fromModel && PROVIDER_COLORS[fromModel]) return PROVIDER_COLORS[fromModel]; + return 'var(--semi-color-text-3, #8f959e)'; +} + +function providerName(apibase: string, model?: string): string { + const lower = (apibase || '').toLowerCase(); + if (lower.includes('deepseek')) return 'DEEPSEEK'; + if (lower.includes('dashscope') || lower.includes('qwen')) return 'QWEN'; + if (lower.includes('anthropic')) return 'ANTHROPIC'; + if (lower.includes('openai')) return 'OPENAI'; + if (lower.includes('openrouter')) return 'OPENROUTER'; + if (lower.includes('google')) return 'GOOGLE'; + if (lower.includes('moonshot')) return 'KIMI'; + if (lower.includes('volces') || lower.includes('volcengine')) return 'DOUBAO'; + if (lower.includes('minimax')) return 'MINIMAX'; + if (lower.includes('bigmodel') || lower.includes('zhipu')) return 'ZHIPU'; + if (lower.includes('stepfun')) return 'STEPFUN'; + const fromModel = providerFromModel(model || ''); + if (fromModel) return fromModel.toUpperCase(); + return 'OTHER'; +} + +function profileLabel(name: string): string { + const s = String(name || ''); + const i = s.indexOf('/'); + return (i >= 0 ? s.slice(i + 1) : s).trim(); +} + +function modelShortName(profile: ModelProfile): string { + const m = profile.model || ''; + const slash = m.lastIndexOf('/'); + return slash >= 0 ? m.slice(slash + 1) : m || profileLabel(profile.name); +} + +export function formatModelSelectionLabel( + profiles: ModelProfile[], + selectedNo: number, + runningNo: number | null | undefined, + isRunning: boolean, +): string { + const selected = profiles[selectedNo]; + const selectedLabel = selected ? modelShortName(selected) : ''; + if (!isRunning || runningNo == null || runningNo === selectedNo) return selectedLabel; + const running = profiles[runningNo]; + return running ? `${modelShortName(running)} → ${selectedLabel}` : selectedLabel; +} + +function ProviderIcon({ apibase, model, size = 14 }: { apibase: string; model?: string; size?: number }) { + const providerKey = providerFromModel(model || '') || providerKeyFromApibase(apibase); + const iconDef = providerKey ? getProviderIcon(providerKey) : undefined; + + if (iconDef?.Component) { + const Comp = iconDef.Component; + return ; + } + return ; +} + +function providerKeyFromApibase(apibase: string): string | null { + const lower = (apibase || '').toLowerCase(); + if (lower.includes('deepseek')) return 'deepseek'; + if (lower.includes('dashscope') || lower.includes('qwen')) return 'qwen'; + if (lower.includes('anthropic')) return 'anthropic'; + if (lower.includes('openai')) return 'openai'; + if (lower.includes('openrouter')) return 'openrouter'; + if (lower.includes('google')) return 'google'; + if (lower.includes('moonshot')) return 'moonshot'; + if (lower.includes('volces') || lower.includes('volcengine')) return 'doubao'; + if (lower.includes('minimax')) return 'minimax'; + if (lower.includes('bigmodel') || lower.includes('zhipu')) return 'zhipu'; + if (lower.includes('stepfun')) return 'stepfun'; + return null; +} + +interface GroupedProfiles { + provider: string; + color: string; + items: { profile: ModelProfile; idx: number }[]; +} + +function groupByProvider(profiles: ModelProfile[]): { groups: GroupedProfiles[]; mixins: { profile: ModelProfile; idx: number }[] } { + const mixins: { profile: ModelProfile; idx: number }[] = []; + const map = new Map(); + + profiles.forEach((p, idx) => { + if (p.kind === 'mixin') { + mixins.push({ profile: p, idx }); + return; + } + const provider = providerName(p.apibase, p.model); + if (!map.has(provider)) { + map.set(provider, { provider, color: providerColor(p.apibase, p.model), items: [] }); + } + map.get(provider)!.items.push({ profile: p, idx }); + }); + + return { groups: Array.from(map.values()), mixins }; +} + +interface ModelSelectorProps { + selectedNo?: number; + runningNo?: number | null; + isRunning?: boolean; + onSelect?: (no: number) => void | Promise; +} + +export function ModelSelector({ + selectedNo: controlledSelectedNo, + runningNo: controlledRunningNo, + isRunning: controlledIsRunning, + onSelect, +}: ModelSelectorProps = {}) { + const [open, setOpen] = useState(false); + const [search, setSearch] = useState(''); + const [expandedMixin, setExpandedMixin] = useState(null); + const [isCompact, setIsCompact] = useState(false); + const menuRef = useRef(null); + const btnRef = useRef(null); + const wrapRef = useRef(null); + const searchRef = useRef(null); + const { lang, t } = useI18n(); + + const profiles = useSettingsStore((s) => s.modelProfiles); + const defaultModelNo = useSettingsStore((s) => s.defaultModelNo); + const liveModel = useSettingsStore((s) => s.liveModel); + const sessionModelNo = useChatStore((s) => s.sessionModelNo); + const sessionStatus = useChatStore((s) => s.status); + const selectSessionModel = useChatStore((s) => s.selectSessionModel); + + const selectedNo = controlledSelectedNo ?? sessionModelNo ?? defaultModelNo; + const runningNo = controlledRunningNo !== undefined + ? controlledRunningNo + : liveModel?.runningLlmNo; + const isRunning = controlledIsRunning ?? sessionStatus === 'running'; + const isLoading = profiles.length === 0; + const currentProfile = profiles[selectedNo]; + + const chipLabel = useMemo(() => { + if (!currentProfile) return t('model.menuLabel'); + if (isRunning && runningNo != null && runningNo !== selectedNo) { + return formatModelSelectionLabel(profiles, selectedNo, runningNo, true); + } + if (currentProfile.kind === 'mixin') { + return t('model.aggregationShort'); + } + return modelShortName(currentProfile); + }, [currentProfile, isRunning, profiles, runningNo, selectedNo, t]); + + const { groups, mixins } = useMemo(() => groupByProvider(profiles), [profiles]); + + const filteredGroups = useMemo(() => { + if (!search.trim()) return groups; + const q = search.toLowerCase(); + return groups + .map((g) => ({ + ...g, + items: g.items.filter( + ({ profile: p }) => + modelShortName(p).toLowerCase().includes(q) || + (p.model || '').toLowerCase().includes(q) || + g.provider.toLowerCase().includes(q), + ), + })) + .filter((g) => g.items.length > 0); + }, [groups, search]); + + const toggle = useCallback(() => { + setOpen((v) => { + if (!v) setSearch(''); + return !v; + }); + }, []); + + const handleSelect = useCallback((idx: number) => { + if (onSelect) onSelect(idx); + else selectSessionModel(idx); + setOpen(false); + }, [onSelect, selectSessionModel]); + + useEffect(() => { + if (open && searchRef.current) { + searchRef.current.focus(); + } + }, [open]); + + // Compact mode: observe toolbar width + useEffect(() => { + const toolbar = wrapRef.current?.closest('[data-slot="composer-toolbar"]') as HTMLElement | null; + if (!toolbar) return; + const observer = new ResizeObserver((entries) => { + const width = entries[0]?.contentRect?.width ?? toolbar.offsetWidth; + setIsCompact(width < 320); + }); + observer.observe(toolbar); + return () => observer.disconnect(); + }, []); + + useEffect(() => { + if (!open) return; + function onClickOutside(e: MouseEvent) { + if (menuRef.current && !menuRef.current.contains(e.target as Node) && + btnRef.current && !btnRef.current.contains(e.target as Node)) { + setOpen(false); + } + } + function onEsc(e: KeyboardEvent) { + if (e.key === 'Escape') setOpen(false); + } + document.addEventListener('mousedown', onClickOutside); + document.addEventListener('keydown', onEsc); + return () => { + document.removeEventListener('mousedown', onClickOutside); + document.removeEventListener('keydown', onEsc); + }; + }, [open]); + + useEffect(() => { + function onHotkey(e: KeyboardEvent) { + if (!(e.metaKey || e.ctrlKey)) return; + if (e.key >= '1' && e.key <= '9') { + const idx = parseInt(e.key) - 1; + if (idx < profiles.length) { + e.preventDefault(); + selectSessionModel(idx); + } + } + } + document.addEventListener('keydown', onHotkey); + return () => document.removeEventListener('keydown', onHotkey); + }, [profiles, selectSessionModel]); + + const handleOpenSettings = useCallback(() => { + setOpen(false); + useSettingsStore.getState().open(); + }, []); + + return ( +
    + + + {open && !isLoading && ( +
    + {/* Search */} +
    + + setSearch(e.target.value)} + data-slot="model-menu-search-input" + /> +
    + +
    + {/* Provider groups */} + {filteredGroups.map((group) => ( +
    +
    + + {group.provider} +
    + {group.items.map(({ profile: p, idx }) => ( + + ))} +
    + ))} + + {/* Mixin section */} + {mixins.length > 0 && ( +
    +
    + {t('model.aggregationShort').toUpperCase()} +
    + {mixins.map(({ profile: p, idx }) => { + const isExpanded = expandedMixin === idx; + const label = p.name?.trim() || t('model.aggregationShort'); + return ( +
    + + {isExpanded && p.members && ( +
    + {p.members.map((memberName) => { + const member = profiles.find((pp) => pp.name === memberName); + return ( +
    + + {member ? modelShortName(member) : String(memberName)} +
    + ); + })} + {p.members.length === 0 && ( +
    + {t('model.emptyMixin')} +
    + )} +
    + )} +
    + ); + })} +
    + )} + + {/* Empty state */} + {filteredGroups.length === 0 && mixins.length === 0 && ( +
    {t('set.noModels')}
    + )} +
    + + {/* Footer actions */} +
    + +
    +
    + )} +
    + ); +} + +function CaretIcon() { + return ( + + ); +} + +function SearchIcon() { + return ( + + ); +} diff --git a/frontends/desktop/src/components/chat/Composer/PrimaryCTA.tsx b/frontends/desktop/src/components/chat/Composer/PrimaryCTA.tsx new file mode 100644 index 000000000..a87919023 --- /dev/null +++ b/frontends/desktop/src/components/chat/Composer/PrimaryCTA.tsx @@ -0,0 +1,87 @@ +import { useCallback, useEffect } from 'react'; + +export type CTAState = 'send' | 'stop' | 'queue' | 'disabled'; + +export function computeCTAState( + isGenerating: boolean, + hasContent: boolean, + hasPendingUploads: boolean = false, +): CTAState { + if (hasPendingUploads) return 'disabled'; + if (isGenerating && hasContent) return 'queue'; + if (isGenerating) return 'stop'; + if (hasContent) return 'send'; + return 'disabled'; +} + +interface Props { + state: CTAState; + onSend: () => void; + onStop: () => void; + onQueue?: () => void; +} + +export function PrimaryCTA({ state, onSend, onStop, onQueue }: Props) { + const handleClick = useCallback(() => { + switch (state) { + case 'send': onSend(); break; + case 'stop': onStop(); break; + case 'queue': onQueue?.(); break; + } + }, [state, onSend, onStop, onQueue]); + + useEffect(() => { + if (state !== 'stop') return; + function onKey(e: KeyboardEvent) { + if (e.key === 'Escape') { + e.preventDefault(); + onStop(); + } + } + document.addEventListener('keydown', onKey); + return () => document.removeEventListener('keydown', onKey); + }, [state, onStop]); + + const label = state === 'stop' ? 'Stop generating' + : state === 'queue' ? 'Queue message' + : 'Send message'; + + return ( + + ); +} + +function SendIcon() { + return ( + + + + ); +} + +function StopIcon() { + return ( + + + + ); +} + +function QueueIcon() { + return ( + + + + ); +} diff --git a/frontends/desktop/src/components/chat/Composer/RichEditorInput.tsx b/frontends/desktop/src/components/chat/Composer/RichEditorInput.tsx new file mode 100644 index 000000000..84a858a3e --- /dev/null +++ b/frontends/desktop/src/components/chat/Composer/RichEditorInput.tsx @@ -0,0 +1,172 @@ +import { useRef, useCallback, useEffect, useImperativeHandle, forwardRef } from 'react'; +import { composerPlainText, normalizeComposerDom, replaceAllContent, insertChipWithSpace, replaceWithSkillChip } from './rich-editor'; + +export interface RichEditorHandle { + focus: () => void; + clear: () => void; + getText: () => string; + setText: (text: string) => void; + insertChip: (kind: string, value: string, label?: string) => void; + setSkillChip: (id: string, prompt: string) => void; + getElement: () => HTMLDivElement | null; +} + +interface Props { + placeholder: string; + disabled: boolean; + onInput: (plainText: string) => void; + onKeyDown: (e: React.KeyboardEvent) => void; + onSlashTrigger?: (query: string) => void; + onSlashDismiss?: () => void; + onAtTrigger?: (query: string) => void; + onAtDismiss?: () => void; + onPasteFiles?: (files: File[]) => void; +} + +export const RichEditorInput = forwardRef(function RichEditorInput( + { placeholder, disabled, onInput, onKeyDown, onSlashTrigger, onSlashDismiss, onAtTrigger, onAtDismiss, onPasteFiles }, + ref, +) { + const editorRef = useRef(null); + const isComposingRef = useRef(false); + const lastTextRef = useRef(''); + + useImperativeHandle(ref, () => ({ + focus() { + editorRef.current?.focus(); + }, + clear() { + if (editorRef.current) { + editorRef.current.textContent = ''; + lastTextRef.current = ''; + } + }, + getText() { + return editorRef.current ? composerPlainText(editorRef.current) : ''; + }, + setText(text: string) { + if (editorRef.current) { + replaceAllContent(editorRef.current, text); + lastTextRef.current = text; + onInput(text); + } + }, + insertChip(kind: string, value: string, label?: string) { + if (editorRef.current) { + editorRef.current.focus(); + insertChipWithSpace(editorRef.current, kind, value, label); + fireInput(); + } + }, + setSkillChip(id: string, prompt: string) { + if (editorRef.current) { + replaceWithSkillChip(editorRef.current, id, prompt); + fireInput(); + } + }, + getElement() { + return editorRef.current; + }, + })); + + const fireInput = useCallback(() => { + if (!editorRef.current) return; + const text = composerPlainText(editorRef.current); + lastTextRef.current = text; + onInput(text); + + // Slash trigger detection + const trimmed = text.trimStart(); + if (trimmed.startsWith('/') && !trimmed.includes('\n')) { + onSlashTrigger?.(trimmed.slice(1)); + } else { + onSlashDismiss?.(); + } + + // @ trigger detection: find last `@` not inside a chip + const atMatch = text.match(/@([^\s@]*)$/); + if (atMatch) { + onAtTrigger?.(atMatch[1]); + } else { + onAtDismiss?.(); + } + }, [onInput, onSlashTrigger, onSlashDismiss, onAtTrigger, onAtDismiss]); + + const handleInput = useCallback(() => { + if (isComposingRef.current) return; + if (editorRef.current) { + normalizeComposerDom(editorRef.current); + } + fireInput(); + }, [fireInput]); + + const handleCompositionStart = useCallback(() => { + isComposingRef.current = true; + }, []); + + const handleCompositionEnd = useCallback(() => { + isComposingRef.current = false; + handleInput(); + }, [handleInput]); + + const handleKeyDown = useCallback((e: React.KeyboardEvent) => { + if (isComposingRef.current || e.nativeEvent.isComposing || e.keyCode === 229) return; + onKeyDown(e); + }, [onKeyDown]); + + const handlePaste = useCallback((e: React.ClipboardEvent) => { + const items = e.clipboardData?.items; + if (!items) return; + + // Check for images + const imageFiles: File[] = []; + for (const item of Array.from(items)) { + if (item.type.startsWith('image/') && item.type !== 'image/svg+xml') { + const file = item.getAsFile(); + if (file) imageFiles.push(file); + } + } + if (imageFiles.length > 0) { + e.preventDefault(); + onPasteFiles?.(imageFiles); + return; + } + + // For text, paste as plain text only + const text = e.clipboardData.getData('text/plain'); + if (text) { + e.preventDefault(); + document.execCommand('insertText', false, text); + } + }, [onPasteFiles]); + + // Auto-resize via measured height + useEffect(() => { + const el = editorRef.current; + if (!el) return; + const observer = new ResizeObserver((entries) => { + const height = entries[0]?.borderBoxSize?.[0]?.blockSize ?? el.offsetHeight; + el.style.setProperty('--editor-scroll-height', `${height}px`); + }); + observer.observe(el); + return () => observer.disconnect(); + }, []); + + return ( +
    + ); +}); diff --git a/frontends/desktop/src/components/chat/Composer/SkillPanel.tsx b/frontends/desktop/src/components/chat/Composer/SkillPanel.tsx new file mode 100644 index 000000000..33f78a6a9 --- /dev/null +++ b/frontends/desktop/src/components/chat/Composer/SkillPanel.tsx @@ -0,0 +1,134 @@ +import { useState, useRef, useEffect, useCallback } from 'react'; +import { useSettingsStore } from '../../../stores/settings'; +import { BUILTIN_SKILLS, type SkillDef } from './skills'; + +const CUSTOM_PRESETS_KEY = 'ga_custom_presets'; + +function getCustomPresets(): SkillDef[] { + try { + const raw = localStorage.getItem(CUSTOM_PRESETS_KEY); + if (!raw) return []; + return JSON.parse(raw); + } catch { + return []; + } +} + +const LABELS = { + hint: { zh: '提示:输入 / 以内联调用技能', en: 'Tip: type / to invoke a skill inline' }, +}; + + +interface Props { + onSelect: (id: string, prompt: string) => void; +} + +export function SkillPanel({ onSelect }: Props) { + const [open, setOpen] = useState(false); + const [focusIdx, setFocusIdx] = useState(-1); + const panelRef = useRef(null); + const btnRef = useRef(null); + const lang = useSettingsStore((s) => s.lang); + + const customs = getCustomPresets(); + const allItems = [...BUILTIN_SKILLS, ...customs]; + + const toggle = useCallback(() => { + setOpen((v) => !v); + setFocusIdx(-1); + }, []); + + const handleSelect = useCallback((id: string, prompt: string) => { + onSelect(id, prompt); + setOpen(false); + }, [onSelect]); + + useEffect(() => { + if (!open) return; + function onClickOutside(e: MouseEvent) { + if (panelRef.current && !panelRef.current.contains(e.target as Node) && + btnRef.current && !btnRef.current.contains(e.target as Node)) { + setOpen(false); + } + } + function onKeydown(e: KeyboardEvent) { + if (e.key === 'Escape') { setOpen(false); return; } + if (e.key === 'ArrowDown') { e.preventDefault(); setFocusIdx((v) => Math.min(v + 1, allItems.length - 1)); } + if (e.key === 'ArrowUp') { e.preventDefault(); setFocusIdx((v) => Math.max(v - 1, 0)); } + if (e.key === 'Enter' && focusIdx >= 0 && focusIdx < allItems.length) { + e.preventDefault(); + handleSelect(allItems[focusIdx].id, allItems[focusIdx].prompt); + } + } + document.addEventListener('mousedown', onClickOutside); + document.addEventListener('keydown', onKeydown); + return () => { + document.removeEventListener('mousedown', onClickOutside); + document.removeEventListener('keydown', onKeydown); + }; + }, [open, focusIdx, allItems, handleSelect]); + + return ( +
    + + + {open && ( +
    +
    +
    Presets
    + {BUILTIN_SKILLS.map((s, i) => ( + + ))} +
    + {customs.length > 0 && ( +
    +
    Custom
    + {customs.map((s, i) => ( + + ))} +
    + )} +
    {LABELS.hint[lang] || LABELS.hint.en}
    +
    + )} +
    + ); +} + +function SkillIcon() { + return ( + + ); +} diff --git a/frontends/desktop/src/components/chat/Composer/StatusStack.tsx b/frontends/desktop/src/components/chat/Composer/StatusStack.tsx new file mode 100644 index 000000000..b6822ae7f --- /dev/null +++ b/frontends/desktop/src/components/chat/Composer/StatusStack.tsx @@ -0,0 +1,40 @@ +import { useChatStore } from '../../../stores/chat'; +import { useSettingsStore } from '../../../stores/settings'; + +const LABELS = { + thinking: { zh: '思考中…', en: 'Thinking…' }, + queued: { zh: '排队中', en: 'Queued' }, +}; + +export function StatusStack() { + const isGenerating = useChatStore((s) => s.status === 'running'); + const queue = useChatStore((s) => s.pendingQueue); + const cancelQueued = useChatStore((s) => s.cancelQueued); + const lang = useSettingsStore((s) => s.lang); + + if (!isGenerating && queue.length === 0) return null; + + const t = (key: keyof typeof LABELS) => LABELS[key][lang] || LABELS[key].en; + + return ( +
    + {isGenerating && ( +
    + + {t('thinking')} +
    + )} + {queue.map((item, i) => ( +
    + #{i + 1} + {item.text.slice(0, 40)}{item.text.length > 40 ? '…' : ''} + +
    + ))} +
    + ); +} diff --git a/frontends/desktop/src/components/chat/Composer/composer.css b/frontends/desktop/src/components/chat/Composer/composer.css new file mode 100644 index 000000000..0b010974e --- /dev/null +++ b/frontends/desktop/src/components/chat/Composer/composer.css @@ -0,0 +1,1056 @@ +/* ═══════════════════════════════════════════════ + Composer — Enhanced with Model Selector, Attachments, Skills + ═══════════════════════════════════════════════ */ + +:root { + --composer-width: 48.75rem; + --composer-control-size: 1.75rem; + --composer-surface-pad-x: 0.75rem; + --composer-surface-pad-y: 0.5rem; + --composer-input-min-height: 1.625rem; + --composer-input-max-height: 9.375rem; + --composer-fallback-height: 2.75rem; + --composer-measured-height: 62px; +} + +/* Root — absolutely positioned at bottom center */ +[data-slot="composer-root"] { + position: absolute; + bottom: 0; + left: 50%; + transform: translateX(-50%); + z-index: 30; + width: min(var(--composer-width), calc(100% - 2rem)); + padding-top: 0.5rem; + padding-bottom: 1rem; +} + +/* Opaque backdrop */ +[data-slot="composer-root"]::before { + content: ''; + position: absolute; + inset: 0.5rem 0 0 0; + background: var(--background); + border-radius: var(--composer-border-radius, 1rem) var(--composer-border-radius, 1rem) 0 0; + z-index: -1; +} + +/* Surface — glass shell */ +[data-slot="composer-surface"] { + display: flex; + flex-direction: column; + gap: 0; + padding: var(--composer-surface-pad-y) var(--composer-surface-pad-x); + border-radius: 0.75rem; + border: 1px solid var(--semi-color-border, #e0e0e0); + background: color-mix(in srgb, var(--semi-color-bg-0, #fff) 85%, transparent); + backdrop-filter: blur(0.75rem) saturate(1.12); + -webkit-backdrop-filter: blur(0.75rem) saturate(1.12); + box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04); + transition: border-color 0.15s; +} + +[data-slot="composer-surface"]:focus-within { + border-color: var(--semi-color-primary, #3370ff); + box-shadow: 0 0 0 2px color-mix(in srgb, var(--semi-color-primary, #3370ff) 15%, transparent); +} + +/* Input row */ +[data-slot="composer-input-row"] { + display: flex; + align-items: flex-end; +} + +/* Rich Editor (contentEditable div) */ +[data-slot="composer-rich-input"] { + flex: 1; + min-height: var(--composer-input-min-height); + max-height: var(--composer-input-max-height); + padding: 0.375rem 0.25rem; + border: none; + background: transparent; + font-size: 0.8125rem; + line-height: 1.5; + color: var(--semi-color-text-0, #1c1f23); + outline: none; + font-family: inherit; + overflow-y: auto; + white-space: pre-wrap; + word-wrap: break-word; +} + +[data-slot="composer-rich-input"]:empty::before { + content: attr(data-placeholder); + color: var(--ui-text-secondary); + pointer-events: none; +} + +[data-slot="composer-rich-input"][contenteditable="false"] { + opacity: 0.5; + cursor: default; +} + +/* Ref Chip (inline) */ +.ref-chip { + display: inline-flex; + align-items: center; + gap: 2px; + padding: 1px 6px; + border-radius: 4px; + background: color-mix(in srgb, var(--semi-color-primary, #3370ff) 10%, transparent); + color: var(--semi-color-primary, #3370ff); + font-size: 0.6875rem; + vertical-align: baseline; + user-select: none; + cursor: default; + line-height: 1.4; +} + +.ref-chip-icon { + display: inline-flex; + align-items: center; +} + +.ref-chip-label { + max-width: 10rem; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +/* ═══ Skill Chip ═══ */ +.skill-chip { + display: inline-flex; + align-items: center; + padding: 0.1rem 0.4rem; + border-radius: 4px; + background: rgba(59, 130, 246, 0.12); + color: #3b82f6; + font-family: var(--font-mono, ui-monospace, monospace); + font-size: 0.82em; + font-weight: 500; + line-height: 1.4; + white-space: nowrap; + user-select: none; + vertical-align: baseline; +} + +/* ═══ @ Ref Popover ═══ */ +[data-slot="at-ref-popover"] { + position: relative; + width: 100%; + margin-bottom: 0.25rem; + animation: skillSlideUp 0.12s ease-out; +} + +[data-slot="at-ref-form"] { + display: flex; + align-items: center; + gap: 0.25rem; + padding: 0.375rem 0.5rem; + background: var(--semi-color-bg-0, #fff); + border: 1px solid var(--semi-color-border, #e0e0e0); + border-radius: 0.5rem; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); +} + +[data-slot="at-ref-kinds"] { + display: flex; + gap: 2px; +} + +[data-slot="at-ref-kind-btn"] { + width: 1.5rem; + height: 1.5rem; + border: none; + border-radius: 0.25rem; + background: transparent; + font-size: 0.75rem; + cursor: pointer; + display: grid; + place-items: center; + transition: background 0.1s; +} + +[data-slot="at-ref-kind-btn"]:hover { + background: var(--semi-color-fill-0, #f5f5f5); +} + +[data-slot="at-ref-kind-btn"][data-active] { + background: color-mix(in srgb, var(--semi-color-primary, #3370ff) 12%, transparent); +} + +[data-slot="at-ref-input"] { + flex: 1; + border: none; + outline: none; + background: transparent; + font-size: 0.75rem; + color: var(--semi-color-text-0, #1c1f23); + font-family: monospace; + min-width: 0; +} + +[data-slot="at-ref-input"]::placeholder { + color: var(--semi-color-text-3, #8f959e); +} + +[data-slot="at-ref-confirm"] { + width: 1.5rem; + height: 1.5rem; + border: none; + border-radius: 0.25rem; + background: var(--semi-color-text-0, #1c1f23); + color: var(--semi-color-bg-0, #fff); + font-size: 0.75rem; + cursor: pointer; + display: grid; + place-items: center; + transition: opacity 0.1s; +} + +[data-slot="at-ref-confirm"]:disabled { + opacity: 0.2; + cursor: default; +} + +/* ═══ Toolbar ═══ */ +[data-slot="composer-toolbar"] { + display: flex; + align-items: center; + justify-content: space-between; + padding-top: 0.25rem; + border-top: 1px solid color-mix(in srgb, var(--semi-color-border, #e0e0e0) 50%, transparent); + margin-top: 0.25rem; +} + +[data-slot="composer-toolbar-left"], +[data-slot="composer-toolbar-right"] { + display: flex; + align-items: center; + gap: 0.25rem; +} + +/* Attach button */ +[data-slot="composer-attach-btn"] { + width: var(--composer-control-size); + height: var(--composer-control-size); + border-radius: 0.375rem; + border: none; + background: transparent; + color: var(--semi-color-text-2, #4e5969); + display: grid; + place-items: center; + cursor: pointer; + transition: background 0.12s, color 0.12s; +} + +[data-slot="composer-attach-btn"]:hover { + background: var(--semi-color-fill-0, #f5f5f5); + color: var(--semi-color-text-0, #1c1f23); +} + +/* Send button — dark circle */ +[data-slot="composer-cta"] { + width: var(--composer-control-size); + height: var(--composer-control-size); + border-radius: 50%; + border: none; + display: grid; + place-items: center; + cursor: pointer; + transition: opacity 0.12s, background 0.12s, border-color 0.12s; + background: var(--semi-color-text-0, #1c1f23); + color: var(--semi-color-bg-0, #fff); +} + +[data-slot="composer-cta"]:disabled { + opacity: 0.2; + cursor: default; +} + +[data-slot="composer-cta"]:not(:disabled):hover { + opacity: 0.8; +} + +[data-slot="composer-cta"][data-state="stop"] { + background: var(--semi-color-bg-0, #fff); + color: var(--semi-color-text-0, #1c1f23); + border: 1px solid var(--semi-color-border, #e0e0e0); +} + +[data-slot="composer-cta"][data-state="stop"]:hover { + background: var(--semi-color-fill-0, #f5f5f5); + opacity: 1; +} + +[data-slot="composer-cta"][data-state="queue"] { + background: var(--semi-color-primary, #3370ff); + color: #fff; +} + +/* ═══ Status Stack ═══ */ +[data-slot="composer-status-stack"] { + display: flex; + flex-wrap: wrap; + gap: 0.25rem; + padding: 0 0.25rem 0.25rem; +} + +[data-slot="status-running"] { + display: inline-flex; + align-items: center; + gap: 0.375rem; + padding: 0.2rem 0.5rem; + border-radius: 1rem; + background: color-mix(in srgb, var(--semi-color-primary, #3370ff) 8%, transparent); + font-size: 0.6875rem; + color: var(--semi-color-primary, #3370ff); + user-select: none; +} + +[data-slot="status-dot"] { + width: 6px; + height: 6px; + border-radius: 50%; + background: var(--semi-color-primary, #3370ff); + animation: statusPulse 1.2s ease-in-out infinite; +} + +@keyframes statusPulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.3; } +} + +[data-slot="status-queued"] { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.2rem 0.375rem; + border-radius: 1rem; + background: var(--semi-color-fill-0, #f5f5f5); + font-size: 0.6875rem; + color: var(--semi-color-text-1, #1c1f23); + user-select: none; +} + +[data-slot="status-queue-num"] { + font-weight: 600; + color: var(--semi-color-text-2, #4e5969); + font-size: 0.625rem; +} + +[data-slot="status-queue-text"] { + max-width: 8rem; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +[data-slot="status-queue-cancel"] { + width: 1rem; + height: 1rem; + border: none; + border-radius: 50%; + background: transparent; + color: var(--semi-color-text-3, #8f959e); + display: grid; + place-items: center; + cursor: pointer; + transition: background 0.1s, color 0.1s; +} + +[data-slot="status-queue-cancel"]:hover { + background: rgba(0, 0, 0, 0.06); + color: var(--semi-color-text-0, #1c1f23); +} + +/* ═══ Drop Overlay ═══ */ +[data-slot="composer-drop-overlay"] { + position: absolute; + inset: 0; + z-index: 100; + display: grid; + place-items: center; + background: color-mix(in srgb, var(--semi-color-primary, #3370ff) 10%, transparent); + border: 2px dashed var(--semi-color-primary, #3370ff); + border-radius: 0.75rem; + color: var(--semi-color-primary, #3370ff); + font-size: 0.8125rem; + font-weight: 500; + pointer-events: none; +} + +/* ═══ Model Selector (Ghost Pill — Hermes parity) ═══ */ +[data-slot="model-selector"] { + position: relative; +} + +[data-slot="model-chip"] { + display: flex; + align-items: center; + gap: 0.25rem; + height: var(--composer-control-size); + padding: 0 0.5rem; + border: none; + border-radius: 0.375rem; + background: transparent; + color: var(--semi-color-text-2, #4e5969); + font-size: 0.75rem; + font-weight: 400; + cursor: pointer; + transition: background 0.12s, color 0.12s; + white-space: nowrap; + max-width: 10rem; +} + +[data-slot="model-chip"]:hover, +[data-slot="model-chip"][data-open] { + background: color-mix(in srgb, var(--semi-color-text-0, #1c1f23) 5%, transparent); + color: var(--semi-color-text-0, #1c1f23); +} + +[data-slot="model-chip"][data-loading] { + padding: 0 0.375rem; +} + +[data-slot="model-chip-label"] { + overflow: hidden; + text-overflow: ellipsis; + max-width: 12rem; +} + +[data-slot="model-chip-caret"] { + display: inline-flex; + opacity: 0.4; + transition: transform 0.15s; +} + +[data-slot="model-chip-caret"] svg { + width: 8px; + height: 8px; +} + +[data-slot="model-chip-caret"][data-open] { + transform: rotate(180deg); +} + +[data-slot="model-chip-spinner"] { + display: inline-flex; + gap: 2px; + align-items: center; + height: 10px; +} + +[data-slot="model-chip-spinner"]::before, +[data-slot="model-chip-spinner"]::after, +[data-slot="model-chip-spinner"] span { + content: ''; + display: block; + width: 3px; + height: 3px; + border-radius: 50%; + background: currentColor; + opacity: 0.4; + animation: dotPulse 1s ease-in-out infinite; +} + +[data-slot="model-chip-spinner"]::after { + animation-delay: 0.2s; +} + +[data-slot="model-chip-spinner"] span { + animation-delay: 0.4s; +} + +@keyframes dotPulse { + 0%, 80%, 100% { opacity: 0.25; transform: scale(0.8); } + 40% { opacity: 0.8; transform: scale(1); } +} + +[data-slot="provider-dot"] { + width: 6px; + height: 6px; + border-radius: 50%; + flex-shrink: 0; +} + +/* Model dropdown menu — Hermes-style grouped panel */ +[data-slot="model-menu"] { + position: absolute; + bottom: calc(100% + 8px); + right: 0; + width: 16rem; + max-height: 24rem; + display: flex; + flex-direction: column; + background: color-mix(in srgb, var(--semi-color-bg-0, #fff) 92%, transparent); + backdrop-filter: blur(14px) saturate(1.15); + -webkit-backdrop-filter: blur(14px) saturate(1.15); + border: 1px solid color-mix(in srgb, var(--semi-color-border, #e0e0e0) 50%, transparent); + border-radius: 0.5rem; + box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08), 0 0 0 0.5px rgba(0, 0, 0, 0.02); + z-index: 60; + animation: skillSlideUp 0.12s ease-out; + overflow: hidden; +} + +/* Search */ +[data-slot="model-menu-search"] { + display: flex; + align-items: center; + gap: 0.375rem; + padding: 0.5rem 0.625rem; + border-bottom: 1px solid color-mix(in srgb, var(--semi-color-border, #e0e0e0) 50%, transparent); +} + +[data-slot="model-menu-search-icon"] { + flex-shrink: 0; + color: var(--semi-color-text-3, #8f959e); +} + +[data-slot="model-menu-search-input"] { + flex: 1; + border: none; + outline: none; + background: transparent; + font-size: 0.75rem; + color: var(--semi-color-text-0, #1c1f23); + min-width: 0; +} + +[data-slot="model-menu-search-input"]::placeholder { + color: var(--semi-color-text-3, #8f959e); +} + +/* Scrollable body */ +[data-slot="model-menu-body"] { + flex: 1; + overflow-y: auto; + padding: 0.25rem; +} + +/* Section */ +[data-slot="model-menu-section"] { + padding-top: 0.25rem; +} + +[data-slot="model-menu-section"] + [data-slot="model-menu-section"] { + border-top: 1px solid color-mix(in srgb, var(--semi-color-border, #e0e0e0) 40%, transparent); + margin-top: 0.25rem; + padding-top: 0.375rem; +} + +[data-slot="model-menu-section-header"] { + display: flex; + align-items: center; + gap: 0.375rem; + padding: 0.25rem 0.5rem; + font-size: 0.5625rem; + font-weight: 600; + color: var(--semi-color-text-3, #8f959e); + letter-spacing: 0.05em; + user-select: none; +} + +/* Items */ +[data-slot="model-menu-item"] { + display: flex; + align-items: center; + gap: 0.375rem; + width: 100%; + padding: 0.375rem 0.5rem; + border: none; + border-radius: 0.25rem; + background: transparent; + color: var(--semi-color-text-0, #1c1f23); + font-size: 0.75rem; + cursor: pointer; + text-align: left; + transition: background 0.1s; +} + +[data-slot="model-menu-item"]:hover { + background: var(--semi-color-fill-0, #f5f5f5); +} + +[data-slot="model-menu-item"][data-active] { + color: var(--semi-color-text-0, #1c1f23); + font-weight: 500; +} + +[data-slot="model-menu-name"] { + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +[data-slot="model-check"] { + font-size: 0.625rem; + color: var(--semi-color-primary, #3370ff); + flex-shrink: 0; + width: 0.75rem; +} + +/* Mixin expand */ +[data-slot="mixin-caret"] { + display: inline-flex; + padding: 2px; + border-radius: 2px; + transition: transform 0.15s; + color: var(--semi-color-text-3, #8f959e); +} + +[data-slot="mixin-caret"]:hover { + background: var(--semi-color-fill-1, #eee); +} + +[data-slot="mixin-caret"][data-expanded] { + transform: rotate(180deg); +} + +[data-slot="mixin-members"] { + padding-left: 1.25rem; +} + +[data-slot="mixin-member"] { + display: flex; + align-items: center; + gap: 0.375rem; + padding: 0.25rem 0.5rem; + font-size: 0.6875rem; + color: var(--semi-color-text-2, #4e5969); +} + +/* Empty */ +[data-slot="model-menu-empty"] { + padding: 1rem 0.5rem; + text-align: center; + font-size: 0.75rem; + color: var(--semi-color-text-3, #8f959e); +} + +/* Footer */ +[data-slot="model-menu-footer"] { + display: flex; + border-top: 1px solid color-mix(in srgb, var(--semi-color-border, #e0e0e0) 50%, transparent); + padding: 0.25rem; +} + +[data-slot="model-menu-action"] { + flex: 1; + padding: 0.375rem 0.5rem; + border: none; + border-radius: 0.25rem; + background: transparent; + color: var(--semi-color-text-2, #4e5969); + font-size: 0.6875rem; + cursor: pointer; + text-align: center; + transition: background 0.1s, color 0.1s; +} + +[data-slot="model-menu-action"]:hover { + background: var(--semi-color-fill-0, #f5f5f5); + color: var(--semi-color-text-0, #1c1f23); +} + +/* ═══ Attachment Strip ═══ */ +[data-slot="attachment-strip"] { + display: flex; + flex-wrap: wrap; + gap: 0.375rem; + padding-bottom: 0.375rem; + animation: attachReveal 0.2s ease-out; +} + +@keyframes attachReveal { + from { opacity: 0; max-height: 0; } + to { opacity: 1; max-height: 200px; } +} + +[data-slot="attachment-thumb"] { + position: relative; + width: 3.5rem; + height: 3.5rem; + border-radius: 0.375rem; + overflow: hidden; + border: 1px solid var(--semi-color-border, #e0e0e0); +} + +[data-slot="attachment-thumb"] img { + width: 100%; + height: 100%; + object-fit: cover; +} + +[data-slot="attachment-file-chip"] { + display: flex; + align-items: center; + gap: 0.375rem; + padding: 0.25rem 0.5rem; + border-radius: 0.375rem; + border: 1px solid var(--semi-color-border, #e0e0e0); + background: var(--semi-color-fill-0, #f9f9f9); + max-width: 12rem; +} + +[data-slot="attachment-file-icon"] { + font-size: 1rem; + flex-shrink: 0; +} + +[data-slot="attachment-file-meta"] { + display: flex; + flex-direction: column; + overflow: hidden; + min-width: 0; +} + +[data-slot="attachment-file-name"] { + font-size: 0.6875rem; + color: var(--semi-color-text-0, #1c1f23); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +[data-slot="attachment-file-size"] { + font-size: 0.625rem; + color: var(--semi-color-text-3, #8f959e); +} + +[data-slot="attachment-remove"] { + flex-shrink: 0; + width: 1rem; + height: 1rem; + border-radius: 50%; + border: none; + background: var(--semi-color-fill-1, #eee); + color: var(--semi-color-text-2, #4e5969); + font-size: 0.625rem; + line-height: 1; + cursor: pointer; + display: grid; + place-items: center; + transition: background 0.1s; +} + +[data-slot="attachment-thumb"] [data-slot="attachment-remove"] { + position: absolute; + top: 2px; + right: 2px; + background: rgba(0, 0, 0, 0.5); + color: #fff; +} + +[data-slot="attachment-remove"]:hover { + background: var(--semi-color-danger, #f53f3f); + color: #fff; +} + +[data-slot="attachment-spinner"] { + width: 12px; + height: 12px; + border: 1.5px solid var(--semi-color-border, #e0e0e0); + border-top-color: var(--semi-color-primary, #3370ff); + border-radius: 50%; + animation: chipSpin 0.6s linear infinite; + flex-shrink: 0; +} + +[data-slot="attachment-error-badge"] { + width: 1rem; + height: 1rem; + border-radius: 50%; + border: none; + background: var(--semi-color-danger, #f53f3f); + color: #fff; + font-size: 0.625rem; + font-weight: 700; + line-height: 1; + cursor: pointer; + display: grid; + place-items: center; + flex-shrink: 0; +} + +[data-slot="attachment-file-chip"][data-status="error"] { + border-color: var(--semi-color-danger, #f53f3f); +} + +[data-slot="attachment-thumb"][data-status="error"] { + border-color: var(--semi-color-danger, #f53f3f); +} + +[data-slot="attachment-file-error"] { + font-size: 0.5625rem; + color: var(--semi-color-danger, #f53f3f); +} + +/* ═══ Skill Panel ═══ */ +[data-slot="skill-wrap"] { + position: relative; +} + +[data-slot="skill-trigger"] { + width: var(--composer-control-size); + height: var(--composer-control-size); + border-radius: 0.375rem; + border: none; + background: transparent; + color: var(--semi-color-text-2, #4e5969); + display: grid; + place-items: center; + cursor: pointer; + transition: background 0.12s, color 0.12s; +} + +[data-slot="skill-trigger"]:hover { + background: var(--semi-color-fill-0, #f5f5f5); + color: var(--semi-color-primary, #3370ff); +} + +[data-slot="skill-panel"] { + position: absolute; + bottom: calc(100% + 6px); + left: 0; + min-width: 11rem; + max-height: 24rem; + overflow-y: auto; + background: var(--semi-color-bg-0, #fff); + border: 1px solid var(--semi-color-border, #e0e0e0); + border-radius: 0.5rem; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08); + padding: 0.25rem; + z-index: 60; + animation: skillSlideUp 0.12s ease-out; +} + +@keyframes skillSlideUp { + from { opacity: 0; transform: translateY(4px); } + to { opacity: 1; transform: translateY(0); } +} + +[data-slot="skill-section"] { + padding: 0.125rem 0; +} + +[data-slot="skill-section"] + [data-slot="skill-section"] { + border-top: 1px solid color-mix(in srgb, var(--semi-color-border, #e0e0e0) 50%, transparent); + margin-top: 0.25rem; + padding-top: 0.25rem; +} + +[data-slot="skill-section-title"] { + font-size: 0.625rem; + font-weight: 600; + color: var(--semi-color-text-3, #8f959e); + text-transform: uppercase; + letter-spacing: 0.03em; + padding: 0.25rem 0.5rem 0.125rem; +} + +[data-slot="skill-item"] { + display: flex; + align-items: center; + gap: 0.5rem; + width: 100%; + padding: 0.375rem 0.5rem; + border: none; + border-radius: 0.25rem; + background: transparent; + color: var(--semi-color-text-0, #1c1f23); + font-size: 0.75rem; + cursor: pointer; + text-align: left; + transition: background 0.1s; +} + +[data-slot="skill-item"]:hover, +[data-slot="skill-item"][data-focused] { + background: var(--semi-color-fill-0, #f5f5f5); +} + +[data-slot="skill-info"] { + display: flex; + align-items: baseline; + gap: 0.5rem; + min-width: 0; +} + +[data-slot="skill-name"] { + font-size: 0.75rem; + font-weight: 500; + color: var(--semi-color-text-0, #1c1f23); + flex-shrink: 0; +} + +[data-slot="skill-desc"] { + font-size: 0.6875rem; + color: var(--semi-color-text-2, #4e5969); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +[data-slot="skill-panel-hint"] { + padding: 0.25rem 0.5rem; + font-size: 0.6875rem; + color: var(--semi-color-text-2, #4e5969); + border-top: 1px solid color-mix(in srgb, var(--semi-color-border, #e0e0e0) 50%, transparent); + margin-top: 0.25rem; + user-select: none; +} + +/* ═══ Completion Drawer (/ slash commands) ═══ */ +[data-slot="completion-drawer"] { + position: relative; + width: 100%; + max-height: 16rem; + overflow-y: auto; + background: var(--semi-color-bg-0, #fff); + border: 1px solid var(--semi-color-border, #e0e0e0); + border-radius: 0.5rem; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); + padding: 0.25rem; + margin-bottom: 0.25rem; + animation: skillSlideUp 0.12s ease-out; +} + +[data-slot="completion-item"] { + display: flex; + align-items: center; + gap: 0.5rem; + width: 100%; + padding: 0.375rem 0.5rem; + border: none; + border-radius: 0.25rem; + background: transparent; + cursor: pointer; + text-align: left; + transition: background 0.1s; +} + +[data-slot="completion-item"]:hover, +[data-slot="completion-item"][data-focused] { + background: var(--semi-color-fill-0, #f5f5f5); +} + +[data-slot="completion-icon"] { + font-size: 1rem; + flex-shrink: 0; + width: 1.25rem; + text-align: center; +} + +[data-slot="completion-info"] { + display: flex; + flex-direction: column; + gap: 1px; + min-width: 0; +} + +[data-slot="completion-title"] { + font-size: 0.75rem; + font-weight: 500; + color: var(--semi-color-text-0, #1c1f23); + font-family: monospace; +} + +[data-slot="completion-badge"] { + display: inline-block; + margin-left: 0.375rem; + font-size: 0.5625rem; + font-family: sans-serif; + font-weight: 400; + color: var(--semi-color-text-3, #8f959e); + background: var(--semi-color-fill-0, #f5f5f5); + padding: 0 4px; + border-radius: 3px; + vertical-align: middle; +} + +[data-slot="completion-desc"] { + font-size: 0.6875rem; + color: var(--semi-color-text-3, #8f959e); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +/* ═══ Context Menu (+ button dropdown) ═══ */ +[data-slot="context-menu-wrap"] { + position: relative; +} + +[data-slot="context-menu"] { + position: absolute; + bottom: calc(100% + 6px); + left: 0; + min-width: 11rem; + background: var(--semi-color-bg-0, #fff); + border: 1px solid var(--semi-color-border, #e0e0e0); + border-radius: 0.5rem; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08); + padding: 0.25rem; + z-index: 60; + animation: skillSlideUp 0.12s ease-out; +} + +[data-slot="context-menu-title"] { + padding: 0.25rem 0.5rem 0.125rem; + font-size: 0.625rem; + font-weight: 600; + color: var(--semi-color-text-3, #8f959e); + text-transform: uppercase; + letter-spacing: 0.03em; + user-select: none; +} + +[data-slot="context-menu-item"] { + display: flex; + align-items: center; + gap: 0.5rem; + width: 100%; + padding: 0.375rem 0.5rem; + border: none; + border-radius: 0.25rem; + background: transparent; + color: var(--semi-color-text-0, #1c1f23); + font-size: 0.75rem; + cursor: pointer; + text-align: left; + transition: background 0.1s; +} + +[data-slot="context-menu-item"]:hover { + background: var(--semi-color-fill-0, #f5f5f5); +} + +[data-slot="context-menu-icon"] { + display: inline-flex; + align-items: center; + color: var(--semi-color-text-2, #4e5969); +} + +[data-slot="context-menu-label"] { + flex: 1; +} + +[data-slot="context-menu-separator"] { + display: block; + height: 1px; + margin: 0.25rem 0.5rem; + background: var(--semi-color-border, #e0e0e0); +} + +[data-slot="context-menu-hint"] { + padding: 0.25rem 0.5rem; + font-size: 0.6875rem; + color: var(--semi-color-text-2, #4e5969); + border-top: 1px solid color-mix(in srgb, var(--semi-color-border, #e0e0e0) 50%, transparent); + margin-top: 0.25rem; + user-select: none; +} diff --git a/frontends/desktop/src/components/chat/Composer/index.tsx b/frontends/desktop/src/components/chat/Composer/index.tsx new file mode 100644 index 000000000..368b76e3e --- /dev/null +++ b/frontends/desktop/src/components/chat/Composer/index.tsx @@ -0,0 +1,308 @@ +import { useRef, useState, useCallback, useEffect } from 'react'; +import type { SendOptions } from '../../../stores/chat'; +import { RichEditorInput, type RichEditorHandle } from './RichEditorInput'; +import { CompletionDrawer } from './CompletionDrawer'; +import { AtRefPopover } from './AtRefPopover'; +import { ContextMenu } from './ContextMenu'; +import { ModelSelector } from './ModelSelector'; +import { AttachmentStrip, type AttachmentFile } from './AttachmentStrip'; +import { SkillPanel } from './SkillPanel'; +import { PrimaryCTA, computeCTAState } from './PrimaryCTA'; +import { StatusStack } from './StatusStack'; +import { usePlaceholder } from './usePlaceholder'; +import './composer.css'; + +interface Props { + onSend: (text: string, opts?: SendOptions) => void; + onStop: () => void; + isGenerating: boolean; + editorRef?: React.RefObject; + hideStatusStack?: boolean; + modelControl?: React.ReactNode | null; +} + +let fileIdCounter = 0; + +export function Composer({ onSend, onStop, isGenerating, editorRef: externalEditorRef, hideStatusStack, modelControl }: Props) { + const internalEditorRef = useRef(null); + const editorRef = (externalEditorRef ?? internalEditorRef) as React.RefObject; + const composerRef = useRef(null); + const fileInputRef = useRef(null); + const imageInputRef = useRef(null); + const { text: placeholderText } = usePlaceholder(); + const [plainText, setPlainText] = useState(''); + const [attachments, setAttachments] = useState([]); + const [isDragOver, setIsDragOver] = useState(false); + const [slashQuery, setSlashQuery] = useState(null); + const [atQuery, setAtQuery] = useState(null); + + useEffect(() => { + const el = composerRef.current; + if (!el) return; + const observer = new ResizeObserver((entries) => { + const height = entries[0]?.borderBoxSize?.[0]?.blockSize ?? el.offsetHeight; + document.documentElement.style.setProperty('--composer-measured-height', `${height}px`); + }); + observer.observe(el); + return () => observer.disconnect(); + }, []); + + const processFiles = useCallback((fileList: FileList | File[]) => { + const MAX_SIZE = 50 * 1024 * 1024; // 50 MB + const newFiles: AttachmentFile[] = []; + for (const file of Array.from(fileList)) { + const id = `att-${++fileIdCounter}`; + const isImage = file.type.startsWith('image/') && file.type !== 'image/svg+xml'; + const tooLarge = file.size > MAX_SIZE; + if (isImage && !tooLarge) { + const reader = new FileReader(); + reader.onload = (e) => { + setAttachments((prev) => + prev.map((a) => a.id === id ? { ...a, preview: e.target?.result as string, status: 'ready' as const } : a) + ); + }; + reader.readAsDataURL(file); + } else if (!isImage && !tooLarge) { + // Upload file to bridge to get absolute disk path (agent reads via file_read tool) + const reader = new FileReader(); + reader.onload = async (e) => { + try { + const dataUrl = e.target?.result as string; + const { uploadFile } = await import('../../../services/chat'); + const serverPath = await uploadFile(file.name, dataUrl); + setAttachments((prev) => + prev.map((a) => a.id === id ? { ...a, path: serverPath, status: 'ready' as const, errorMsg: undefined } : a) + ); + } catch (error) { + const errorMsg = error instanceof Error ? error.message : 'upload failed'; + setAttachments((prev) => + prev.map((a) => a.id === id ? { ...a, status: 'error' as const, errorMsg } : a) + ); + } + }; + reader.onerror = () => { + setAttachments((prev) => + prev.map((a) => a.id === id ? { ...a, status: 'error' as const, errorMsg: 'read failed' } : a) + ); + }; + reader.readAsDataURL(file); + } + newFiles.push({ + id, + name: file.name, + size: file.size, + type: isImage ? 'image' : 'file', + status: tooLarge ? 'error' : 'uploading', + errorMsg: tooLarge ? 'File too large (max 50 MB)' : undefined, + path: (file as File & { path?: string }).path || file.name, + }); + } + setAttachments((prev) => [...prev, ...newFiles]); + }, []); + + const handleSend = useCallback(() => { + const text = plainText.trim(); + if (!text && attachments.length === 0) return; + const readyImages = attachments.filter((a) => a.type === 'image' && a.status === 'ready'); + const pendingImages = attachments.filter((a) => a.type === 'image' && a.status === 'uploading'); + const pendingFiles = attachments.filter((a) => a.type === 'file' && a.status === 'uploading'); + const errorFiles = attachments.filter((a) => a.status === 'error'); + if (pendingImages.length > 0 || pendingFiles.length > 0 || errorFiles.length > 0) return; + const opts: SendOptions = {}; + const files = attachments.filter((a) => a.type === 'file'); + if (files.length > 0) { + opts.files = files.map((f) => ({ name: f.name, path: f.path || f.name, size: f.size })); + } + if (readyImages.length > 0) { + opts.images = readyImages.map((f) => ({ name: f.name, path: f.path || f.name, base64: f.preview! })); + } + onSend(text || '', Object.keys(opts).length > 0 ? opts : undefined); + editorRef.current?.clear(); + setPlainText(''); + setAttachments([]); + }, [plainText, attachments, onSend]); + + const handleKeyDown = useCallback( + (e: React.KeyboardEvent) => { + if (e.key === 'Enter' && !e.shiftKey) { + e.preventDefault(); + handleSend(); + } + }, + [handleSend], + ); + + const handleEditorInput = useCallback((text: string) => { + setPlainText(text); + }, []); + + const handleSlashTrigger = useCallback((query: string) => { + setSlashQuery(query); + }, []); + + const handleSlashDismiss = useCallback(() => { + setSlashQuery(null); + }, []); + + const handleCompletionSelect = useCallback((id: string, prompt: string) => { + editorRef.current?.setSkillChip(id, prompt); + editorRef.current?.focus(); + setSlashQuery(null); + }, []); + + const handleAtTrigger = useCallback((query: string) => { + setAtQuery(query); + }, []); + + const handleAtDismiss = useCallback(() => { + setAtQuery(null); + }, []); + + const handleAtConfirm = useCallback((kind: string, value: string) => { + // Remove the `@query` text from editor, then insert chip + const currentText = editorRef.current?.getText() || ''; + const atIdx = currentText.lastIndexOf('@'); + if (atIdx >= 0) { + editorRef.current?.setText(currentText.slice(0, atIdx)); + } + editorRef.current?.insertChip(kind, value); + editorRef.current?.focus(); + setAtQuery(null); + }, []); + + const handlePasteFiles = useCallback((files: File[]) => { + processFiles(files); + }, [processFiles]); + + const handleRemoveAttachment = useCallback((id: string) => { + setAttachments((prev) => prev.filter((a) => a.id !== id)); + }, []); + + const handleSkillSelect = useCallback((id: string, prompt: string) => { + editorRef.current?.setSkillChip(id, prompt); + editorRef.current?.focus(); + }, []); + + const handleFileClick = useCallback(() => { + fileInputRef.current?.click(); + }, []); + + const handleImageClick = useCallback(() => { + imageInputRef.current?.click(); + }, []); + + const handlePasteFromClipboard = useCallback(async () => { + try { + const items = await navigator.clipboard.read(); + for (const item of items) { + const imageType = item.types.find((t) => t.startsWith('image/')); + if (imageType) { + const blob = await item.getType(imageType); + const file = new File([blob], 'clipboard-image.png', { type: imageType }); + processFiles([file]); + return; + } + } + } catch { /* clipboard permission denied — silently ignore */ } + }, [processFiles]); + + const handleFileChange = useCallback((e: React.ChangeEvent) => { + if (e.target.files && e.target.files.length > 0) { + processFiles(e.target.files); + } + e.target.value = ''; + }, [processFiles]); + + const handleDragOver = useCallback((e: React.DragEvent) => { + e.preventDefault(); + setIsDragOver(true); + }, []); + + const handleDragLeave = useCallback((e: React.DragEvent) => { + e.preventDefault(); + setIsDragOver(false); + }, []); + + const handleDrop = useCallback((e: React.DragEvent) => { + e.preventDefault(); + setIsDragOver(false); + if (e.dataTransfer.files.length > 0) { + processFiles(e.dataTransfer.files); + } + }, [processFiles]); + + const hasContent = plainText.trim().length > 0 || attachments.length > 0; + const hasPendingUploads = attachments.some((a) => a.status === 'uploading'); + const ctaState = computeCTAState(isGenerating, hasContent, hasPendingUploads); + + return ( +
    + {isDragOver &&
    Drop files here
    } +
    + {!hideStatusStack && } + + + +
    + +
    +
    +
    + + +
    +
    + {modelControl === undefined ? : modelControl} + +
    +
    +
    + + +
    + ); +} diff --git a/frontends/desktop/src/components/chat/Composer/rich-editor.ts b/frontends/desktop/src/components/chat/Composer/rich-editor.ts new file mode 100644 index 000000000..9505302f5 --- /dev/null +++ b/frontends/desktop/src/components/chat/Composer/rich-editor.ts @@ -0,0 +1,191 @@ +/** + * Composer Rich Editor — DOM utilities for contentEditable input. + * Not a React component. Pure DOM manipulation functions. + */ + +// ═══ DOM → PlainText round-trip ═══ + +export function composerPlainText(el: HTMLElement): string { + let text = ''; + for (const node of el.childNodes) { + if (node.nodeType === Node.TEXT_NODE) { + text += node.textContent || ''; + } else if (node instanceof HTMLElement) { + if (node.dataset.refText) { + text += node.dataset.refText; + } else if (node.tagName === 'BR') { + text += '\n'; + } else { + const inner = composerPlainText(node); + if (inner) text += '\n' + inner; + } + } + } + return text; +} + +// ═══ DOM Normalization ═══ + +export function normalizeComposerDom(el: HTMLElement): void { + const children = Array.from(el.childNodes); + for (const child of children) { + if (child instanceof HTMLElement) { + if (child.dataset.refText) continue; + if (child.tagName === 'BR') continue; + // Unwrap browser-inserted divs/paragraphs: move their children up + if (child.tagName === 'DIV' || child.tagName === 'P') { + const br = document.createElement('br'); + el.insertBefore(br, child); + while (child.firstChild) { + el.insertBefore(child.firstChild, child); + } + el.removeChild(child); + } + } + } + // Merge adjacent text nodes + el.normalize(); +} + +// ═══ Caret Utils ═══ + +export function placeCaretEnd(el: HTMLElement): void { + const range = document.createRange(); + range.selectNodeContents(el); + range.collapse(false); + const sel = window.getSelection(); + if (sel) { + sel.removeAllRanges(); + sel.addRange(range); + } +} + +export function placeCaretAt(el: HTMLElement, offset: number): void { + const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT); + let pos = 0; + let node: Text | null = null; + while (walker.nextNode()) { + node = walker.currentNode as Text; + const len = node.textContent?.length || 0; + if (pos + len >= offset) { + const range = document.createRange(); + range.setStart(node, offset - pos); + range.collapse(true); + const sel = window.getSelection(); + if (sel) { sel.removeAllRanges(); sel.addRange(range); } + return; + } + pos += len; + } + placeCaretEnd(el); +} + +export function getCaretOffset(el: HTMLElement): number { + const sel = window.getSelection(); + if (!sel || sel.rangeCount === 0) return 0; + const range = sel.getRangeAt(0).cloneRange(); + range.selectNodeContents(el); + range.setEnd(sel.getRangeAt(0).startContainer, sel.getRangeAt(0).startOffset); + return range.toString().length; +} + +// ═══ Insert at Caret ═══ + +export function insertAtCaret(el: HTMLElement, node: Node): void { + el.focus(); + const sel = window.getSelection(); + if (!sel || sel.rangeCount === 0) { + el.appendChild(node); + return; + } + const range = sel.getRangeAt(0); + range.deleteContents(); + range.insertNode(node); + // Move caret after inserted node + range.setStartAfter(node); + range.collapse(true); + sel.removeAllRanges(); + sel.addRange(range); +} + +export function replaceAllContent(el: HTMLElement, text: string): void { + el.textContent = text; + placeCaretEnd(el); +} + +// ═══ Chip Creation ═══ + +export function refChipElement(kind: string, value: string, label?: string): HTMLSpanElement { + const chip = document.createElement('span'); + chip.contentEditable = 'false'; + chip.dataset.refText = `@${kind}:\`${value}\``; + chip.dataset.refKind = kind; + chip.className = 'ref-chip'; + chip.innerHTML = `${kindIconSvg(kind)}${escapeHtml(label || value)}`; + return chip; +} + +export function insertChipWithSpace(el: HTMLElement, kind: string, value: string, label?: string): void { + const chip = refChipElement(kind, value, label); + insertAtCaret(el, chip); + // Insert a trailing space so caret doesn't get stuck + const space = document.createTextNode(' '); + insertAtCaret(el, space); +} + +// ═══ Skill Chip ═══ + +export function skillChipElement(id: string, prompt: string): HTMLSpanElement { + const chip = document.createElement('span'); + chip.contentEditable = 'false'; + chip.dataset.refText = prompt; + chip.dataset.skillId = id; + chip.className = 'skill-chip'; + chip.textContent = `/${id}`; + return chip; +} + +export function replaceWithSkillChip(el: HTMLElement, id: string, prompt: string): void { + el.textContent = ''; + const chip = skillChipElement(id, prompt); + el.appendChild(chip); + const space = document.createTextNode(' '); + el.appendChild(space); + placeCaretEnd(el); +} + +// ═══ Value Quoting ═══ + +export function quoteRefValue(value: string): string { + if (!value.includes('`')) return `\`${value}\``; + if (!value.includes('"')) return `"${value}"`; + if (!value.includes("'")) return `'${value}'`; + return `\`${value.replace(/`/g, '\\`')}\``; +} + +// ═══ REF_RE ═══ + +export const REF_RE = /@(file|url|image):(`[^`\n]+`|"[^"\n]+"|'[^'\n]+'|\S+)/g; + +// ═══ Helpers ═══ + +export function escapeHtml(str: string): string { + return str + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); +} + +function kindIconSvg(kind: string): string { + switch (kind) { + case 'file': + return ''; + case 'url': + return ''; + case 'image': + return ''; + default: + return ''; + } +} diff --git a/frontends/desktop/src/components/chat/Composer/skills.ts b/frontends/desktop/src/components/chat/Composer/skills.ts new file mode 100644 index 000000000..12ed134d5 --- /dev/null +++ b/frontends/desktop/src/components/chat/Composer/skills.ts @@ -0,0 +1,55 @@ +export interface SkillDef { + id: string; + title: string; + desc: { zh: string; en: string }; + prompt: string; +} + +export const BUILTIN_SKILLS: SkillDef[] = [ + { + id: 'plan', + title: 'Plan', + desc: { en: 'Explore, plan, execute, verify', zh: '探索、规划、执行、验证' }, + prompt: 'Enter Plan mode: read memory/plan_sop.md, follow Explore → Plan → Execute → Verify flow for the task I describe next.', + }, + { + id: 'goal', + title: 'Goal', + desc: { en: 'Achieve a specific objective autonomously', zh: '自主达成指定目标' }, + prompt: 'Enter Goal mode: read L3 goal mode SOP, autonomously achieve the goal I describe next.', + }, + { + id: 'autonomous', + title: 'Autonomous', + desc: { en: 'Select tasks and execute independently', zh: '自主选取任务并独立执行' }, + prompt: 'Enter autonomous mode: read memory/autonomous_operation_sop.md, select or plan tasks, execute independently and produce a report.', + }, + { + id: 'hive', + title: 'Hive', + desc: { en: 'Multi-agent parallel collaboration', zh: '多 agent 并行协作' }, + prompt: 'Start Goal Hive mode: follow hive SOP, spawn multiple workers to collaboratively achieve my next goal.', + }, + { + id: 'review', + title: 'Review', + desc: { en: 'Critical review of latest output', zh: '对最近产出做严格复核' }, + prompt: 'Enter reviewer mode: rigorously critique the latest output, check each item and report issues.', + }, + { + id: 'findwork', + title: 'Find Work', + desc: { en: 'Analyze context, suggest next tasks', zh: '分析当前情况,推荐下一步' }, + prompt: 'Analyze my situation using the autonomous planning approach, generate a batch of TODOs that would interest me.', + }, +]; + +export function matchSkillPrefix(content: string): { id: string; rest: string } | null { + for (const skill of BUILTIN_SKILLS) { + if (content.startsWith(skill.prompt)) { + const rest = content.slice(skill.prompt.length).trimStart(); + return { id: skill.id, rest }; + } + } + return null; +} diff --git a/frontends/desktop/src/components/chat/Composer/usePlaceholder.ts b/frontends/desktop/src/components/chat/Composer/usePlaceholder.ts new file mode 100644 index 000000000..0f45592bd --- /dev/null +++ b/frontends/desktop/src/components/chat/Composer/usePlaceholder.ts @@ -0,0 +1,40 @@ +import { useRef, useMemo } from 'react'; +import { useI18n } from '../../../i18n'; +import { useChatStore } from '../../../stores/chat'; + +const NEW_COUNT = 7; +const FOLLOWUP_COUNT = 5; + +function pickRandom(max: number): number { + return Math.floor(Math.random() * max); +} + +export function usePlaceholder(): { text: string } { + const { t } = useI18n(); + const activeSessionId = useChatStore((s) => s.activeSessionId); + const hasMessages = useChatStore((s) => s.messages.length > 0); + + const rolledRef = useRef<{ sessionId: string | null; index: number; wasNew: boolean }>({ + sessionId: null, + index: pickRandom(NEW_COUNT), + wasNew: true, + }); + + const text = useMemo(() => { + const prev = rolledRef.current; + + if (prev.sessionId !== activeSessionId) { + const isNew = !hasMessages; + const count = isNew ? NEW_COUNT : FOLLOWUP_COUNT; + const index = pickRandom(count); + rolledRef.current = { sessionId: activeSessionId, index, wasNew: isNew }; + const pool = isNew ? 'new' : 'followUp'; + return t(`composer.placeholder.${pool}.${index}`); + } + + const pool = prev.wasNew ? 'new' : 'followUp'; + return t(`composer.placeholder.${pool}.${prev.index}`); + }, [activeSessionId, hasMessages, t]); + + return { text }; +} diff --git a/frontends/desktop/src/components/chat/EmptyState.tsx b/frontends/desktop/src/components/chat/EmptyState.tsx new file mode 100644 index 000000000..b967baf95 --- /dev/null +++ b/frontends/desktop/src/components/chat/EmptyState.tsx @@ -0,0 +1,45 @@ +import { IconChecklistStroked, IconFlagStroked, IconLightningStroked, IconShareStroked, IconShieldStroked, IconSearchStroked } from '@douyinfe/semi-icons'; +import { useI18n } from '../../i18n'; +import { BUILTIN_SKILLS, type SkillDef } from './Composer/skills'; +import wordmarkLight from '../../assets/generic-agent-black.svg'; +import wordmarkDark from '../../assets/generic-agent-white.svg'; +import './emptyState.css'; + +const SKILL_ICONS: Record = { + plan: , + goal: , + autonomous: , + hive: , + review: , + findwork: , +}; + +interface Props { + onPresetClick: (skill: SkillDef) => void; +} + +export function EmptyState({ onPresetClick }: Props) { + const { t } = useI18n(); + + return ( +
    +
    + GenericAgent + +
    +
    + {BUILTIN_SKILLS.map((skill) => ( + + ))} +
    +
    + ); +} diff --git a/frontends/desktop/src/components/chat/Thread/AssistantActionBar.css b/frontends/desktop/src/components/chat/Thread/AssistantActionBar.css new file mode 100644 index 000000000..00b6a2c5b --- /dev/null +++ b/frontends/desktop/src/components/chat/Thread/AssistantActionBar.css @@ -0,0 +1,37 @@ +/* ─── Assistant Action Bar ─── */ +[data-slot="assistant-action-bar"] { + display: flex; + align-items: center; + justify-content: flex-end; + min-height: 1.5rem; + gap: 0.25rem; + padding-right: var(--message-text-indent); + padding-left: var(--message-text-indent); + opacity: 0; + pointer-events: none; + transition: opacity 120ms ease-out; +} + +[data-slot="aui_assistant-message-root"]:hover [data-slot="assistant-action-bar"], +[data-slot="aui_assistant-message-root"]:focus-within [data-slot="assistant-action-bar"] { + opacity: 1; + pointer-events: auto; +} + +[data-slot="action-bar-btn"] { + display: grid; + width: 1.5rem; + height: 1.5rem; + place-items: center; + border: none; + border-radius: 0.25rem; + background: none; + color: var(--semi-color-text-2); + cursor: pointer; + transition: color 0.1s, background 0.1s; +} + +[data-slot="action-bar-btn"]:hover { + background: var(--semi-color-fill-1); + color: var(--semi-color-text-0); +} diff --git a/frontends/desktop/src/components/chat/Thread/AssistantActionBar.tsx b/frontends/desktop/src/components/chat/Thread/AssistantActionBar.tsx new file mode 100644 index 000000000..9525f05b9 --- /dev/null +++ b/frontends/desktop/src/components/chat/Thread/AssistantActionBar.tsx @@ -0,0 +1,44 @@ +import { memo, useCallback, useRef, useState } from 'react'; +import './AssistantActionBar.css'; + +interface Props { + getMessageText: () => string; +} + +export const AssistantActionBar = memo(function AssistantActionBar({ getMessageText }: Props) { + const [copied, setCopied] = useState(false); + const timerRef = useRef>(); + + const handleCopy = useCallback(() => { + const text = getMessageText(); + if (!text) return; + navigator.clipboard.writeText(text).then(() => { + setCopied(true); + if (timerRef.current) clearTimeout(timerRef.current); + timerRef.current = setTimeout(() => setCopied(false), 2000); + }); + }, [getMessageText]); + + if (typeof navigator === 'undefined' || !navigator.clipboard) return null; + + return ( +
    + +
    + ); +}); diff --git a/frontends/desktop/src/components/chat/Thread/AssistantMessage.tsx b/frontends/desktop/src/components/chat/Thread/AssistantMessage.tsx new file mode 100644 index 000000000..88ea5add7 --- /dev/null +++ b/frontends/desktop/src/components/chat/Thread/AssistantMessage.tsx @@ -0,0 +1,45 @@ +import { memo, useCallback, useMemo, useRef } from 'react'; +import type { Message } from '../../../services/chat'; +import { parseAgentContent, ParsedSegment } from '../agentProtocol'; +import { MessageParts } from './parts'; +import { AssistantActionBar } from './AssistantActionBar'; + +interface Props { + message: Message; + isStreaming: boolean; +} + +export const AssistantMessage = memo(function AssistantMessage({ message, isStreaming }: Props) { + const segments = useMemo(() => { + const turnSegs = message.turn_segs; + if (turnSegs && turnSegs.length > 0) { + return turnSegs.flatMap((seg) => parseAgentContent(seg)); + } + return parseAgentContent(message.content); + }, [message.content, message.turn_segs]); + + const segmentsRef = useRef(segments); + segmentsRef.current = segments; + + const getMessageText = useCallback(() => { + const segs = segmentsRef.current; + const texts: string[] = []; + for (const seg of segs) { + if (seg.type === 'prose' || seg.type === 'summary') { + texts.push(seg.content); + } + } + return texts.join('\n\n'); + }, []); + + return ( +
    + + +
    + ); +}); diff --git a/frontends/desktop/src/components/chat/Thread/InlineError.tsx b/frontends/desktop/src/components/chat/Thread/InlineError.tsx new file mode 100644 index 000000000..79ea33de5 --- /dev/null +++ b/frontends/desktop/src/components/chat/Thread/InlineError.tsx @@ -0,0 +1,19 @@ +import { memo } from 'react'; +import { useI18n } from '../../../i18n'; +import { summarizeError } from '../../../lib/error-summary'; + +interface Props { + error: string; + msgId: string; +} + +export const InlineError = memo(function InlineError({ error, msgId }: Props) { + const { t } = useI18n(); + const display = summarizeError(error, t); + + return ( + + ); +}); diff --git a/frontends/desktop/src/components/chat/Thread/MessageList.tsx b/frontends/desktop/src/components/chat/Thread/MessageList.tsx new file mode 100644 index 000000000..bfc1ef847 --- /dev/null +++ b/frontends/desktop/src/components/chat/Thread/MessageList.tsx @@ -0,0 +1,113 @@ +import { memo, useMemo, useRef, useLayoutEffect } from 'react'; +import type { Message } from '../../../services/chat'; +import { buildThreadGroups, type ThreadGroup } from '../../../lib/thread-grouping'; +import { TurnPair } from './TurnPair'; +import { UserMessage } from './UserMessage'; +import { InlineError } from './InlineError'; + +const RENDER_BUDGET = 300; + +interface Props { + messages: Message[]; + isRunning: boolean; + budgetMultiplier: number; + onShowEarlier: () => void; + scrollRef: React.RefObject; +} + +function getGroupPartCount(group: ThreadGroup): number { + if (group.kind === 'turn') { + return group.turns.reduce((sum, t) => sum + t.segments.length, 0); + } + return 1; +} + +export const MessageList = memo(function MessageList({ + messages, + isRunning, + budgetMultiplier, + onShowEarlier, + scrollRef, +}: Props) { + const groups = useMemo(() => buildThreadGroups(messages), [messages]); + const savedDistanceRef = useRef(null); + + // Compute cutoff index + const cutoffIndex = useMemo(() => { + if (!isFinite(budgetMultiplier)) return 0; + const totalBudget = RENDER_BUDGET * budgetMultiplier; + let accumulated = 0; + for (let i = groups.length - 1; i >= 0; i--) { + accumulated += getGroupPartCount(groups[i]); + if (accumulated > totalBudget) { + return i + 1; + } + } + return 0; + }, [groups, budgetMultiplier]); + + const visibleGroups = useMemo(() => groups.slice(cutoffIndex), [groups, cutoffIndex]); + const hiddenCount = cutoffIndex; + + // Scroll position restore after expanding earlier messages + useLayoutEffect(() => { + if (savedDistanceRef.current !== null && scrollRef?.current) { + scrollRef.current.scrollTop = scrollRef.current.scrollHeight - savedDistanceRef.current; + savedDistanceRef.current = null; + } + }); + + const handleShowEarlier = () => { + const viewport = scrollRef?.current; + if (viewport) { + savedDistanceRef.current = viewport.scrollHeight - viewport.scrollTop; + } + onShowEarlier(); + }; + + if (messages.length === 0) { + return ( +
    +

    Send a message to begin.

    +
    + ); + } + + return ( + <> + {hiddenCount > 0 && ( + + )} + {visibleGroups.map((group, i) => { + const globalIndex = cutoffIndex + i; + if (group.kind === 'turn') { + return ( + + ); + } + if (group.msg.role === 'user') { + return ( +
    + +
    + ); + } + if (group.msg.role === 'error') { + return ; + } + return ( +
    + {group.msg.content} +
    + ); + })} + + ); +}); diff --git a/frontends/desktop/src/components/chat/Thread/StreamIndicators.tsx b/frontends/desktop/src/components/chat/Thread/StreamIndicators.tsx new file mode 100644 index 000000000..03cfea8db --- /dev/null +++ b/frontends/desktop/src/components/chat/Thread/StreamIndicators.tsx @@ -0,0 +1,68 @@ +import { memo, useState, useEffect, useRef } from 'react'; + +function formatElapsed(ms: number): string { + const s = Math.floor(ms / 1000); + if (s < 60) return `${s}s`; + const m = Math.floor(s / 60); + return `${m}m ${s % 60}s`; +} + +export const ResponseLoadingIndicator = memo(function ResponseLoadingIndicator() { + const [elapsed, setElapsed] = useState(0); + const startRef = useRef(Date.now()); + + useEffect(() => { + const id = setInterval(() => setElapsed(Date.now() - startRef.current), 1000); + return () => clearInterval(id); + }, []); + + return ( +
    + + {formatElapsed(elapsed)} +
    + ); +}); + +interface StallProps { + contentLength: number; +} + +export const StreamStallIndicator = memo(function StreamStallIndicator({ contentLength }: StallProps) { + const [show, setShow] = useState(false); + const [stallElapsed, setStallElapsed] = useState(0); + const lastLengthRef = useRef(contentLength); + const lastChangeRef = useRef(Date.now()); + const stallStartRef = useRef(null); + + useEffect(() => { + if (contentLength !== lastLengthRef.current) { + lastLengthRef.current = contentLength; + lastChangeRef.current = Date.now(); + stallStartRef.current = null; + setShow(false); + setStallElapsed(0); + } + }, [contentLength]); + + useEffect(() => { + const id = setInterval(() => { + const sinceChange = Date.now() - lastChangeRef.current; + if (sinceChange >= 2000) { + if (!stallStartRef.current) stallStartRef.current = lastChangeRef.current + 2000; + setShow(true); + setStallElapsed(Date.now() - stallStartRef.current); + } + }, 500); + return () => clearInterval(id); + }, []); + + if (!show) return null; + + return ( +
    + + +{formatElapsed(stallElapsed)} +
    + ); +}); diff --git a/frontends/desktop/src/components/chat/Thread/ThreadContent.tsx b/frontends/desktop/src/components/chat/Thread/ThreadContent.tsx new file mode 100644 index 000000000..19d176692 --- /dev/null +++ b/frontends/desktop/src/components/chat/Thread/ThreadContent.tsx @@ -0,0 +1,13 @@ +import type { ReactNode } from 'react'; + +interface Props { + children: ReactNode; +} + +export function ThreadContent({ children }: Props) { + return ( +
    + {children} +
    + ); +} diff --git a/frontends/desktop/src/components/chat/Thread/TurnPair.tsx b/frontends/desktop/src/components/chat/Thread/TurnPair.tsx new file mode 100644 index 000000000..b64604b86 --- /dev/null +++ b/frontends/desktop/src/components/chat/Thread/TurnPair.tsx @@ -0,0 +1,19 @@ +import { memo } from 'react'; +import type { Message } from '../../../services/chat'; +import { UserMessage } from './UserMessage'; +import { AssistantMessage } from './AssistantMessage'; + +interface Props { + userMsg: Message; + assistantMsg: Message; + isStreaming: boolean; +} + +export const TurnPair = memo(function TurnPair({ userMsg, assistantMsg, isStreaming }: Props) { + return ( +
    + + +
    + ); +}); diff --git a/frontends/desktop/src/components/chat/Thread/UserMessage.tsx b/frontends/desktop/src/components/chat/Thread/UserMessage.tsx new file mode 100644 index 000000000..a87a9d437 --- /dev/null +++ b/frontends/desktop/src/components/chat/Thread/UserMessage.tsx @@ -0,0 +1,140 @@ +import { memo, useCallback, useRef, useState, useLayoutEffect } from 'react'; +import { matchSkillPrefix } from '../Composer/skills'; +import { BRIDGE_BASE } from '../../../services/constants'; + +function fmtSize(bytes?: number): string { + if (!bytes) return ''; + if (bytes < 1024) return `${bytes} B`; + if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`; + return `${(bytes / (1024 * 1024)).toFixed(1)} MB`; +} + +function iconForExt(name: string): string { + const ext = name.split('.').pop()?.toLowerCase() || ''; + if (['js', 'ts', 'tsx', 'jsx', 'py', 'rs', 'go', 'c', 'cpp', 'java'].includes(ext)) return '◇'; + if (['json', 'yaml', 'yml', 'toml', 'xml'].includes(ext)) return '{}'; + if (['md', 'txt', 'log', 'csv'].includes(ext)) return '¶'; + if (['pdf'].includes(ext)) return '⊞'; + return '◎'; +} + +function CopyButton({ text }: { text: string }) { + const [copied, setCopied] = useState(false); + const timerRef = useRef>(); + + const handleCopy = useCallback((e: React.MouseEvent) => { + e.stopPropagation(); + navigator.clipboard.writeText(text).then(() => { + setCopied(true); + if (timerRef.current) clearTimeout(timerRef.current); + timerRef.current = setTimeout(() => setCopied(false), 2000); + }); + }, [text]); + + if (typeof navigator === 'undefined' || !navigator.clipboard) return null; + + return ( + + ); +} + +interface Props { + content: string; + msgId?: string; + images?: { name: string; path: string }[]; + files?: { name: string; path: string; size?: number }[]; +} + +export const UserMessage = memo(function UserMessage({ content, msgId, images, files }: Props) { + const textRef = useRef(null); + const [clamped, setClamped] = useState(false); + const [expanded, setExpanded] = useState(false); + const expandedRef = useRef(false); + expandedRef.current = expanded; + + useLayoutEffect(() => { + const el = textRef.current; + if (!el) return; + const observer = new ResizeObserver(() => { + if (!expandedRef.current) { + setClamped(el.scrollHeight > el.clientHeight + 2); + } + }); + observer.observe(el); + return () => observer.disconnect(); + }, []); + + if (!content && (!images || images.length === 0) && (!files || files.length === 0)) return null; + + const skill = matchSkillPrefix(content); + + return ( + <> + {images && images.length > 0 && ( +
    + {images.map((img, i) => ( + {img.name} + ))} +
    + )} + {files && files.length > 0 && ( +
    + {files.map((f, i) => ( +
    + {iconForExt(f.name)} + {f.name} + {f.size != null && f.size > 0 && {fmtSize(f.size)}} +
    + ))} +
    + )} +
    +
    + +
    + {skill ? ( + <> + /{skill.id} + {skill.rest && <> {skill.rest}} + + ) : ( + content + )} +
    + {clamped && ( + + )} +
    +
    + + ); +}); diff --git a/frontends/desktop/src/components/chat/Thread/UserTurnRail.css b/frontends/desktop/src/components/chat/Thread/UserTurnRail.css new file mode 100644 index 000000000..b96854031 --- /dev/null +++ b/frontends/desktop/src/components/chat/Thread/UserTurnRail.css @@ -0,0 +1,144 @@ +/* ─── User Turn Rail ─── */ + +/* + * Layout model: + * - nav (user-turn-rail): absolute positioned in thread-root, pointer-events: none + * - rail-hitarea: the interactive zone, pointer-events: auto + * - rail-marks: always visible vertical tick column + * - rail-panel: absolute, appears on hover to the left of marks + * + * Hover stability: the hitarea uses a ::before pseudo-element as an invisible + * bridge between the panel and marks so the mouse doesn't leave the interactive + * zone while traveling between them. + */ + +[data-slot="user-turn-rail"] { + position: absolute; + right: 0; + top: 50%; + transform: translateY(-50%); + z-index: 100; + pointer-events: none; +} + +[data-slot="rail-hitarea"] { + position: relative; + display: flex; + align-items: center; + justify-content: flex-end; + padding: 0.5rem; + pointer-events: auto; +} + +/* Hover bridge: invisible area extending left to cover panel gap */ +[data-slot="user-turn-rail"][data-expanded] [data-slot="rail-hitarea"]::before { + content: ''; + position: absolute; + top: 0; + bottom: 0; + right: 0; + left: -260px; + pointer-events: auto; +} + +/* Mark column */ +[data-slot="rail-marks"] { + display: flex; + flex-direction: column; + align-items: flex-end; + gap: 0.25rem; +} + +[data-slot="user-turn-rail"][data-expanded] [data-slot="rail-marks"] { + visibility: hidden; +} + +[data-slot="rail-mark"] { + width: 2.5rem; + height: 0.5rem; + display: flex; + align-items: center; + justify-content: flex-end; + border: none; + padding: 0; + margin: 0; + background: transparent; + cursor: pointer; +} + +[data-slot="rail-mark-line"] { + width: 1rem; + height: 2px; + border-radius: 999px; + background: var(--semi-color-fill-2); + transition: background-color 120ms ease; +} + +[data-slot="rail-mark"][data-active] [data-slot="rail-mark-line"] { + background: var(--semi-color-text-0); +} + +/* Expanded panel */ +[data-slot="rail-panel"] { + position: absolute; + right: calc(100% - 0.5rem); + top: 50%; + transform: translateY(-50%); + display: flex; + flex-direction: column; + gap: 1px; + max-width: 240px; + min-width: 140px; + padding: 0.25rem; + border-radius: 0.5rem; + background: var(--semi-color-bg-3, #2a2a2a); + box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15); + opacity: 0; + pointer-events: none; + transition: opacity 120ms ease; +} + +[data-slot="user-turn-rail"][data-expanded] [data-slot="rail-panel"] { + opacity: 1; + pointer-events: auto; +} + +[data-slot="rail-panel-item"] { + display: block; + width: 100%; + padding: 0.3rem 0.5rem; + border: none; + border-radius: 0.25rem; + background: transparent; + color: var(--semi-color-text-2); + font-size: 0.75rem; + line-height: 1.4; + text-align: left; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + cursor: pointer; + transition: background-color 100ms ease; +} + +[data-slot="rail-panel-item"]:hover, +[data-slot="rail-panel-item"][data-active] { + background: var(--semi-color-fill-1); + color: var(--semi-color-text-0); +} + +/* Focus ring */ +[data-slot="rail-mark"]:focus-visible [data-slot="rail-mark-line"] { + box-shadow: 0 0 0 2px var(--semi-color-primary-light-default, rgba(0, 100, 250, 0.2)); +} + +[data-slot="rail-mark"]:focus-visible { + outline: none; +} + +/* Hide on narrow viewports where there's no gutter */ +@media (max-width: 900px) { + [data-slot="user-turn-rail"] { + display: none; + } +} diff --git a/frontends/desktop/src/components/chat/Thread/UserTurnRail.tsx b/frontends/desktop/src/components/chat/Thread/UserTurnRail.tsx new file mode 100644 index 000000000..d7725ead2 --- /dev/null +++ b/frontends/desktop/src/components/chat/Thread/UserTurnRail.tsx @@ -0,0 +1,189 @@ +import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import type { Message } from '../../../services/chat'; +import './UserTurnRail.css'; + +const MIN_TURNS = 3; +const MAX_PREVIEW_CHARS = 40; +const JUMP_DURATION = 170; +const SCROLL_TOP_MARGIN = 12; + +interface Props { + messages: Message[]; + stopScroll: () => void; + onJumpToCollapsed: (msgId: string) => void; +} + +interface UserTurn { + id: string; + content: string; +} + +function previewText(content: string): string { + const normalized = content.replace(/\s+/g, ' ').trim(); + return normalized.length <= MAX_PREVIEW_CHARS + ? normalized + : normalized.slice(0, MAX_PREVIEW_CHARS) + '…'; +} + +function easeOutCubic(t: number): number { + return 1 - Math.pow(1 - t, 3); +} + +let jumpRaf = 0; + +function jumpScroll(el: HTMLElement, targetTop: number, duration: number) { + cancelAnimationFrame(jumpRaf); + const start = el.scrollTop; + const diff = targetTop - start; + if (Math.abs(diff) < 1) return; + const startTime = performance.now(); + + function step(now: number) { + const elapsed = now - startTime; + const t = Math.min(elapsed / duration, 1); + el.scrollTop = start + diff * easeOutCubic(t); + if (t < 1) jumpRaf = requestAnimationFrame(step); + } + jumpRaf = requestAnimationFrame(step); +} + +export const UserTurnRail = memo(function UserTurnRail({ messages, stopScroll, onJumpToCollapsed }: Props) { + const userTurns: UserTurn[] = useMemo( + () => messages + .filter((m) => m.role === 'user') + .map((m) => ({ id: m.id, content: m.content })), + [messages], + ); + + const [activeId, setActiveId] = useState(null); + const [hovered, setHovered] = useState(false); + const leaveTimer = useRef | null>(null); + const scrollRaf = useRef(0); + + const handleMouseEnter = useCallback(() => { + if (leaveTimer.current) { + clearTimeout(leaveTimer.current); + leaveTimer.current = null; + } + setHovered(true); + }, []); + + const handleMouseLeave = useCallback(() => { + leaveTimer.current = setTimeout(() => { + setHovered(false); + leaveTimer.current = null; + }, 150); + }, []); + + // Scroll-based active tracking: find the last user message whose top is at or above viewport top. + useEffect(() => { + if (userTurns.length < MIN_TURNS) return; + + const viewport = document.querySelector('[data-slot="aui_thread-viewport"]'); + if (!viewport) return; + + function updateActive() { + scrollRaf.current = 0; + if (!viewport) return; + + const vpTop = viewport.getBoundingClientRect().top; + let bestId: string | null = null; + + for (const turn of userTurns) { + const el = document.getElementById(`msg-${turn.id}`); + if (!el) continue; + const elTop = el.getBoundingClientRect().top - vpTop; + // Pick the last user message whose top edge is within SCROLL_TOP_MARGIN of viewport top + if (elTop <= SCROLL_TOP_MARGIN) { + bestId = turn.id; + } else { + break; + } + } + + // If nothing qualifies (user hasn't scrolled past any), pick the first + if (!bestId && userTurns.length > 0) { + bestId = userTurns[0].id; + } + + if (bestId) setActiveId(bestId); + } + + function onScroll() { + if (!scrollRaf.current) { + scrollRaf.current = requestAnimationFrame(updateActive); + } + } + + viewport.addEventListener('scroll', onScroll, { passive: true }); + // Initial calculation + updateActive(); + + return () => { + viewport.removeEventListener('scroll', onScroll); + cancelAnimationFrame(scrollRaf.current); + }; + }, [userTurns]); + + const handleJump = useCallback((id: string) => { + const viewport = document.querySelector('[data-slot="aui_thread-viewport"]'); + const el = document.getElementById(`msg-${id}`); + + if (!el) { + onJumpToCollapsed(id); + return; + } + + if (!viewport) return; + stopScroll(); + + // Use the turn-pair container's offsetTop to avoid sticky positioning offset + const turnPair = el.closest('[data-slot="aui_turn-pair"]'); + const scrollTarget = turnPair || el; + const target = scrollTarget.offsetTop - SCROLL_TOP_MARGIN; + jumpScroll(viewport, target, JUMP_DURATION); + }, [stopScroll, onJumpToCollapsed]); + + if (userTurns.length < MIN_TURNS) return null; + + return ( + + ); +}); diff --git a/frontends/desktop/src/components/chat/Thread/index.tsx b/frontends/desktop/src/components/chat/Thread/index.tsx new file mode 100644 index 000000000..7fec6b698 --- /dev/null +++ b/frontends/desktop/src/components/chat/Thread/index.tsx @@ -0,0 +1,95 @@ +import { useCallback, useRef, useState, useEffect } from 'react'; +import { useChatStore } from '../../../stores/chat'; +import { useStickToBottom, useSessionScrollStability } from '../../../hooks/useStickToBottom'; +import { ThreadContent } from './ThreadContent'; +import { MessageList } from './MessageList'; +import { UserTurnRail } from './UserTurnRail'; +import './thread.css'; + +export function Thread() { + const { messages, status, activeSessionId } = useChatStore(); + const { scrollRef, isAtBottom, scrollToBottom, stopScroll } = useStickToBottom(); + const [budgetMultiplier, setBudgetMultiplier] = useState(1); + const pendingJumpRef = useRef(null); + + useSessionScrollStability(scrollRef, scrollToBottom, stopScroll, activeSessionId); + + // Reset budget when session changes + useEffect(() => { + setBudgetMultiplier(1); + pendingJumpRef.current = null; + }, [activeSessionId]); + + // After budget expands and DOM updates, execute pending jump + useEffect(() => { + if (!pendingJumpRef.current) return; + const id = pendingJumpRef.current; + + // Wait a frame for DOM to render newly expanded messages + const raf = requestAnimationFrame(() => { + const el = document.getElementById(`msg-${id}`); + if (el) { + pendingJumpRef.current = null; + const viewport = scrollRef.current; + if (viewport) { + const turnPair = el.closest('[data-slot="aui_turn-pair"]'); + const scrollTarget = turnPair || el; + viewport.scrollTop = scrollTarget.offsetTop - 12; + } + } + }); + return () => cancelAnimationFrame(raf); + }, [budgetMultiplier, scrollRef]); + + const expandAllMessages = useCallback(() => { + setBudgetMultiplier(Infinity); + }, []); + + const requestJumpToCollapsed = useCallback((msgId: string) => { + pendingJumpRef.current = msgId; + expandAllMessages(); + }, [expandAllMessages]); + + const handleShowEarlier = useCallback(() => { + const viewport = scrollRef.current; + if (viewport) { + // MessageList will restore scroll via its own layout effect + } + setBudgetMultiplier(m => m + 1); + }, [scrollRef]); + + return ( +
    +
    + + +
    + +
    + + + + {!isAtBottom && ( + + )} +
    + ); +} diff --git a/frontends/desktop/src/components/chat/Thread/parts/ApprovalPart.tsx b/frontends/desktop/src/components/chat/Thread/parts/ApprovalPart.tsx new file mode 100644 index 000000000..800e09919 --- /dev/null +++ b/frontends/desktop/src/components/chat/Thread/parts/ApprovalPart.tsx @@ -0,0 +1,238 @@ +import { memo, useState, useCallback, useEffect, useRef } from 'react'; +import { useChatStore } from '../../../../stores/chat'; +import './approvalPart.css'; + +interface Props { + question: string; + candidates: string[]; +} + +/* ─── Badge letter helper ─── */ +function badgeLetter(index: number): string | null { + return index < 26 ? String.fromCharCode(65 + index) : null; // A-Z +} + +/* ─── Settled view (after user responded) ─── */ +function ApprovalSettled({ question, answer }: { question: string; answer: string | null }) { + return ( +
    +
    {question}
    +
    + {answer ? answer : Skipped} +
    +
    + ); +} + +/* ─── Main component ─── */ +export const ApprovalPart = memo(function ApprovalPart({ question, candidates }: Props) { + const sendMessage = useChatStore((s) => s.sendMessage); + + // State + const [selectedChoice, setSelectedChoice] = useState(null); + const [draft, setDraft] = useState(''); + const [submitting, setSubmitting] = useState(false); + const [responded, setResponded] = useState(false); + const [respondedAnswer, setRespondedAnswer] = useState(null); + + const otherRef = useRef(null); + const cardRef = useRef(null); + + // Derived + const pendingAnswer = selectedChoice ?? (draft.trim() || null); + const hasCandidates = candidates.length > 0; + + /* ─── Actions ─── */ + const selectChoice = useCallback((choice: string) => { + setSelectedChoice(choice); + setDraft(''); + }, []); + + const submitAnswer = useCallback(async (answer: string) => { + if (submitting || responded) return; + setSubmitting(true); + await sendMessage(answer); + setRespondedAnswer(answer); + setResponded(true); + setSubmitting(false); + }, [submitting, responded, sendMessage]); + + const handleSkip = useCallback(async () => { + if (submitting || responded) return; + setSubmitting(true); + await sendMessage(''); + setRespondedAnswer(null); + setResponded(true); + setSubmitting(false); + }, [submitting, responded, sendMessage]); + + const handleConfirm = useCallback(() => { + if (pendingAnswer !== null) { + submitAnswer(pendingAnswer); + } + }, [pendingAnswer, submitAnswer]); + + /* ─── Other textarea handlers ─── */ + const handleOtherFocus = useCallback(() => { + setSelectedChoice(null); + }, []); + + const handleOtherChange = useCallback((e: React.ChangeEvent) => { + setDraft(e.target.value); + setSelectedChoice(null); + }, []); + + const handleOtherKeyDown = useCallback((e: React.KeyboardEvent) => { + if (e.nativeEvent.isComposing || e.keyCode === 229) return; + if (e.key === 'Enter' && !e.shiftKey) { + e.preventDefault(); + const trimmed = draft.trim(); + if (trimmed) { + submitAnswer(trimmed); + } + } + }, [draft, submitAnswer]); + + /* ─── Global keyboard shortcuts ─── */ + useEffect(() => { + if (responded || submitting) return; + + function handleKeyDown(e: KeyboardEvent) { + if (e.metaKey || e.ctrlKey || e.altKey || e.defaultPrevented) return; + + const active = document.activeElement; + if (active) { + const tag = active.tagName.toLowerCase(); + if (tag === 'input' || tag === 'textarea' || (active as HTMLElement).isContentEditable) { + return; + } + } + + const key = e.key.toLowerCase(); + + // Letter key a-z + if (key.length === 1 && key >= 'a' && key <= 'z') { + const index = key.charCodeAt(0) - 97; // 0-25 + if (index < candidates.length) { + e.preventDefault(); + selectChoice(candidates[index]); + } else if (index === candidates.length) { + // Focus "Other" textarea + e.preventDefault(); + otherRef.current?.focus(); + } + return; + } + + // Enter to confirm + if (key === 'enter' && !e.shiftKey) { + const currentAnswer = selectedChoice ?? (draft.trim() || null); + if (currentAnswer !== null) { + e.preventDefault(); + submitAnswer(currentAnswer); + } + } + } + + window.addEventListener('keydown', handleKeyDown); + return () => window.removeEventListener('keydown', handleKeyDown); + }, [responded, submitting, candidates, selectedChoice, draft, selectChoice, submitAnswer]); + + /* ─── Render ─── */ + if (responded) { + return ; + } + + // Badge index for "Other" row + const otherBadgeIndex = candidates.length; + const otherBadge = badgeLetter(otherBadgeIndex); + const otherActive = draft.trim().length > 0 && selectedChoice === null; + + return ( +
    +
    {question}
    + + {hasCandidates ? ( +
    + {candidates.map((c, i) => { + const letter = badgeLetter(i); + const isSelected = selectedChoice === c; + return ( + + ); + })} + {/* Other row */} +
    + {otherBadge && ( + + {otherBadge} + + )} +