From 7107f20e758bae4e50ac3ae6b791b5027783c425 Mon Sep 17 00:00:00 2001 From: hcyang Date: Thu, 9 Jul 2026 15:13:24 +0800 Subject: [PATCH 01/51] =?UTF-8?q?feat(vscode-ide-companion):=20=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E5=8C=96VSCode=E6=8F=92=E4=BB=B6=E6=A0=B8=E5=BF=83web?= =?UTF-8?q?view=E5=8F=8A=E7=9B=B8=E5=85=B3UI=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增App主视图及其子组件,构建聊天功能框架 - 实现问答交互组件AskUserQuestion,支持单选、多选及文本输入 - 开发AssistantBubble气泡组件,支持内容显示及复制 - 添加基础UI元素组件:按钮、卡片、勾选框、徽章及折叠面板 - 实现命令面板组件,包含输入、列表、分组及空状态处理 - 创建聊天状态管理上下文ChatProvider,集成RPC通信及消息处理 - 配置编辑器和忽略文件以符合项目规范和构建需求 - 增加气泡装饰点BubbleDot组件,用于消息列表美化展示 --- .editorconfig | 12 + .gitignore | 3 +- .vscode/launch.json | 16 + .vscode/tasks.json | 51 + package-lock.json | 7932 ++++++++++++++++- .../vscode-ide-companion/.vscode/launch.json | 16 + .../vscode-ide-companion/.vscode/tasks.json | 42 + packages/vscode-ide-companion/.vscodeignore | 12 + packages/vscode-ide-companion/README.md | 94 - packages/vscode-ide-companion/README_cn.md | 94 - packages/vscode-ide-companion/README_en.md | 87 - .../{resources => assets}/deepcoding_icon.png | Bin .../{resources => assets}/deepcoding_icon.svg | 0 .../vscode-ide-companion/assets/theme.svg | 1 + packages/vscode-ide-companion/components.json | 25 + .../vscode-ide-companion/esbuild.config.mjs | 49 + .../vscode-ide-companion/eslint.config.mjs | 38 + packages/vscode-ide-companion/package.json | 91 +- .../resources/deepcode_screenshot.png | Bin 357519 -> 0 bytes .../vscode-ide-companion/resources/faq1.gif | Bin 186246 -> 0 bytes .../resources/prompt-attachments.js | 293 - .../resources/webview.css | 1605 ---- .../resources/webview.html | 2354 ----- .../scripts/copy-templates.js | 28 + .../src/extension.test.ts | 144 + .../vscode-ide-companion/src/extension.ts | 513 +- .../src/getWebviewContent.ts | 128 + packages/vscode-ide-companion/src/provider.ts | 323 - packages/vscode-ide-companion/src/router.ts | 255 + .../src/tests/extension-utils.test.ts | 132 - .../src/tests/extension.test.ts | 477 - .../src/tests/prompt-attachments.test.ts | 240 - .../src/tests/run-tests.mjs | 15 - .../vscode-ide-companion/src/tests/setup.ts | 97 + .../vscode-ide-companion/src/webview/App.tsx | 58 + .../webview/components/AskUserQuestion.tsx | 227 + .../src/webview/components/Composer.test.tsx | 244 + .../src/webview/components/Composer.tsx | 213 + .../src/webview/components/ContextMeter.tsx | 76 + .../src/webview/components/DiffPreview.tsx | 70 + .../webview/components/ErrorBoundary.test.tsx | 164 + .../src/webview/components/ErrorBoundary.tsx | 50 + .../src/webview/components/Header.tsx | 108 + .../src/webview/components/Messages.test.tsx | 103 + .../src/webview/components/Messages.tsx | 67 + .../src/webview/components/ModeToggle.tsx | 31 + .../components/NetworkStatusIndicator.tsx | 22 + .../components/PermissionPrompt.test.tsx | 186 + .../webview/components/PermissionPrompt.tsx | 295 + .../src/webview/components/PlanRenderer.tsx | 88 + .../webview/components/SessionList.test.tsx | 164 + .../src/webview/components/SessionList.tsx | 136 + .../src/webview/components/SkillsPanel.tsx | 65 + .../src/webview/components/SkillsTags.tsx | 31 + .../webview/components/ThinkingLiveBubble.tsx | 63 + .../components/bubbles/AssistantBubble.tsx | 56 + .../webview/components/bubbles/BubbleDot.tsx | 30 + .../components/bubbles/SystemBubble.tsx | 36 + .../components/bubbles/ThinkingBubble.tsx | 35 + .../webview/components/bubbles/ToolBubble.tsx | 94 + .../webview/components/bubbles/UserBubble.tsx | 52 + .../src/webview/components/markdown/index.css | 223 + .../src/webview/components/markdown/index.tsx | 381 + .../src/webview/components/ui/badge.tsx | 42 + .../src/webview/components/ui/button.tsx | 66 + .../src/webview/components/ui/card.tsx | 70 + .../src/webview/components/ui/checkbox.tsx | 27 + .../src/webview/components/ui/collapsible.tsx | 16 + .../src/webview/components/ui/command.tsx | 151 + .../src/webview/components/ui/dialog.tsx | 132 + .../src/webview/components/ui/drawer.tsx | 102 + .../webview/components/ui/dropdown-menu.tsx | 236 + .../src/webview/components/ui/empty.tsx | 87 + .../src/webview/components/ui/field.tsx | 216 + .../src/webview/components/ui/hover-card.tsx | 36 + .../src/webview/components/ui/input-group.tsx | 135 + .../src/webview/components/ui/input.tsx | 19 + .../src/webview/components/ui/item.tsx | 173 + .../src/webview/components/ui/label.tsx | 19 + .../src/webview/components/ui/popover.tsx | 54 + .../webview/components/ui/progress-ring.tsx | 135 + .../src/webview/components/ui/progress.tsx | 22 + .../src/webview/components/ui/radio-group.tsx | 30 + .../src/webview/components/ui/scroll-area.tsx | 45 + .../src/webview/components/ui/separator.tsx | 26 + .../src/webview/components/ui/sonner.tsx | 38 + .../src/webview/components/ui/spinner.tsx | 16 + .../src/webview/components/ui/tabs.tsx | 74 + .../src/webview/components/ui/textarea.tsx | 18 + .../src/webview/components/ui/tooltip.tsx | 42 + .../src/webview/context/ChatProvider.test.tsx | 860 ++ .../src/webview/context/ChatProvider.tsx | 362 + .../src/webview/context/ThemeProvider.tsx | 132 + .../src/webview/context/index.ts | 3 + .../webview/hooks/useNetworkStatus.test.ts | 118 + .../src/webview/hooks/useNetworkStatus.ts | 19 + .../src/webview/index.css | 159 + .../src/webview/index.html | 12 + .../src/webview/lib/utils.test.ts | 56 + .../src/webview/lib/utils.ts | 6 + .../vscode-ide-companion/src/webview/main.tsx | 30 + .../src/webview/services/chatService.test.ts | 280 + .../src/webview/services/chatService.ts | 152 + .../src/webview/services/index.ts | 2 + .../vscode-ide-companion/src/webview/types.ts | 125 + .../src/webview/utils/index.ts | 101 + .../src/webview/utils/utils.test.ts | 233 + .../src/webview/vite-env.d.ts | 11 + .../vscode-ide-companion/src/webview/wrpc.ts | 56 + .../vscode-ide-companion/tsconfig.build.json | 21 - packages/vscode-ide-companion/tsconfig.json | 17 +- .../tsconfig.webview.json | 24 + packages/vscode-ide-companion/vite.config.ts | 34 + .../vscode-ide-companion/vitest.config.ts | 27 + 114 files changed, 16817 insertions(+), 6585 deletions(-) create mode 100644 .editorconfig create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json create mode 100644 packages/vscode-ide-companion/.vscode/launch.json create mode 100644 packages/vscode-ide-companion/.vscode/tasks.json create mode 100644 packages/vscode-ide-companion/.vscodeignore delete mode 100644 packages/vscode-ide-companion/README.md delete mode 100644 packages/vscode-ide-companion/README_cn.md delete mode 100644 packages/vscode-ide-companion/README_en.md rename packages/vscode-ide-companion/{resources => assets}/deepcoding_icon.png (100%) rename packages/vscode-ide-companion/{resources => assets}/deepcoding_icon.svg (100%) create mode 100644 packages/vscode-ide-companion/assets/theme.svg create mode 100644 packages/vscode-ide-companion/components.json create mode 100644 packages/vscode-ide-companion/esbuild.config.mjs create mode 100644 packages/vscode-ide-companion/eslint.config.mjs delete mode 100644 packages/vscode-ide-companion/resources/deepcode_screenshot.png delete mode 100644 packages/vscode-ide-companion/resources/faq1.gif delete mode 100644 packages/vscode-ide-companion/resources/prompt-attachments.js delete mode 100644 packages/vscode-ide-companion/resources/webview.css delete mode 100644 packages/vscode-ide-companion/resources/webview.html create mode 100644 packages/vscode-ide-companion/scripts/copy-templates.js create mode 100644 packages/vscode-ide-companion/src/extension.test.ts create mode 100644 packages/vscode-ide-companion/src/getWebviewContent.ts delete mode 100644 packages/vscode-ide-companion/src/provider.ts create mode 100644 packages/vscode-ide-companion/src/router.ts delete mode 100644 packages/vscode-ide-companion/src/tests/extension-utils.test.ts delete mode 100644 packages/vscode-ide-companion/src/tests/extension.test.ts delete mode 100644 packages/vscode-ide-companion/src/tests/prompt-attachments.test.ts delete mode 100644 packages/vscode-ide-companion/src/tests/run-tests.mjs create mode 100644 packages/vscode-ide-companion/src/tests/setup.ts create mode 100644 packages/vscode-ide-companion/src/webview/App.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/AskUserQuestion.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/Composer.test.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/Composer.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ContextMeter.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/DiffPreview.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ErrorBoundary.test.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ErrorBoundary.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/Header.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/Messages.test.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/Messages.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ModeToggle.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/NetworkStatusIndicator.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/PermissionPrompt.test.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/PermissionPrompt.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/PlanRenderer.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/SessionList.test.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/SessionList.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/SkillsPanel.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/SkillsTags.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ThinkingLiveBubble.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/bubbles/AssistantBubble.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/bubbles/BubbleDot.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/bubbles/SystemBubble.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/bubbles/ThinkingBubble.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/bubbles/ToolBubble.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/bubbles/UserBubble.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/markdown/index.css create mode 100644 packages/vscode-ide-companion/src/webview/components/markdown/index.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ui/badge.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ui/button.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ui/card.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ui/checkbox.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ui/collapsible.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ui/command.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ui/dialog.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ui/drawer.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ui/dropdown-menu.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ui/empty.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ui/field.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ui/hover-card.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ui/input-group.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ui/input.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ui/item.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ui/label.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ui/popover.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ui/progress-ring.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ui/progress.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ui/radio-group.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ui/scroll-area.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ui/separator.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ui/sonner.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ui/spinner.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ui/tabs.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ui/textarea.tsx create mode 100644 packages/vscode-ide-companion/src/webview/components/ui/tooltip.tsx create mode 100644 packages/vscode-ide-companion/src/webview/context/ChatProvider.test.tsx create mode 100644 packages/vscode-ide-companion/src/webview/context/ChatProvider.tsx create mode 100644 packages/vscode-ide-companion/src/webview/context/ThemeProvider.tsx create mode 100644 packages/vscode-ide-companion/src/webview/context/index.ts create mode 100644 packages/vscode-ide-companion/src/webview/hooks/useNetworkStatus.test.ts create mode 100644 packages/vscode-ide-companion/src/webview/hooks/useNetworkStatus.ts create mode 100644 packages/vscode-ide-companion/src/webview/index.css create mode 100644 packages/vscode-ide-companion/src/webview/index.html create mode 100644 packages/vscode-ide-companion/src/webview/lib/utils.test.ts create mode 100644 packages/vscode-ide-companion/src/webview/lib/utils.ts create mode 100644 packages/vscode-ide-companion/src/webview/main.tsx create mode 100644 packages/vscode-ide-companion/src/webview/services/chatService.test.ts create mode 100644 packages/vscode-ide-companion/src/webview/services/chatService.ts create mode 100644 packages/vscode-ide-companion/src/webview/services/index.ts create mode 100644 packages/vscode-ide-companion/src/webview/types.ts create mode 100644 packages/vscode-ide-companion/src/webview/utils/index.ts create mode 100644 packages/vscode-ide-companion/src/webview/utils/utils.test.ts create mode 100644 packages/vscode-ide-companion/src/webview/vite-env.d.ts create mode 100644 packages/vscode-ide-companion/src/webview/wrpc.ts delete mode 100644 packages/vscode-ide-companion/tsconfig.build.json create mode 100644 packages/vscode-ide-companion/tsconfig.webview.json create mode 100644 packages/vscode-ide-companion/vite.config.ts create mode 100644 packages/vscode-ide-companion/vitest.config.ts diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..8c52ff93 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore index 634aea11..f8ef22e3 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,6 @@ out/ # Editors .idea/ -.vscode/ *.tgz *.log *.vsix @@ -28,4 +27,4 @@ out/ packages/cli/src/generated/ packages/core/src/generated/ packages/vscode-ide-companion/*.vsix -packages/vscode-ide-companion/templates/ \ No newline at end of file +packages/vscode-ide-companion/templates/ diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..bc27e4de --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug VS Code Companion", + "type": "extensionHost", + "request": "launch", + "args": ["--extensionDevelopmentPath=${workspaceFolder}/packages/vscode-ide-companion"], + "outFiles": ["${workspaceFolder}/packages/vscode-ide-companion/dist/**/*.js"], + "preLaunchTask": "Dev: Webview Server", + "env": { + "NODE_OPTIONS": "--no-warnings" + } + } + ] +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000..11d6895c --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,51 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Dev: Webview Server", + "type": "npm", + "script": "dev:webview", + "path": "packages/vscode-ide-companion", + "isBackground": true, + "problemMatcher": { + "owner": "typescript", + "fileLocation": "relative", + "pattern": { + "regexp": "^$" + }, + "background": { + "activeOnStart": true, + "beginsPattern": ".*VITE.*", + "endsPattern": ".*ready in.*" + } + }, + "presentation": { + "reveal": "always", + "panel": "dedicated" + } + }, + { + "label": "Watch VS Code Companion", + "type": "npm", + "script": "watch", + "path": "packages/vscode-ide-companion", + "isBackground": true, + "problemMatcher": { + "owner": "typescript", + "fileLocation": "relative", + "pattern": { + "regexp": "^$" + }, + "background": { + "activeOnStart": true, + "beginsPattern": ".*Watching.*", + "endsPattern": ".*✅.*" + } + }, + "presentation": { + "reveal": "always", + "panel": "dedicated" + } + } + ] +} diff --git a/package-lock.json b/package-lock.json index 5c894763..11f6c016 100644 --- a/package-lock.json +++ b/package-lock.json @@ -53,6 +53,57 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/@asamuzakjp/css-color": { + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.11.tgz", + "integrity": "sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", + "@csstools/css-calc": "^3.2.0", + "@csstools/css-color-parser": "^4.1.0", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/dom-selector": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-7.1.1.tgz", + "integrity": "sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", + "@asamuzakjp/nwsapi": "^2.3.9", + "bidi-js": "^1.0.3", + "css-tree": "^3.2.1", + "is-potential-custom-element-name": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/generational-cache": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/generational-cache/-/generational-cache-1.0.1.tgz", + "integrity": "sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/nwsapi": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", + "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", + "dev": true, + "license": "MIT" + }, "node_modules/@azu/format-text": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@azu/format-text/-/format-text-1.0.2.tgz", @@ -256,7 +307,6 @@ "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" @@ -266,7 +316,6 @@ "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", @@ -297,7 +346,6 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.29.7", @@ -310,11 +358,22 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", + "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "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", @@ -327,21 +386,53 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz", + "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/traverse": "^7.29.7", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.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==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz", + "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "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==", - "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.29.7", @@ -355,7 +446,6 @@ "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", @@ -369,11 +459,61 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz", + "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.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==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz", + "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz", + "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "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==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -392,7 +532,6 @@ "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" @@ -402,7 +541,6 @@ "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", @@ -416,7 +554,6 @@ "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==", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.29.7" @@ -428,11 +565,104 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", + "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==", + "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-syntax-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", + "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", + "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-modules-commonjs": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz", + "integrity": "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.29.7.tgz", + "integrity": "sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/plugin-syntax-typescript": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.29.7.tgz", + "integrity": "sha512-/Foi8vKY2EVbed/1eZx0gJEEwHAIxogrySI7rULcRIvhZzbvoE/b5qG5Ghc0WKAFKOHA9SD1x7RsFlOYdutIiQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "@babel/plugin-syntax-jsx": "^7.29.7", + "@babel/plugin-transform-modules-commonjs": "^7.29.7", + "@babel/plugin-transform-typescript": "^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==", + "dev": true, + "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==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.7", @@ -447,7 +677,6 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.7", @@ -466,7 +695,6 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.29.7", @@ -476,81 +704,433 @@ "node": ">=6.9.0" } }, - "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" - ], + "node_modules/@bramus/specificity": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", + "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" + "dependencies": { + "css-tree": "^3.0.0" + }, + "bin": { + "specificity": "bin/cli.js" } }, - "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" - ], + "node_modules/@csstools/color-helpers": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.1.0.tgz", + "integrity": "sha512-064IFJdjTfUqnjpCVpMOdbr8FLQBhinbZj6yRv2An2E41O/pLEXqfFRWqGq/SxlE5PEUYTlvWsG2r8MswAVvkg==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } ], + "license": "MIT-0", "engines": { - "node": ">=18" + "node": ">=20.19.0" } }, - "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" - ], + "node_modules/@csstools/css-calc": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.2.1.tgz", + "integrity": "sha512-DtdHlgXh5ZkA43cwBcAm+huzgJiwx3ZTWVjBs94kwz2xKqSimDA3lBgCjphYgwgVUMWatSM0pDd8TILB1yrVVg==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } ], + "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" } }, - "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" - ], + "node_modules/@csstools/css-color-parser": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.1.9.tgz", + "integrity": "sha512-paQcIaOO53Rk5+YrBaBjm/SgrV4INImjo2BT1DtQRYr+XeTRbeAYlS+jxXp9drqvKmtFnWRJKIalDLhZZDu42A==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^6.1.0", + "@csstools/css-calc": "^3.2.1" + }, "engines": { - "node": ">=18" + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" } }, - "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" - ], + "node_modules/@csstools/css-parser-algorithms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-syntax-patches-for-csstree": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.6.tgz", + "integrity": "sha512-TcJCWFbXLPpJYq6z7bfOyjWYJDiDg2/I4gyUC9pqPNqHFRIey0EB0q0L5cSnQDfWJg8Jd6VadakxdIez/3zkqQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peerDependencies": { + "css-tree": "^3.2.1" + }, + "peerDependenciesMeta": { + "css-tree": { + "optional": true + } + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", + "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@dotenvx/dotenvx": { + "version": "1.75.1", + "resolved": "https://registry.npmjs.org/@dotenvx/dotenvx/-/dotenvx-1.75.1.tgz", + "integrity": "sha512-/BITOC9dmS/edY2zQwZNicQ059O6RKabtQfyEafV0nGtfYRNHYy1DIPiYVcov40+tob9hfmBnbR963dS+EQ1DQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@dotenvx/primitives": "^0.8.0", + "commander": "^11.1.0", + "conf": "^10.2.0", + "dotenv": "^17.2.1", + "enquirer": "^2.4.1", + "env-paths": "^2.2.1", + "execa": "^5.1.1", + "fdir": "^6.2.0", + "ignore": "^5.3.0", + "object-treeify": "1.1.33", + "open": "^8.4.2", + "picomatch": "^4.0.4", + "systeminformation": "^5.22.11", + "undici": "^7.11.0", + "which": "^4.0.0", + "yocto-spinner": "^1.1.0" + }, + "bin": { + "dotenvx": "src/cli/dotenvx.js" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@dotenvx/dotenvx/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==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/isexe": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", + "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@dotenvx/primitives": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@dotenvx/primitives/-/primitives-0.8.0.tgz", + "integrity": "sha512-VYJy0uhFm9zTJ1TxBaW/pA8bjbOM/OttaNMwZ1RHG4JKyRG7DhSdiqD1ipQoAyoD22olUtxbP78W9xY3Wd11bg==", + "license": "BSD-3-Clause" + }, + "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, @@ -1062,24 +1642,113 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@humanfs/core": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", - "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "node_modules/@exodus/bytes": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.1.tgz", + "integrity": "sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/types": "^0.15.0" - }, + "license": "MIT", "engines": { - "node": ">=18.18.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@noble/hashes": "^1.8.0 || ^2.0.0" + }, + "peerDependenciesMeta": { + "@noble/hashes": { + "optional": true + } } }, - "node_modules/@humanfs/node": { - "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", - "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", - "dev": true, + "node_modules/@floating-ui/core": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz", + "integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.6" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", + "license": "MIT" + }, + "node_modules/@fontsource-variable/inter": { + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/@fontsource-variable/inter/-/inter-5.2.8.tgz", + "integrity": "sha512-kOfP2D+ykbcX/P3IFnokOhVRNoTozo5/JxhAIVYLpea/UBmCQ/YWPBfWIDuBImXX/15KH+eKh4xpEUyS2sQQGQ==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, + "node_modules/@hono/node-server": { + "version": "1.19.14", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz", + "integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==", + "license": "MIT", + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, + "node_modules/@hookform/resolvers": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-5.4.0.tgz", + "integrity": "sha512-EIsqr/t/qbinPIhGjMdtvutIN1Kk4uwbROE9/UQ93CAVGR7GkA7Y92+fX80OzXi/OB67jVFYwKGO1WzkxmkFZw==", + "license": "MIT", + "dependencies": { + "@standard-schema/utils": "^0.3.0" + }, + "peerDependencies": { + "react-hook-form": "^7.55.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@humanfs/core": "^0.19.2", @@ -1132,7 +1801,6 @@ "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==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", @@ -1143,7 +1811,6 @@ "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", @@ -1154,7 +1821,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -1164,25 +1830,84 @@ "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, "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==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz", + "integrity": "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==", + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.9", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -1196,7 +1921,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -1206,7 +1930,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -1216,215 +1939,2719 @@ "node": ">= 8" } }, - "node_modules/@secretlint/config-creator": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/@secretlint/config-creator/-/config-creator-10.2.2.tgz", - "integrity": "sha512-BynOBe7Hn3LJjb3CqCHZjeNB09s/vgf0baBaHVw67w7gHF0d25c3ZsZ5+vv8TgwSchRdUCRrbbcq5i2B1fJ2QQ==", - "dev": true, + "node_modules/@radix-ui/number": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.2.tgz", + "integrity": "sha512-ceTwaxc4I5IOi97DgCotl3pqiyRGvffcc0oOsE2dQYaJOFIDsDt4VWG6xEbg1QePv9QWausCEIppud/tJ1wNig==", + "license": "MIT" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.4.tgz", + "integrity": "sha512-7AdCK9PQyiljKoBDbN8OuctCbd/esdwZPQ8RtOE3SsyQtUpiPb+ND75q0jEhC1m1ecBI0MFNeLJvwIh9iKHRcQ==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-accessible-icon": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accessible-icon/-/react-accessible-icon-1.1.10.tgz", + "integrity": "sha512-TraSwZUqTcVbiDV2/RXzAXC7aeVVXchq0daPFZE7zAxYFaMzjOUggLOfQH9KFLgRizuwVKZO/crveV1eeO3/ZQ==", "license": "MIT", "dependencies": { - "@secretlint/types": "^10.2.2" + "@radix-ui/react-visually-hidden": "1.2.6" }, - "engines": { - "node": ">=20.0.0" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@secretlint/config-loader": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/@secretlint/config-loader/-/config-loader-10.2.2.tgz", - "integrity": "sha512-ndjjQNgLg4DIcMJp4iaRD6xb9ijWQZVbd9694Ol2IszBIbGPPkwZHzJYKICbTBmh6AH/pLr0CiCaWdGJU7RbpQ==", - "dev": true, + "node_modules/@radix-ui/react-accordion": { + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.14.tgz", + "integrity": "sha512-iE8YB9nmTBH8zd73ofBISZ8JCzgMoMkATJr7qDwa6u5F1+7mTM81V6fa71jgZ65rpjVpecDf1vSnwIFP9Ly1zw==", "license": "MIT", "dependencies": { - "@secretlint/profiler": "^10.2.2", - "@secretlint/resolver": "^10.2.2", - "@secretlint/types": "^10.2.2", - "ajv": "^8.17.1", - "debug": "^4.4.1", - "rc-config-loader": "^4.1.3" + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-collapsible": "1.1.14", + "@radix-ui/react-collection": "1.1.10", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-controllable-state": "1.2.3" }, - "engines": { - "node": ">=20.0.0" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@secretlint/config-loader/node_modules/ajv": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", - "dev": true, + "node_modules/@radix-ui/react-alert-dialog": { + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.17.tgz", + "integrity": "sha512-563ygGeyWPrxyVCNp7OV4rE2aIXhFPknpFyo4wbDlcyMMPZ6ySh+zC5WTvY0ZFLgPTg/QB6tA8PyDQyJ2b4cPg==", "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-dialog": "1.1.17", + "@radix-ui/react-primitive": "2.1.6" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@secretlint/config-loader/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, - "node_modules/@secretlint/core": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/@secretlint/core/-/core-10.2.2.tgz", - "integrity": "sha512-6rdwBwLP9+TO3rRjMVW1tX+lQeo5gBbxl1I5F8nh8bgGtKwdlCMhMKsBWzWg1ostxx/tIG7OjZI0/BxsP8bUgw==", - "dev": true, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.10.tgz", + "integrity": "sha512-j2VTDz1vgCsmuG0k5lBfOcM8n5JPFqZBcMryasFjHYMhwxYL5SRUV5lMSUpRdNtw3D/Sv8pzJtrlAgkssYSsQQ==", "license": "MIT", "dependencies": { - "@secretlint/profiler": "^10.2.2", - "@secretlint/types": "^10.2.2", - "debug": "^4.4.1", - "structured-source": "^4.0.0" + "@radix-ui/react-primitive": "2.1.6" }, - "engines": { - "node": ">=20.0.0" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@secretlint/formatter": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/@secretlint/formatter/-/formatter-10.2.2.tgz", - "integrity": "sha512-10f/eKV+8YdGKNQmoDUD1QnYL7TzhI2kzyx95vsJKbEa8akzLAR5ZrWIZ3LbcMmBLzxlSQMMccRmi05yDQ5YDA==", - "dev": true, + "node_modules/@radix-ui/react-aspect-ratio": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-aspect-ratio/-/react-aspect-ratio-1.1.10.tgz", + "integrity": "sha512-kbI7NrqhDeuytYrq7JjAsoXczvL8wgj2tc1MyaYWm+50bMKHCHQtVWCryslx4cCpmCTTkBcwQckE4CmmGV2haQ==", "license": "MIT", "dependencies": { - "@secretlint/resolver": "^10.2.2", - "@secretlint/types": "^10.2.2", - "@textlint/linter-formatter": "^15.2.0", - "@textlint/module-interop": "^15.2.0", - "@textlint/types": "^15.2.0", - "chalk": "^5.4.1", - "debug": "^4.4.1", - "pluralize": "^8.0.0", - "strip-ansi": "^7.1.0", - "table": "^6.9.0", - "terminal-link": "^4.0.0" + "@radix-ui/react-primitive": "2.1.6" }, - "engines": { - "node": ">=20.0.0" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@secretlint/formatter/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, + "node_modules/@radix-ui/react-avatar": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.2.0.tgz", + "integrity": "sha512-am/CwltXtmtdtP+5FbYblYDnMa/zuKcMJP1i3/SJMDXXfj2mG+BTqLH2wucqeyyiQMursUtg/5cK+Nh2pCaSOA==", "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" + "dependencies": { + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-is-hydrated": "0.1.1", + "@radix-ui/react-use-layout-effect": "1.1.2" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@secretlint/node": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/@secretlint/node/-/node-10.2.2.tgz", - "integrity": "sha512-eZGJQgcg/3WRBwX1bRnss7RmHHK/YlP/l7zOQsrjexYt6l+JJa5YhUmHbuGXS94yW0++3YkEJp0kQGYhiw1DMQ==", - "dev": true, + "node_modules/@radix-ui/react-checkbox": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.5.tgz", + "integrity": "sha512-pREzrmNnVwGvYaBoM64huTRK7B3lrTRuwj8A9nwhPiEtMb+yudiWh6zWAqEtP0Dzd5+iBa1Ki7V1pCxV8ExMdA==", "license": "MIT", "dependencies": { - "@secretlint/config-loader": "^10.2.2", - "@secretlint/core": "^10.2.2", - "@secretlint/formatter": "^10.2.2", - "@secretlint/profiler": "^10.2.2", - "@secretlint/source-creator": "^10.2.2", - "@secretlint/types": "^10.2.2", - "debug": "^4.4.1", - "p-map": "^7.0.3" + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-previous": "1.1.2", + "@radix-ui/react-use-size": "1.1.2" }, - "engines": { - "node": ">=20.0.0" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@secretlint/profiler": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/@secretlint/profiler/-/profiler-10.2.2.tgz", - "integrity": "sha512-qm9rWfkh/o8OvzMIfY8a5bCmgIniSpltbVlUVl983zDG1bUuQNd1/5lUEeWx5o/WJ99bXxS7yNI4/KIXfHexig==", - "dev": true, + "node_modules/@radix-ui/react-collapsible": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.14.tgz", + "integrity": "sha512-9bT+FvifX1FK2Mj6UEsTdyu0cN3JaA3KdfhaBao+ONrYFy/pyOy3TU1TNw7iOk1o+0hOEq67RojlUUmoFGwxyA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-layout-effect": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.10.tgz", + "integrity": "sha512-IVVz4EvBcKjrzKgof714qDnz/SzQAkLA2Emh5edlHbgcE6fNd3Un6CJLlaYcnm8N4JmAtzQgse4dOKxcD2yc9g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-slot": "1.3.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.3.tgz", + "integrity": "sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.4.tgz", + "integrity": "sha512-QwH4PO5urrbO+FaGd5Aglg+YJgWTyyuZ3g/6mKvsqraLkglDdckw9JafgL5McL5VEJ6EPNduPaT3ZE9BttDAqg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context-menu": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context-menu/-/react-context-menu-2.3.1.tgz", + "integrity": "sha512-XbrxS68W5dyiE4fAb96yvJwSVU5x66B20A99sD5Mk3xSWK/LqeOnx6TZnim1KieMjXS/CTFq8reOAjWxas2G8Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-menu": "2.1.18", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-controllable-state": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.17.tgz", + "integrity": "sha512-TDTYmpdq8dI2+Xgvgj9AJ8Ghqq+Eph/TRVEdaFQPDItIY+6QSkU7MJMeevw1568Yw/2Ijz8BTphPSP2XejKphw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-dismissable-layer": "1.1.13", + "@radix-ui/react-focus-guards": "1.1.4", + "@radix-ui/react-focus-scope": "1.1.10", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-portal": "1.1.12", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-slot": "1.3.0", + "@radix-ui/react-use-controllable-state": "1.2.3", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.7.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.2.tgz", + "integrity": "sha512-C3vFhbyi4SW3PmbAi6Awpu4OzJtd0MxGurvSsYtr7p7nM8RNB3VAF3CUmnp2j50knpkrRcB7+ycVXzgLgF6yNA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.13.tgz", + "integrity": "sha512-2v+zNAWWe0ySxgC0D0yeXMPQ23xZVgXZTerTz+JKlmdRj6gfTqmCcR29jb6d290DezXPGgruHWDX/vYUebtErg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-escape-keydown": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.18.tgz", + "integrity": "sha512-PZGV82gFk0WltDRI//SsG28ZIjlo9ANTmoNYg0jLNzXXiDsAy5PkOOYQaVD1pPxY6t7gxffb1QMD6qaUvsBZdw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-menu": "2.1.18", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-controllable-state": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.4.tgz", + "integrity": "sha512-cot/aB/mOm0IYVYTTmQcEEK1M48lZWi8FlYe5nDPQQ8NYZUlXEFgncJ9p2Kzer3RKSrY7cTTpEMLZKNo9QoP5Q==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.10.tgz", + "integrity": "sha512-Fas/lXQqhVvqwAb64s5RFeHiHYElZ6SUQbZaNd6EkfhP/Al7wTIQ9WIR4QVX475tlu5yFCEdDcJH6/UwsZjMWw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-callback-ref": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-form": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-form/-/react-form-0.1.10.tgz", + "integrity": "sha512-1NfuvctVtX4sU3Mmq/IdrR8UunxiCMiVg3A5UENKhFzxUBeOyaQQ+lmaQaV7Tc8cqvBKsJL3/KGBsixK0D8WFg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-label": "2.1.10", + "@radix-ui/react-primitive": "2.1.6" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-hover-card": { + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.17.tgz", + "integrity": "sha512-GjZQIEANVkuuWeztlKz6QEHe31ZX2iDfHzcTMCQVZXC0JyQrgfKWSC+LOOEw6aVV64zyjzobIzSA4AU4eKWrHA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-dismissable-layer": "1.1.13", + "@radix-ui/react-popper": "1.3.1", + "@radix-ui/react-portal": "1.1.12", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-controllable-state": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.2.tgz", + "integrity": "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.10.tgz", + "integrity": "sha512-ib0zvq2ZsAqKm5tRnqGJn3vOxSgIts5ToxsXT0q1S/GfLD1Zj7UOEnkw8u2w6sRmn47djpQWuSU1DCL1R29/yw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.6" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.18.tgz", + "integrity": "sha512-lj8Rxjtn6zJq1oSbE/uDtAwCbB9BnxgHD+8MwJMuTh6u1dPamYhW9iuELr/Z8d0D/UysFblYYHeBPwi7T4k0YQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-collection": "1.1.10", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.13", + "@radix-ui/react-focus-guards": "1.1.4", + "@radix-ui/react-focus-scope": "1.1.10", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-popper": "1.3.1", + "@radix-ui/react-portal": "1.1.12", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-roving-focus": "1.1.13", + "@radix-ui/react-slot": "1.3.0", + "@radix-ui/react-use-callback-ref": "1.1.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.7.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menubar": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menubar/-/react-menubar-1.1.18.tgz", + "integrity": "sha512-hX7EGx/oFq6DPY27GQuP/2wP48GHf5LG6r06VgNJlG+znmDS8OfopZcRcGly3L4lsB9FqpmLx6JQSE9P3BUpyw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-collection": "1.1.10", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-menu": "2.1.18", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-roving-focus": "1.1.13", + "@radix-ui/react-use-controllable-state": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-navigation-menu": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.16.tgz", + "integrity": "sha512-nJ0SkrSQgudyYhMiYeHA1ayLVuduEJCFLan1RZZN7c9kqzzCFLaU9kuy81uNtqzweM9YaQPgWzxi9MwQ9jZ04g==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-collection": "1.1.10", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.13", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-layout-effect": "1.1.2", + "@radix-ui/react-use-previous": "1.1.2", + "@radix-ui/react-visually-hidden": "1.2.6" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-one-time-password-field": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-one-time-password-field/-/react-one-time-password-field-0.1.10.tgz", + "integrity": "sha512-GHkcJ+WVj91At+OvUVTD4R3W0/wxw9t/sG5xFUBYXaCbtWiooZX5Md376QjJqgH4VsVyXrbVNHO2O4NYcmjfVg==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.2", + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-collection": "1.1.10", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-roving-focus": "1.1.13", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-effect-event": "0.0.3", + "@radix-ui/react-use-is-hydrated": "0.1.1", + "@radix-ui/react-use-layout-effect": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-password-toggle-field": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-password-toggle-field/-/react-password-toggle-field-0.1.5.tgz", + "integrity": "sha512-fVuA82u0b/fClpbEJv8yp1nU9eSvoSEOERsU/hhf3FXGPIvkmE7oEaHEu8poowoXO39/Va7zq2E0TUcYr1dBRg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-effect-event": "0.0.3", + "@radix-ui/react-use-is-hydrated": "0.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover": { + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.17.tgz", + "integrity": "sha512-/YSAOdJ7YJvdn7bn5sdSx2egW+SKY+u7O5RyAVs94Ymrg2fg5QTSFPMRkzvhGyFuE4/qsmPBdrwYoZMZh/4f+g==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-dismissable-layer": "1.1.13", + "@radix-ui/react-focus-guards": "1.1.4", + "@radix-ui/react-focus-scope": "1.1.10", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-popper": "1.3.1", + "@radix-ui/react-portal": "1.1.12", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-slot": "1.3.0", + "@radix-ui/react-use-controllable-state": "1.2.3", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.7.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.3.1.tgz", + "integrity": "sha512-bhnq/0DEPTi2lsOD3J5rTL65qUKHbKbhqHsmN9TMiclSXpipi651ooUKPPp6G5lF/WiHBdn1s0Wuqsn+myVAvw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.10", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.2", + "@radix-ui/react-use-rect": "1.1.2", + "@radix-ui/react-use-size": "1.1.2", + "@radix-ui/rect": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.12.tgz", + "integrity": "sha512-m309havGzsjLHHaIX50G5PlvRs3xkgPCsGk/5PTvYm8D5q33yG0J7w/712PTOhid7NTaFETtnSXjngHQavvhVw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-layout-effect": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.6.tgz", + "integrity": "sha512-zdTk4PlUO0E18HnZ3wYbW0KkJJxWCdiNYp6g6X1PtONFhxVkg01vliTJAmwIszU6mHiyBOoW9P0rAugl5/hULQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.6.tgz", + "integrity": "sha512-wetd0QI77DbvrPpTAvH1SqOxsYF2wZe5TNxqwOd5Ty4XDpV3dpV0s8K/1MGMJBeY5o7lg8ub5VIt1Ub+yVen6g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.3.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-progress": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.10.tgz", + "integrity": "sha512-JYzEg60lk79PwKM27WZyKd7PW8O4OM5jOaFfRPfOyeXmMw7tLJh5kSj+CEjVTehszuwml/AdCzPGMXBTGf4BBw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-primitive": "2.1.6" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.4.1.tgz", + "integrity": "sha512-/SSxZdKEo2Eo29FFRKd06EfFDYp8HryKg0WYg7QLXaydPzl52YfSvCH2a3QDBRdtcuwACroJT8UVjQVgOJ7P9A==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-roving-focus": "1.1.13", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-previous": "1.1.2", + "@radix-ui/react-use-size": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.13.tgz", + "integrity": "sha512-9gkwneI0guf8JDmrFxPjJF6Ozzgioyw+/lonYNCwefS9ZHA05er0BVHiXr+LbWGHxUfczvMY6G1oiZZi1VzjRw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-collection": "1.1.10", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area": { + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.12.tgz", + "integrity": "sha512-xuafVzQiTCLsyEjakowTdG3OgTXsmO7IdCiO77otIa+z44xoLNs9Do5eg7POFumIOCjtG6djfm6RKUKpUa/csA==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.2", + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.3.1.tgz", + "integrity": "sha512-w6eDvY78LE9ZUiNnXCA1QVK8RYN7k9galFv09kjVydJqBAgHd7Y9A6h0UJ/6DCZNGZMZrB2ohcSW1Bo9d8+wWA==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.2", + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-collection": "1.1.10", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.13", + "@radix-ui/react-focus-guards": "1.1.4", + "@radix-ui/react-focus-scope": "1.1.10", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-popper": "1.3.1", + "@radix-ui/react-portal": "1.1.12", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-slot": "1.3.0", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-layout-effect": "1.1.2", + "@radix-ui/react-use-previous": "1.1.2", + "@radix-ui/react-visually-hidden": "1.2.6", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.7.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-separator": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.10.tgz", + "integrity": "sha512-Y6K6jLQCVfCnTL2MEtGxDLffkhNfEfHsEg3Wa8JU+IWdn3EWbLXd3OuOfQRN7p/W/cUce1WyTk3QeuAoDBzN9g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.6" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slider": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.4.1.tgz", + "integrity": "sha512-r91WSpQucNGFKAIxT8FT0H0zyjd5tJlqObLp7LOMV4z49KoDCwjy01w3vDOU4e1wxhF9IgjYco7SB6byOW7Buw==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.2", + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-collection": "1.1.10", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-layout-effect": "1.1.2", + "@radix-ui/react-use-previous": "1.1.2", + "@radix-ui/react-use-size": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.3.0.tgz", + "integrity": "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.3.1.tgz", + "integrity": "sha512-55bQtCnOB0BohomSHi6qvQXpJEEqUGDm6hRrM0Bph5OXwhSegqkd8IqgBAQkM1IlgUlWZIxpxRcpOEfRIgimyw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-previous": "1.1.2", + "@radix-ui/react-use-size": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.15.tgz", + "integrity": "sha512-kxc9gI6/HfcU4nfMMVS3AmQK414kbU1IE6UCJmMmxjhO3cRPXOyYnmvyKD+ODt7q56nRq9l7Wovi6uaGwKgMlg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-roving-focus": "1.1.13", + "@radix-ui/react-use-controllable-state": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast": { + "version": "1.2.17", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.17.tgz", + "integrity": "sha512-uL4kyyWy000pPL43fGGCV5qT6ZchCWEQZOSlkYiPwPt8Hy1iW38RjeptIvz1/SZesrW6Vn58Ct3sV7tfEfiAbw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-collection": "1.1.10", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-dismissable-layer": "1.1.13", + "@radix-ui/react-portal": "1.1.12", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-layout-effect": "1.1.2", + "@radix-ui/react-visually-hidden": "1.2.6" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.12.tgz", + "integrity": "sha512-AsAVsYNZIlRBsci7BhE+QyQeKd1h6TffJYt+lF0QQkd5OpQ3klfIByPsCb4G0h/Fq6PJwh1FYNluzBFYzhk4+w==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-controllable-state": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle-group": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.13.tgz", + "integrity": "sha512-Xb9PLtlvU66F36LiKba6dFswu6V2mDkgidO4fNSbQHQwmZ9ObxMIO17MN/LJ4aWJecVuSVLAHPZjyeMzJrgeiA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-roving-focus": "1.1.13", + "@radix-ui/react-toggle": "1.1.12", + "@radix-ui/react-use-controllable-state": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toolbar": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toolbar/-/react-toolbar-1.1.13.tgz", + "integrity": "sha512-Za1l4f6fzTkGgz/iynAMN8iaqiKff2wm2/QwiLmHPtDQreWEBrvSimgQFIekxMUdRPhILM7xdIXxuS/o/DGZag==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-roving-focus": "1.1.13", + "@radix-ui/react-separator": "1.1.10", + "@radix-ui/react-toggle-group": "1.1.13" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.10.tgz", + "integrity": "sha512-NlNe8D0dWEpVfXFli90IO6X07Josx/b1iu98tDnx9Xv0HT4wLIL+m2VOheMHhK7qbp2HoTBqALEFzGyZs/levw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-dismissable-layer": "1.1.13", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-popper": "1.3.1", + "@radix-ui/react-portal": "1.1.12", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-slot": "1.3.0", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-visually-hidden": "1.2.6" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.2.tgz", + "integrity": "sha512-xCso9j1/u8sEgP1RNHjFrXJLApL8LiqOkI1R4ywuN00rxWdYg4oQXuwKLS3i0j5NWLromUD27/4nlxj2UFVvIw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.3.tgz", + "integrity": "sha512-PLzC90MS+ReootmjC597dvopoelpZ8Q61HJkDXZSExitIq7PL55vHNnesAHwguHK0aPfBnpdNzQtv1uliaqQrA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.3", + "@radix-ui/react-use-layout-effect": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.3.tgz", + "integrity": "sha512-6c8ZqvPTWILEKnyVkP53EGRCcpnJiKTC21sS/6R1GF5xKyHJJWQEPfkqlcgUkdRQivd6tb23abUwe4ngWmY0JA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.2.tgz", + "integrity": "sha512-2uVLvLjgO7NZCWw01/FdqRwmA42J0BcjPMUCA+koFEOAb+zjqIP7SiFz/7zWPrKnVmSqr76Omq2ALyCuX4dhLw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-is-hydrated": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.1.tgz", + "integrity": "sha512-qwOiz4Tjo8CNnrOLAYUMXeZwDzXgXpvK4TKQPmWLECM9XoWvA6+0Z2/7Ag3A4ivjS4ovbLJPbskkxioFyBhr8A==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.2.tgz", + "integrity": "sha512-jrBWOxZITuGcnjRCM2t2U5ZPkCLxD+Ym6DjfssS5haTj2iiak/DOb64JeN6OdLfLgptb6/e2kKR+ZuTrGoZTPA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.2.tgz", + "integrity": "sha512-IGBQPtRFdhN6MQ8dbegVmBq1LVZluya3F1jWY+puIcQC3MHctRwTDSBWCkL/3ZcnMJLTMJ++Z+ktmvg0F89iCw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.2.tgz", + "integrity": "sha512-d8a+bBY/FxikNPlgJJoaBHZX+zKVbWHYJGTLnLvveQgFSTntkGdEKv3JDtHrMS0DNYpllz2nRsTLGLKYttbpmw==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.2.tgz", + "integrity": "sha512-giWQp+4mxjBPt4KZ0MmyuykFNWfbDxKt4x+fPkRYmgRFJSbCZFzUglvMb/Kjn38tm10YP4ufiQZDx3zna4LU6w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.6.tgz", + "integrity": "sha512-jCE0WljWifTI4niIMCll06kGpsJTAPiZVU9H4WR1N6qW7At9ystHbN7dDB+we2xH535roFHj7qKS+RGj0FMDWQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.6" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.2.tgz", + "integrity": "sha512-xnXE7wG13PI+cxieVssYXlQJuYVRhH9NBoxt3KNwzghDIA69GMm7d4wXRouHIYjE+KvS6U/MsMO73NdS2MH9ZA==", + "license": "MIT" + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "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==", + "license": "MIT" + }, + "node_modules/@secretlint/config-creator": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/config-creator/-/config-creator-10.2.2.tgz", + "integrity": "sha512-BynOBe7Hn3LJjb3CqCHZjeNB09s/vgf0baBaHVw67w7gHF0d25c3ZsZ5+vv8TgwSchRdUCRrbbcq5i2B1fJ2QQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/types": "^10.2.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/config-loader": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/config-loader/-/config-loader-10.2.2.tgz", + "integrity": "sha512-ndjjQNgLg4DIcMJp4iaRD6xb9ijWQZVbd9694Ol2IszBIbGPPkwZHzJYKICbTBmh6AH/pLr0CiCaWdGJU7RbpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/profiler": "^10.2.2", + "@secretlint/resolver": "^10.2.2", + "@secretlint/types": "^10.2.2", + "ajv": "^8.17.1", + "debug": "^4.4.1", + "rc-config-loader": "^4.1.3" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/config-loader/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@secretlint/config-loader/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/@secretlint/core": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/core/-/core-10.2.2.tgz", + "integrity": "sha512-6rdwBwLP9+TO3rRjMVW1tX+lQeo5gBbxl1I5F8nh8bgGtKwdlCMhMKsBWzWg1ostxx/tIG7OjZI0/BxsP8bUgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/profiler": "^10.2.2", + "@secretlint/types": "^10.2.2", + "debug": "^4.4.1", + "structured-source": "^4.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/formatter": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/formatter/-/formatter-10.2.2.tgz", + "integrity": "sha512-10f/eKV+8YdGKNQmoDUD1QnYL7TzhI2kzyx95vsJKbEa8akzLAR5ZrWIZ3LbcMmBLzxlSQMMccRmi05yDQ5YDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/resolver": "^10.2.2", + "@secretlint/types": "^10.2.2", + "@textlint/linter-formatter": "^15.2.0", + "@textlint/module-interop": "^15.2.0", + "@textlint/types": "^15.2.0", + "chalk": "^5.4.1", + "debug": "^4.4.1", + "pluralize": "^8.0.0", + "strip-ansi": "^7.1.0", + "table": "^6.9.0", + "terminal-link": "^4.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/formatter/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/@secretlint/node": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/node/-/node-10.2.2.tgz", + "integrity": "sha512-eZGJQgcg/3WRBwX1bRnss7RmHHK/YlP/l7zOQsrjexYt6l+JJa5YhUmHbuGXS94yW0++3YkEJp0kQGYhiw1DMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/config-loader": "^10.2.2", + "@secretlint/core": "^10.2.2", + "@secretlint/formatter": "^10.2.2", + "@secretlint/profiler": "^10.2.2", + "@secretlint/source-creator": "^10.2.2", + "@secretlint/types": "^10.2.2", + "debug": "^4.4.1", + "p-map": "^7.0.3" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/profiler": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/profiler/-/profiler-10.2.2.tgz", + "integrity": "sha512-qm9rWfkh/o8OvzMIfY8a5bCmgIniSpltbVlUVl983zDG1bUuQNd1/5lUEeWx5o/WJ99bXxS7yNI4/KIXfHexig==", + "dev": true, + "license": "MIT" + }, + "node_modules/@secretlint/resolver": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/resolver/-/resolver-10.2.2.tgz", + "integrity": "sha512-3md0cp12e+Ae5V+crPQYGd6aaO7ahw95s28OlULGyclyyUtf861UoRGS2prnUrKh7MZb23kdDOyGCYb9br5e4w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@secretlint/secretlint-formatter-sarif": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-formatter-sarif/-/secretlint-formatter-sarif-10.2.2.tgz", + "integrity": "sha512-ojiF9TGRKJJw308DnYBucHxkpNovDNu1XvPh7IfUp0A12gzTtxuWDqdpuVezL7/IP8Ua7mp5/VkDMN9OLp1doQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-sarif-builder": "^3.2.0" + } + }, + "node_modules/@secretlint/secretlint-rule-no-dotenv": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-rule-no-dotenv/-/secretlint-rule-no-dotenv-10.2.2.tgz", + "integrity": "sha512-KJRbIShA9DVc5Va3yArtJ6QDzGjg3PRa1uYp9As4RsyKtKSSZjI64jVca57FZ8gbuk4em0/0Jq+uy6485wxIdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/types": "^10.2.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/secretlint-rule-preset-recommend": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-rule-preset-recommend/-/secretlint-rule-preset-recommend-10.2.2.tgz", + "integrity": "sha512-K3jPqjva8bQndDKJqctnGfwuAxU2n9XNCPtbXVI5JvC7FnQiNg/yWlQPbMUlBXtBoBGFYp08A94m6fvtc9v+zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/source-creator": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/source-creator/-/source-creator-10.2.2.tgz", + "integrity": "sha512-h6I87xJfwfUTgQ7irWq7UTdq/Bm1RuQ/fYhA3dtTIAop5BwSFmZyrchph4WcoEvbN460BWKmk4RYSvPElIIvxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/types": "^10.2.2", + "istextorbinary": "^9.5.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/types": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/types/-/types-10.2.2.tgz", + "integrity": "sha512-Nqc90v4lWCXyakD6xNyNACBJNJ0tNCwj2WNk/7ivyacYHxiITVgmLUFXTBOeCdy79iz6HtN9Y31uw/jbLrdOAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "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/@secretlint/resolver": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/@secretlint/resolver/-/resolver-10.2.2.tgz", - "integrity": "sha512-3md0cp12e+Ae5V+crPQYGd6aaO7ahw95s28OlULGyclyyUtf861UoRGS2prnUrKh7MZb23kdDOyGCYb9br5e4w==", + "node_modules/@standard-schema/utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz", + "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", + "license": "MIT" + }, + "node_modules/@swc/core": { + "version": "1.15.43", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.43.tgz", + "integrity": "sha512-1CuKjFkPxIgGdeHVuNbkxmBxkcbdc08u0aiI43pFq6yY1tTVKmXT9hFEooyyKs/sJ3xf1GPHyEwTtk9Xl8dvQw==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.27" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.15.43", + "@swc/core-darwin-x64": "1.15.43", + "@swc/core-linux-arm-gnueabihf": "1.15.43", + "@swc/core-linux-arm64-gnu": "1.15.43", + "@swc/core-linux-arm64-musl": "1.15.43", + "@swc/core-linux-ppc64-gnu": "1.15.43", + "@swc/core-linux-s390x-gnu": "1.15.43", + "@swc/core-linux-x64-gnu": "1.15.43", + "@swc/core-linux-x64-musl": "1.15.43", + "@swc/core-win32-arm64-msvc": "1.15.43", + "@swc/core-win32-ia32-msvc": "1.15.43", + "@swc/core-win32-x64-msvc": "1.15.43" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.17" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.15.43", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.43.tgz", + "integrity": "sha512-v1aVuvXdo/BHxJzco9V2xpHrvwWmhfS8t6gziY5wJxd+Z2h8AeJRnAwPD8itCDaGXVBwJ/CaKfxEzTkG0Va0OA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.15.43", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.43.tgz", + "integrity": "sha512-lp3d4Lamc8dt5huYdGLSR+9hLxmfr1jb0l+4XXG2zPqZwYWRN9R0U2qYoTrggiU2RWW0oV9VbWM3kBnqIc2kdQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.15.43", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.43.tgz", + "integrity": "sha512-JWTQQELtsG5GgphDrr/XqqmM2pDN3cZqbMS0Mrg+iTiXL3F74sn/S2IyYE/5u4h2KLkTf9qQ7dXyxsbx7YzkeA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.15.43", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.43.tgz", + "integrity": "sha512-B4otJRdPWIsmiSBf0uG7Z/+vMWmkufjz5MmYxubwKuZazDW14Zd3symga1N62QR4RT+kEFeHEgsXfZGyn/w0hw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.15.43", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.43.tgz", + "integrity": "sha512-6zB6OnpViBxYy4tgY3v2i6AZY9fwkcHZ032UOwtwUuW1d19sdT07qF0kZe6/3UR1tUaK6jjg2rmVcUIBCEYVjQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-ppc64-gnu": { + "version": "1.15.43", + "resolved": "https://registry.npmjs.org/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.43.tgz", + "integrity": "sha512-coxE1ZWdB3uSDVNoEtYNrRi/1epvckZx9cTJ8ICUxTMTxGk+yvQ/Twacp3ruZSaMPGCriUjP86C37VhaT6nyRg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-s390x-gnu": { + "version": "1.15.43", + "resolved": "https://registry.npmjs.org/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.43.tgz", + "integrity": "sha512-lXfLhs+LpBsD5inuYx+YDH5WsPPBQ95KPUiy8P5wq9ob9xKDZFqwNfU2QW6bGO8NqRO/H9JQomTSt5Yyh+FGfA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.15.43", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.43.tgz", + "integrity": "sha512-07XnKwTmKy8TGOZG3D9fRnLWGynxPjwQnZLVmBFbo6F+7vHYzBIOuwXEhemrChBWb6yDNZsVCcMWCPX6FDD2xg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.15.43", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.43.tgz", + "integrity": "sha512-TJc+bsSIaBh+hZvZ5GRtW/K1bw66TJ9vsUwvVIsZdiWxU5ObLwZvfcnZ3UpgVfMnFibRes9uriJrQNBHEEogRQ==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } }, - "node_modules/@secretlint/secretlint-formatter-sarif": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/@secretlint/secretlint-formatter-sarif/-/secretlint-formatter-sarif-10.2.2.tgz", - "integrity": "sha512-ojiF9TGRKJJw308DnYBucHxkpNovDNu1XvPh7IfUp0A12gzTtxuWDqdpuVezL7/IP8Ua7mp5/VkDMN9OLp1doQ==", + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.15.43", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.43.tgz", + "integrity": "sha512-jfd7s2/bUQYkOHLs+LWQNKZdmDa8+sufKLllhpWAhVQ2GDCwsHe3vR/j+OSiItZNtkzFuaawa3+SAKz9y5gYfw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.15.43", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.43.tgz", + "integrity": "sha512-rLAE8JvucqEW1ZGohxPQrQWPBQeJG4+ypKbWfdlU/qmKScvCkxf9/Jxnzki1dkUQCQ7P5Enp13RlvqOlvx/32g==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.15.43", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.43.tgz", + "integrity": "sha512-h8MLDHZcfIukwQWj03rIJZx1I0E81AYj2X7J/nGErG4nz+QAv6G1Z+peotvinL3lqpbo32tLYSMFo32/ySzxKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@swc/types": { + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.27.tgz", + "integrity": "sha512-K6h3iUlqeM946U4sXFYeahefR1YBbXJvko+hv8WS8/0BNJ4OHiHRywMnQUJCqkR7Y9+hqQ1TvEpiKqUhz7NEFg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.1.tgz", + "integrity": "sha512-6NDaqRoAMSXD1mr/RXu0HBvNE9a2n5tHPsxu9XHLws8o4Twes5rBM2205SUUiJ9goAtadrN6xTGX0UDEwp/N4A==", "dev": true, "license": "MIT", "dependencies": { - "node-sarif-builder": "^3.2.0" + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "5.21.6", + "jiti": "^2.7.0", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.3.1" } }, - "node_modules/@secretlint/secretlint-rule-no-dotenv": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/@secretlint/secretlint-rule-no-dotenv/-/secretlint-rule-no-dotenv-10.2.2.tgz", - "integrity": "sha512-KJRbIShA9DVc5Va3yArtJ6QDzGjg3PRa1uYp9As4RsyKtKSSZjI64jVca57FZ8gbuk4em0/0Jq+uy6485wxIdg==", + "node_modules/@tailwindcss/oxide": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.1.tgz", + "integrity": "sha512-yVPyo8RNkabVr3O2EhHEE0Rewu7YKzc1DhIqfL46LKveFrmu9XbDazNOJY7/GRuvw1h6u3utWnR29H/p5JPlgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.3.1", + "@tailwindcss/oxide-darwin-arm64": "4.3.1", + "@tailwindcss/oxide-darwin-x64": "4.3.1", + "@tailwindcss/oxide-freebsd-x64": "4.3.1", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.1", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.1", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.1", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.1", + "@tailwindcss/oxide-linux-x64-musl": "4.3.1", + "@tailwindcss/oxide-wasm32-wasi": "4.3.1", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.1", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.1" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.1.tgz", + "integrity": "sha512-SVlyf61g374l5cHyg8x9kf5xmLcOaxvOTsbsqDnSsDJaKOEFZ7GCvi84VAVGpxojYOs1+3K6M0UjXfqPU8vmOQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.1.tgz", + "integrity": "sha512-hVnWLwv+e/l7c4WKyVtHVrIPvYdqWHjRB3MDIqARynzFtnQg85kmQEFCbV9Ja0VVx4xXTIiDWY60Y7iz/iNoDA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.1.tgz", + "integrity": "sha512-Cf7abu0WVgbhU7ANgPUnSAvm7nCvMweusHb8FnaHlLfv/Caq4GYaEZg7ZImzzmjx4lIAfuS8q+eLIS7A7IzxIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.1.tgz", + "integrity": "sha512-ZZqzX2Y+GXtXXfqSfpJhDm60OoZfvLHLCgm+J7NVqgHHJjG/m9ugZI77RwTsVd4fnBJuCFP6Ae6kTJb71UdS8g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.1.tgz", + "integrity": "sha512-/Ah/xik0LaMYfv9DZ0S/t4pBlBNYOcqtRwusjgovHkvT8ixueWCLyJjsaF5kQIckjb4IT8Q6K6p/iPmZMixYgg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.1.tgz", + "integrity": "sha512-gqdFoVJlw444GvpnheZLHmvTzSxI/cOUUh2KSNejQjTcYkW062SVD+En0rUgD+QV91bz1XGIGtt1HJd48xUGbQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.1.tgz", + "integrity": "sha512-Bwv9KwOvE0VKa86xPFif9b9c3Y1NxOV1P0gLti/IYaWEsQYZXDlxfGEtA8mdDZ7SG3wyNXAWYT5SIn3giL57oA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.1.tgz", + "integrity": "sha512-Ymi8O8T15HYQdOUWUtTI6ldN0neHP85FC+Qz32xTcZ7iJXtem/x8ITev0o1e9e5rkqj4lONZfTRLvkmin1+tKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.1.tgz", + "integrity": "sha512-M+P/91qJ6uILLw4k2G93GMDRAXj61SMvFQYt39AqvUqYgExXpLL5aepfns7sj4HiAQeolirQF9E0lzRvdf4zPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.1.tgz", + "integrity": "sha512-zsM8uOeqvVGHsAXsJxsT28ttosFahLJKCLOTUBqRAtKnVgGSRitds9T432QiT8b77Yga7JIBkulIRRlJPtYhRA==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@secretlint/types": "^10.2.2" + "@emnapi/core": "^1.10.0", + "@emnapi/runtime": "^1.10.0", + "@emnapi/wasi-threads": "^1.2.1", + "@napi-rs/wasm-runtime": "^1.1.4", + "@tybys/wasm-util": "^0.10.2", + "tslib": "^2.8.1" }, "engines": { - "node": ">=20.0.0" + "node": ">=14.0.0" } }, - "node_modules/@secretlint/secretlint-rule-preset-recommend": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/@secretlint/secretlint-rule-preset-recommend/-/secretlint-rule-preset-recommend-10.2.2.tgz", - "integrity": "sha512-K3jPqjva8bQndDKJqctnGfwuAxU2n9XNCPtbXVI5JvC7FnQiNg/yWlQPbMUlBXtBoBGFYp08A94m6fvtc9v+zA==", + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.1.tgz", + "integrity": "sha512-aiNvSq9BsVk8V513lDKlrCFAgf8qBMPZTpgEhInL+NwQqs97mYmupVMrPrgBBSL8Pv/0zXu9MrMF9rMun1ZeNg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=20.0.0" + "node": ">= 20" } }, - "node_modules/@secretlint/source-creator": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/@secretlint/source-creator/-/source-creator-10.2.2.tgz", - "integrity": "sha512-h6I87xJfwfUTgQ7irWq7UTdq/Bm1RuQ/fYhA3dtTIAop5BwSFmZyrchph4WcoEvbN460BWKmk4RYSvPElIIvxw==", + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.1.tgz", + "integrity": "sha512-xDEyu1rg290472FEGaKHnzyDyh5QH+AlWvsU5hMoMtPpzmKlRI0jaYKCgSHDYtaQWZOYbMaduSyCwFwY4n1HmA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.1.tgz", + "integrity": "sha512-hItDHuIIlEV61R+faXu66s1K36aTurO/Qw0e45Vskz57gXl9pWOT6eg3zmcEui6CZXddbN7zd41bwmvag4JGwQ==", "dev": true, "license": "MIT", "dependencies": { - "@secretlint/types": "^10.2.2", - "istextorbinary": "^9.5.0" + "@tailwindcss/node": "4.3.1", + "@tailwindcss/oxide": "4.3.1", + "tailwindcss": "4.3.1" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7 || ^8" + } + }, + "node_modules/@tanstack/query-core": { + "version": "5.101.2", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.101.2.tgz", + "integrity": "sha512-hH5MLoJhF7KaIGd7q3xTXGXvslI+GYlM1Z/35aSHHWaCJWB7XvTSHYuV3eM7tw+aE0mT/xMro4M4Q9rCGHT0lw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.101.2", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.101.2.tgz", + "integrity": "sha512-seDkr6kzGzX1okaaTtZPtgA688CDPlXUz1C6xSg0ESqn04Vuc8tlrYms1s3de+znBqhPVxFRfpAfUf+6XvfPWg==", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.101.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, + "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": ">=20.0.0" + "node": ">=18" } }, - "node_modules/@secretlint/types": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/@secretlint/types/-/types-10.2.2.tgz", - "integrity": "sha512-Nqc90v4lWCXyakD6xNyNACBJNJ0tNCwj2WNk/7ivyacYHxiITVgmLUFXTBOeCdy79iz6HtN9Y31uw/jbLrdOAg==", + "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": ">=20.0.0" + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" } }, - "node_modules/@sindresorhus/merge-streams": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", - "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "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" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "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/@textlint/ast-node-types": { @@ -1543,6 +4770,78 @@ "@textlint/ast-node-types": "15.7.1" } }, + "node_modules/@ts-morph/common": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.27.0.tgz", + "integrity": "sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ==", + "license": "MIT", + "dependencies": { + "fast-glob": "^3.3.3", + "minimatch": "^10.0.1", + "path-browserify": "^1.0.1" + } + }, + "node_modules/@ts-morph/common/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@ts-morph/common/node_modules/brace-expansion": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", + "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@ts-morph/common/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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/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/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/ejs": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-3.1.5.tgz", @@ -1624,6 +4923,16 @@ "csstype": "^3.2.2" } }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "devOptional": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, "node_modules/@types/sarif": { "version": "2.1.7", "resolved": "https://registry.npmjs.org/@types/sarif/-/sarif-2.1.7.tgz", @@ -1637,6 +4946,12 @@ "integrity": "sha512-iEN8J0BoMnsWBqjVbWH/c0G0Hh7O21lpR2/+PrvAVgWdzL7eexIFm4JN/Wn10PTcmNdtS6U67r499mlWMXOxNw==", "license": "MIT" }, + "node_modules/@types/validate-npm-package-name": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/validate-npm-package-name/-/validate-npm-package-name-4.0.2.tgz", + "integrity": "sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw==", + "license": "MIT" + }, "node_modules/@types/vscode": { "version": "1.125.0", "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.125.0.tgz", @@ -1979,6 +5294,136 @@ "resolved": "packages/core", "link": true }, + "node_modules/@vitejs/plugin-react-swc": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-4.3.1.tgz", + "integrity": "sha512-PaeokKjAGraNN+s5SIApgsktnJprIyt3zgEIu7awnEdfn29QiB2crTcCzyi2XGpX9rUnTc0cKU07Wm0N0g7H2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "^1.0.0", + "@swc/core": "^1.15.11" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "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/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": "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/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/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/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/@vscode/vsce": { "version": "3.9.2", "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-3.9.2.tgz", @@ -2223,6 +5668,81 @@ "node": ">=10" } }, + "node_modules/@webview-rpc/client": { + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/@webview-rpc/client/-/client-1.0.17.tgz", + "integrity": "sha512-pXqHmnsOTLqPxHkGzLipTHjBJGOZQQNZPpDA0F4yqwJLfNTuV1J7KSashtU6MztOPVZ0xXtTxYqdxG0vXPI/gw==", + "dependencies": { + "@webview-rpc/shared": "1.0.17" + } + }, + "node_modules/@webview-rpc/host": { + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/@webview-rpc/host/-/host-1.0.17.tgz", + "integrity": "sha512-sJfTM+v2KA3MQagUVrw6Vp/D0YCzNMF0xBNSdVnFTlqICWavc1OEMhLkSRwJXAkSVXX6ePEPVELOjkcl7O8kUQ==", + "dependencies": { + "@webview-rpc/shared": "1.0.17", + "zod": "^4.1.11" + } + }, + "node_modules/@webview-rpc/react-query": { + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/@webview-rpc/react-query/-/react-query-1.0.17.tgz", + "integrity": "sha512-nl9W5At9UMGFSylSjohzeuCYexVGCOle2d3DXT6oqXQKLw7+ihJ00LTWbw221Cg88qasSEV8AUrFz6OJeoTrSg==", + "dependencies": { + "@tanstack/react-query": "^5.90.5", + "@webview-rpc/client": "1.0.17", + "@webview-rpc/shared": "1.0.17", + "react": "^19.2.0", + "zod": "^4.1.11" + } + }, + "node_modules/@webview-rpc/shared": { + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/@webview-rpc/shared/-/shared-1.0.17.tgz", + "integrity": "sha512-R0zHO0tQN0fNWPbMIxAgZHJsiIU7gDB+Td570TppU8tPOGDieqS4DUWM4doP6awnn9dzZI6HE7XN/kYFQS4+Dg==", + "dependencies": { + "zod": "^4.1.11" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/acorn": { "version": "8.17.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", @@ -2273,6 +5793,54 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/ansi-escapes": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", @@ -2307,21 +5875,65 @@ "dev": true, "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "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==", + "license": "Python-2.0" + }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "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.16.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", + "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=4" } }, - "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==", - "license": "Python-2.0" - }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -2339,6 +5951,15 @@ "dev": true, "license": "MIT" }, + "node_modules/atomically": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/atomically/-/atomically-1.7.0.tgz", + "integrity": "sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==", + "license": "MIT", + "engines": { + "node": ">=10.12.0" + } + }, "node_modules/auto-bind": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/auto-bind/-/auto-bind-5.0.1.tgz", @@ -2351,6 +5972,43 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/autoprefixer": { + "version": "10.5.2", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.2.tgz", + "integrity": "sha512-rD5t5DwOjJdmSORcTq64j8MawTC+tbQ+HHqjR4NDumamy/ambn1UJrlKL+KdwujWxMkFjPM3pPHOEA9tl4767Q==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.4", + "caniuse-lite": "^1.0.30001799", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, "node_modules/azure-devops-node-api": { "version": "12.5.0", "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-12.5.0.tgz", @@ -2395,7 +6053,6 @@ "version": "2.10.38", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.38.tgz", "integrity": "sha512-31/02mVB4yuQU6adKk5SlY6m+mxDwUq5KZkyYgnLrrKl7TEm1+3PyDtDBz2kOv/wxZz41GHsvV1A/u6RmiyBvw==", - "dev": true, "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.cjs" @@ -2404,6 +6061,16 @@ "node": ">=6.0.0" } }, + "node_modules/bidi-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", + "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, "node_modules/binaryextensions": { "version": "6.11.0", "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-6.11.0.tgz", @@ -2433,6 +6100,59 @@ "readable-stream": "^3.4.0" } }, + "node_modules/body-parser": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", + "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^2.0.0", + "debug": "^4.4.3", + "http-errors": "^2.0.1", + "iconv-lite": "^0.7.2", + "on-finished": "^2.4.1", + "qs": "^6.15.2", + "raw-body": "^3.0.2", + "type-is": "^2.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/body-parser/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "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/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -2462,7 +6182,6 @@ "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" @@ -2472,10 +6191,9 @@ } }, "node_modules/browserslist": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", - "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", - "dev": true, + "version": "4.28.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.4.tgz", + "integrity": "sha512-MTc8i/x9jBQd1iMw2CFGS+rwMa07eYjLR0CCTLDACl9xhxy+nIs3KeML/biicXtk9JrZ6dnnTatmc7ErPXIxqw==", "funding": [ { "type": "opencollective", @@ -2492,10 +6210,10 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.10.12", - "caniuse-lite": "^1.0.30001782", - "electron-to-chromium": "^1.5.328", - "node-releases": "^2.0.36", + "baseline-browser-mapping": "^2.10.38", + "caniuse-lite": "^1.0.30001799", + "electron-to-chromium": "^1.5.376", + "node-releases": "^2.0.48", "update-browserslist-db": "^1.2.3" }, "bin": { @@ -2552,7 +6270,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", - "dev": true, "license": "MIT", "dependencies": { "run-applescript": "^7.0.0" @@ -2564,11 +6281,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -2582,7 +6307,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -2599,7 +6323,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -2609,7 +6332,6 @@ "version": "1.0.30001799", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz", "integrity": "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==", - "dev": true, "funding": [ { "type": "opencollective", @@ -2626,6 +6348,16 @@ ], "license": "CC-BY-4.0" }, + "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": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -2695,6 +6427,19 @@ "license": "ISC", "optional": true }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, "node_modules/cli-boxes": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-4.0.1.tgz", @@ -2722,6 +6467,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/cli-truncate": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-6.0.0.tgz", @@ -2798,6 +6555,32 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cmdk": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.1.1.tgz", + "integrity": "sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "^1.1.1", + "@radix-ui/react-dialog": "^1.1.6", + "@radix-ui/react-id": "^1.1.0", + "@radix-ui/react-primitive": "^2.0.2" + }, + "peerDependencies": { + "react": "^18 || ^19 || ^19.0.0-rc", + "react-dom": "^18 || ^19 || ^19.0.0-rc" + } + }, "node_modules/cockatiel": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/cockatiel/-/cockatiel-3.2.1.tgz", @@ -2808,6 +6591,12 @@ "node": ">=16" } }, + "node_modules/code-block-writer": { + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.3.tgz", + "integrity": "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==", + "license": "MIT" + }, "node_modules/code-excerpt": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/code-excerpt/-/code-excerpt-4.0.0.tgz", @@ -2863,34 +6652,214 @@ "node": ">=18" } }, - "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/convert-to-spaces": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/convert-to-spaces/-/convert-to-spaces-2.0.1.tgz", - "integrity": "sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==", + "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/conf": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/conf/-/conf-10.2.0.tgz", + "integrity": "sha512-8fLl9F04EJqjSqH+QjITQfJF8BrOVaYr1jewVgSRAEWePfxT0sku4w2hrGQ60BC/TNLGQ2pgxNlTbWQmMPFvXg==", + "license": "MIT", + "dependencies": { + "ajv": "^8.6.3", + "ajv-formats": "^2.1.1", + "atomically": "^1.7.0", + "debounce-fn": "^4.0.0", + "dot-prop": "^6.0.1", + "env-paths": "^2.2.1", + "json-schema-typed": "^7.0.3", + "onetime": "^5.1.2", + "pkg-up": "^3.1.0", + "semver": "^7.3.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/conf/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/conf/node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/conf/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/conf/node_modules/json-schema-typed": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-7.0.3.tgz", + "integrity": "sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A==", + "license": "BSD-2-Clause" + }, + "node_modules/conf/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/content-disposition": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/convert-to-spaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/convert-to-spaces/-/convert-to-spaces-2.0.1.tgz", + "integrity": "sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cosmiconfig": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.2.tgz", + "integrity": "sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg==", + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cosmiconfig/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": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "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", @@ -2918,6 +6887,20 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, "node_modules/css-what": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", @@ -2931,6 +6914,25 @@ "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/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/csstype": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", @@ -2938,11 +6940,58 @@ "devOptional": true, "license": "MIT" }, + "node_modules/data-urls": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz", + "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/data-urls/node_modules/whatwg-mimetype": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", + "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/debounce-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-4.0.0.tgz", + "integrity": "sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ==", + "license": "MIT", + "dependencies": { + "mimic-fn": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/debounce-fn/node_modules/mimic-fn": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz", + "integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -2956,6 +7005,13 @@ } } }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, "node_modules/decompress-response": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", @@ -2973,6 +7029,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/dedent": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", + "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, "node_modules/deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -2995,11 +7065,19 @@ "resolved": "packages/vscode-ide-companion", "link": true }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/default-browser": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz", "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==", - "dev": true, "license": "MIT", "dependencies": { "bundle-name": "^4.1.0", @@ -3016,7 +7094,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -3029,7 +7106,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -3048,17 +7124,57 @@ "node": ">=0.4.0" } }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "dev": true, "license": "Apache-2.0", - "optional": true, "engines": { "node": ">=8" } }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, + "node_modules/diff": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", + "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", @@ -3118,11 +7234,37 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, + "node_modules/dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dotenv": { + "version": "17.4.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", + "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -3160,6 +7302,12 @@ "url": "https://bevry.me/fund" } }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, "node_modules/ejs": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/ejs/-/ejs-5.0.2.tgz", @@ -3173,10 +7321,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.375", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.375.tgz", - "integrity": "sha512-ZWP5eB4BVPW/ZYo9252hQZHZ5XavtsTgpbhcmMmRwymavC5AsLWQWBPaKMeNd2LW0KGby5HPXvj7+sr4ta5j/Q==", - "dev": true, + "version": "1.5.380", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.380.tgz", + "integrity": "sha512-W6d5AbuEoRayO447cqrg6lKJIlscgRnnxOZl/08kfV71BQDoEBC7Wwis68z87LjyK6f4kWyTaubuDbhHKrZkbA==", "license": "ISC" }, "node_modules/emoji-regex": { @@ -3185,6 +7332,15 @@ "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", "license": "MIT" }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/encoding-sniffer": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz", @@ -3210,6 +7366,54 @@ "once": "^1.4.0" } }, + "node_modules/enhanced-resolve": { + "version": "5.21.6", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.6.tgz", + "integrity": "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/enquirer/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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/enquirer/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==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -3222,6 +7426,15 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/environment": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", @@ -3234,11 +7447,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "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-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -3248,17 +7469,22 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" } }, + "node_modules/es-module-lexer": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.0.tgz", + "integrity": "sha512-KLdwQm2NvGLDkQDCGvmiQrhkd0JbMzXthwQAUgWjQuQdBLFa3eiBP5arXZyA+f8x+x7OXgud6bq2rxjGtHV2tw==", + "dev": true, + "license": "MIT" + }, "node_modules/es-object-atoms": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -3344,6 +7570,12 @@ "node": ">=6" } }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -3550,6 +7782,16 @@ "node": ">=4.0" } }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "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", @@ -3560,6 +7802,15 @@ "node": ">=0.10.0" } }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/eventemitter3": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", @@ -3567,6 +7818,77 @@ "dev": true, "license": "MIT" }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.1.0.tgz", + "integrity": "sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/execa": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.1.tgz", + "integrity": "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==", + "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/execa/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==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/execa/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==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/expand-template": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", @@ -3578,6 +7900,102 @@ "node": ">=6" } }, + "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/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.5.2.tgz", + "integrity": "sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==", + "license": "MIT", + "dependencies": { + "ip-address": "^10.2.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/express/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", @@ -3594,14 +8012,12 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, "license": "MIT" }, "node_modules/fast-glob": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -3618,7 +8034,6 @@ "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" @@ -3645,7 +8060,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", - "dev": true, "funding": [ { "type": "github", @@ -3662,7 +8076,6 @@ "version": "1.20.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", - "dev": true, "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -3672,7 +8085,6 @@ "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" @@ -3686,6 +8098,21 @@ } } }, + "node_modules/figures": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", + "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", + "license": "MIT", + "dependencies": { + "is-unicode-supported": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -3703,7 +8130,6 @@ "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" @@ -3712,6 +8138,27 @@ "node": ">=8" } }, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -3779,6 +8226,65 @@ "node": ">= 6" } }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/framer-motion": { + "version": "12.42.2", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.42.2.tgz", + "integrity": "sha512-5XY9luDiu0oHfHBjpDthFMh0ES+122w6p/papSJBweMkO8Sn+PW2QaEgRblQBpWFnuvZS5qvarpt/hO2pjGmnw==", + "license": "MIT", + "dependencies": { + "motion-dom": "^12.42.2", + "motion-utils": "^12.39.0", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -3791,7 +8297,6 @@ "version": "11.3.5", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.5.tgz", "integrity": "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==", - "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", @@ -3821,17 +8326,21 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/fuzzysort": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fuzzysort/-/fuzzysort-3.1.0.tgz", + "integrity": "sha512-sR9BNCjBg6LNgwvxlBd0sBABvQitkLzoVY9MYYROQVX/FvfJ4Mai9LsGhDgd8qYdds0bY77VzYd5iuB+v5rwQQ==", + "license": "MIT" + }, "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" @@ -3862,7 +8371,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -3883,11 +8391,31 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/get-own-enumerable-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-own-enumerable-keys/-/get-own-enumerable-keys-1.0.0.tgz", + "integrity": "sha512-PKsK2FSrQCyxcGHsGrLDcK0lx+0Ke+6e8KFFozA9/fIQLhQzPaRvJFdcz7+Axg3jUH/Mq+NI4xa5u/UT2tQskA==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dev": true, "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -3897,6 +8425,22 @@ "node": ">= 0.4" } }, + "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==", + "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/github-from-package": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", @@ -4023,7 +8567,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -4036,7 +8579,6 @@ "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/gradient-string": { @@ -4115,7 +8657,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -4144,7 +8685,6 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", - "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -4170,6 +8710,15 @@ "hermes-estree": "0.25.1" } }, + "node_modules/hono": { + "version": "4.12.27", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.27.tgz", + "integrity": "sha512-1yrb/+w6HWQJrUCLkJ2IF5jNIPvvFkblV5RNOYl6bV+OA6p9GLcMpHFFGTosSvHvcAUibuUukRqhlYI4z32C7Q==", + "license": "MIT", + "engines": { + "node": ">=16.9.0" + } + }, "node_modules/hosted-git-info": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", @@ -4203,6 +8752,19 @@ "dev": true, "license": "ISC" }, + "node_modules/html-encoding-sniffer": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", + "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.6.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, "node_modules/htmlparser2": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz", @@ -4236,6 +8798,26 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/http-proxy-agent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", @@ -4264,6 +8846,15 @@ "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==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, "node_modules/husky": { "version": "9.1.7", "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", @@ -4319,7 +8910,6 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -4329,7 +8919,6 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, "license": "MIT", "dependencies": { "parent-module": "^1.0.0", @@ -4380,9 +8969,7 @@ "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", - "optional": true + "license": "ISC" }, "node_modules/ini": { "version": "1.3.8", @@ -4486,11 +9073,34 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "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==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "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-docker": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", - "dev": true, "license": "MIT", "bin": { "is-docker": "cli.js" @@ -4515,7 +9125,6 @@ "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" @@ -4540,7 +9149,6 @@ "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" @@ -4564,11 +9172,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-in-ssh": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-in-ssh/-/is-in-ssh-1.0.0.tgz", + "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-inside-container": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", - "dev": true, "license": "MIT", "dependencies": { "is-docker": "^3.0.0" @@ -4583,21 +9202,101 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "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==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true, + "license": "MIT" + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/is-regexp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-3.1.0.tgz", + "integrity": "sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA==", + "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==", + "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==", "license": "MIT", "engines": { - "node": ">=0.12.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-wsl": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", - "dev": true, "license": "MIT", "dependencies": { "is-inside-container": "^1.0.0" @@ -4613,7 +9312,6 @@ "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/istextorbinary": { @@ -4634,6 +9332,25 @@ "url": "https://bevry.me/fund" } }, + "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/jose": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.3.tgz", + "integrity": "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -4644,7 +9361,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", - "dev": true, "funding": [ { "type": "github", @@ -4663,11 +9379,97 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsdom": { + "version": "29.1.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-29.1.1.tgz", + "integrity": "sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^5.1.11", + "@asamuzakjp/dom-selector": "^7.1.1", + "@bramus/specificity": "^2.4.2", + "@csstools/css-syntax-patches-for-csstree": "^1.1.3", + "@exodus/bytes": "^1.15.0", + "css-tree": "^3.2.1", + "data-urls": "^7.0.0", + "decimal.js": "^10.6.0", + "html-encoding-sniffer": "^6.0.0", + "is-potential-custom-element-name": "^1.0.1", + "lru-cache": "^11.3.5", + "parse5": "^8.0.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^6.0.1", + "undici": "^7.25.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^8.0.1", + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.1", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24.0.0" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/entities": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", + "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/jsdom/node_modules/lru-cache": { + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/jsdom/node_modules/parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^8.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/jsdom/node_modules/whatwg-mimetype": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", + "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -4683,6 +9485,12 @@ "dev": true, "license": "MIT" }, + "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/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -4690,6 +9498,12 @@ "dev": true, "license": "MIT" }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "license": "BSD-2-Clause" + }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", @@ -4701,7 +9515,6 @@ "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" @@ -4721,7 +9534,6 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", - "dev": true, "license": "MIT", "dependencies": { "universalify": "^2.0.0" @@ -4821,6 +9633,15 @@ "node": ">=0.10.0" } }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -4845,6 +9666,273 @@ "node": ">= 0.8.0" } }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "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/linkify-it": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.1.tgz", @@ -5032,12 +10120,52 @@ "dev": true, "license": "MIT" }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", - "dev": true, - "license": "MIT" + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", + "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "is-unicode-supported": "^1.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/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==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/log-update": { "version": "6.1.0", @@ -5191,12 +10319,40 @@ "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": "1.22.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.22.0.tgz", + "integrity": "sha512-c9o3l0PiNcgOQDW4F31BEYHudE7kgxVt3o30qMl36ZPwTxXlGB4QnLilhERvVM4uh/pl5MDyY1/gzZSYcHDtBg==", + "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-it": { "version": "14.2.0", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.2.0.tgz", @@ -5228,23 +10384,55 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" } }, + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "dev": true, + "license": "CC0-1.0" + }, "node_modules/mdurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", "license": "MIT" }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -5254,7 +10442,6 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -5268,7 +10455,6 @@ "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" @@ -5326,7 +10512,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", - "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -5349,6 +10534,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "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": "3.1.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", @@ -5366,9 +10561,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, "license": "MIT", - "optional": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5391,11 +10584,25 @@ "license": "MIT", "optional": true }, + "node_modules/motion-dom": { + "version": "12.42.2", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.42.2.tgz", + "integrity": "sha512-5gIMWLp/PycBtJRJWRgjxke5n8dlvkSn2DrYW+tr3XcqAZY1xZh6BJyooJXCM8wdfM7wfMjkBJNLge1CKPUIRA==", + "license": "MIT", + "dependencies": { + "motion-utils": "^12.39.0" + } + }, + "node_modules/motion-utils": { + "version": "12.39.0", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.39.0.tgz", + "integrity": "sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==", + "license": "MIT" + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/mute-stream": { @@ -5405,6 +10612,24 @@ "dev": true, "license": "ISC" }, + "node_modules/nanoid": { + "version": "3.3.15", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz", + "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", + "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/napi-build-utils": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", @@ -5420,6 +10645,15 @@ "dev": true, "license": "MIT" }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/node-abi": { "version": "3.92.0", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.92.0.tgz", @@ -5457,10 +10691,9 @@ "optional": true }, "node_modules/node-releases": { - "version": "2.0.47", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.47.tgz", - "integrity": "sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==", - "dev": true, + "version": "2.0.50", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.50.tgz", + "integrity": "sha512-J6l92tKHX6w8Jy5nO1Vuc01NoIiRGi/d6qBKVxh+IQ8Cr3b6HbVNfKiF8ZpFKufTwpwxMmce2W3iQZ861ZRyTg==", "license": "MIT", "engines": { "node": ">=18" @@ -5528,6 +10761,34 @@ "node": ">=10" } }, + "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==", + "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==", + "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", @@ -5541,11 +10802,19 @@ "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" @@ -5554,13 +10823,46 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object-treeify": { + "version": "1.1.33", + "resolved": "https://registry.npmjs.org/object-treeify/-/object-treeify-1.1.33.tgz", + "integrity": "sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/obug": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.3.tgz", + "integrity": "sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "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", - "optional": true, "dependencies": { "wrappy": "1" } @@ -5571,26 +10873,143 @@ "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "license": "MIT", "dependencies": { - "mimic-fn": "^2.1.0" + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", + "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "wsl-utils": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/openai": { + "version": "6.44.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-6.44.0.tgz", + "integrity": "sha512-09/gH+8jH0RgUwsgWHAaxsKGRT5zVZ95IaJUnqAWj6XejIBmnFRwq2WUIF37VtDEsmGrtPmvCs5+yBSeZGWvkA==", + "license": "Apache-2.0", + "peerDependencies": { + "ws": "^8.18.0", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", + "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "cli-cursor": "^5.0.0", + "cli-spinners": "^2.9.2", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.0.0", + "log-symbols": "^6.0.0", + "stdin-discarder": "^0.2.2", + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/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==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ora/node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" }, "engines": { - "node": ">=6" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/open": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", - "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", - "dev": true, + "node_modules/ora/node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", "license": "MIT", "dependencies": { - "default-browser": "^5.2.1", - "define-lazy-prop": "^3.0.0", - "is-inside-container": "^1.0.0", - "wsl-utils": "^0.1.0" + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" }, "engines": { "node": ">=18" @@ -5599,40 +11018,33 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/openai": { - "version": "6.44.0", - "resolved": "https://registry.npmjs.org/openai/-/openai-6.44.0.tgz", - "integrity": "sha512-09/gH+8jH0RgUwsgWHAaxsKGRT5zVZ95IaJUnqAWj6XejIBmnFRwq2WUIF37VtDEsmGrtPmvCs5+yBSeZGWvkA==", - "license": "Apache-2.0", - "peerDependencies": { - "ws": "^8.18.0", - "zod": "^3.25 || ^4.0" + "node_modules/ora/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==", + "license": "ISC", + "engines": { + "node": ">=14" }, - "peerDependenciesMeta": { - "ws": { - "optional": true - }, - "zod": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, + "node_modules/ora/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "license": "MIT", "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-limit": { @@ -5680,11 +11092,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "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==", - "dev": true, "license": "MIT", "dependencies": { "callsites": "^3.0.0" @@ -5722,6 +11142,18 @@ "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==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/parse-semver": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", @@ -5795,6 +11227,15 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/patch-console": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/patch-console/-/patch-console-2.0.0.tgz", @@ -5804,6 +11245,12 @@ "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "license": "MIT" + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -5818,7 +11265,6 @@ "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" @@ -5851,6 +11297,16 @@ "node": "20 || >=22" } }, + "node_modules/path-to-regexp": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/path-type": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", @@ -5864,6 +11320,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "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/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -5881,7 +11344,6 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -5890,6 +11352,88 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "license": "MIT", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-up/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "license": "MIT", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "license": "MIT", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-up/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/pluralize": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", @@ -5900,6 +11444,66 @@ "node": ">=4" } }, + "node_modules/postcss": { + "version": "8.5.16", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.16.tgz", + "integrity": "sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==", + "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/postcss-selector-parser": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.4.tgz", + "integrity": "sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/powershell-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz", + "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/prebuild-install": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", @@ -5936,23 +11540,111 @@ "dev": true, "license": "MIT", "engines": { - "node": ">= 0.8.0" + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.8.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.4.tgz", + "integrity": "sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "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/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/pretty-format/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/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==", + "license": "MIT", + "dependencies": { + "parse-ms": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prompts/node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "license": "MIT", + "engines": { + "node": ">=6" } }, - "node_modules/prettier": { - "version": "3.8.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.4.tgz", - "integrity": "sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==", - "dev": true, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" }, "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" + "node": ">= 0.10" } }, "node_modules/pump": { @@ -5990,7 +11682,6 @@ "version": "6.15.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" @@ -6006,7 +11697,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, "funding": [ { "type": "github", @@ -6023,6 +11713,127 @@ ], "license": "MIT" }, + "node_modules/radix-ui": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/radix-ui/-/radix-ui-1.6.0.tgz", + "integrity": "sha512-EUEC70O03EgxWMP5aoqfBZ6iLC5bczFagGy7zhSYRt8o5DP7IWNiP3ywetse3L9b8843ExB0OGWZvgbYVJuNeg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-accessible-icon": "1.1.10", + "@radix-ui/react-accordion": "1.2.14", + "@radix-ui/react-alert-dialog": "1.1.17", + "@radix-ui/react-arrow": "1.1.10", + "@radix-ui/react-aspect-ratio": "1.1.10", + "@radix-ui/react-avatar": "1.2.0", + "@radix-ui/react-checkbox": "1.3.5", + "@radix-ui/react-collapsible": "1.1.14", + "@radix-ui/react-collection": "1.1.10", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-context-menu": "2.3.1", + "@radix-ui/react-dialog": "1.1.17", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.13", + "@radix-ui/react-dropdown-menu": "2.1.18", + "@radix-ui/react-focus-guards": "1.1.4", + "@radix-ui/react-focus-scope": "1.1.10", + "@radix-ui/react-form": "0.1.10", + "@radix-ui/react-hover-card": "1.1.17", + "@radix-ui/react-label": "2.1.10", + "@radix-ui/react-menu": "2.1.18", + "@radix-ui/react-menubar": "1.1.18", + "@radix-ui/react-navigation-menu": "1.2.16", + "@radix-ui/react-one-time-password-field": "0.1.10", + "@radix-ui/react-password-toggle-field": "0.1.5", + "@radix-ui/react-popover": "1.1.17", + "@radix-ui/react-popper": "1.3.1", + "@radix-ui/react-portal": "1.1.12", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-progress": "1.1.10", + "@radix-ui/react-radio-group": "1.4.1", + "@radix-ui/react-roving-focus": "1.1.13", + "@radix-ui/react-scroll-area": "1.2.12", + "@radix-ui/react-select": "2.3.1", + "@radix-ui/react-separator": "1.1.10", + "@radix-ui/react-slider": "1.4.1", + "@radix-ui/react-slot": "1.3.0", + "@radix-ui/react-switch": "1.3.1", + "@radix-ui/react-tabs": "1.1.15", + "@radix-ui/react-toast": "1.2.17", + "@radix-ui/react-toggle": "1.1.12", + "@radix-ui/react-toggle-group": "1.1.13", + "@radix-ui/react-toolbar": "1.1.13", + "@radix-ui/react-tooltip": "1.2.10", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-effect-event": "0.0.3", + "@radix-ui/react-use-escape-keydown": "1.1.2", + "@radix-ui/react-use-is-hydrated": "0.1.1", + "@radix-ui/react-use-layout-effect": "1.1.2", + "@radix-ui/react-use-size": "1.1.2", + "@radix-ui/react-visually-hidden": "1.2.6" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/range-parser": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.3.0.tgz", + "integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "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/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -6106,6 +11917,41 @@ } } }, + "node_modules/react-dom": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", + "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.7" + } + }, + "node_modules/react-hook-form": { + "version": "7.81.0", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.81.0.tgz", + "integrity": "sha512-ocbmr2p5KBMoAfj4WCUvped33lVi1Kd5DuDUvQDnB6VEAacOjPI/jMbtDdbhco4y9ct4xUuCmMY0b/C9L0QHjw==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-hook-form" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18 || ^19" + } + }, + "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/react-reconciler": { "version": "0.33.0", "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.33.0.tgz", @@ -6121,6 +11967,75 @@ "react": "^19.2.0" } }, + "node_modules/react-remove-scroll": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", + "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/read": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", @@ -6291,11 +12206,50 @@ "node": ">= 6" } }, + "node_modules/recast": { + "version": "0.23.12", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.12.tgz", + "integrity": "sha512-dEWRjcINDu/F4l2dYx57ugBtD7HV9KXESyxhzw/MqWLeglJrsjJKqACPyUPg+6AF8mIgm+Zi0dZ3ACoIg+QtpA==", + "license": "MIT", + "dependencies": { + "ast-types": "^0.16.1", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tiny-invariant": "^1.3.3", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">= 4" + } + }, + "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/redent/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/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -6305,7 +12259,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -6331,7 +12284,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -6345,11 +12297,71 @@ "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/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/run-applescript": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -6362,7 +12374,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "funding": [ { "type": "github", @@ -6407,7 +12418,6 @@ "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/sax": { @@ -6420,6 +12430,19 @@ "node": ">=11.0.0" } }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, "node_modules/scheduler": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", @@ -6445,37 +12468,211 @@ "secretlint": "bin/secretlint.js" }, "engines": { - "node": ">=20.0.0" + "node": ">=20.0.0" + } + }, + "node_modules/section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/send/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/send/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shadcn": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/shadcn/-/shadcn-4.12.0.tgz", + "integrity": "sha512-o781ieQziCnXH2FKsEqxp1fnbHdbgAPO9inTSPeZ59hQfsZXuMGp3ul8oFSV5KQS4nbUK9b+DrDE6C7OvfKKQQ==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/parser": "^7.28.0", + "@babel/plugin-transform-typescript": "^7.28.0", + "@babel/preset-typescript": "^7.27.1", + "@dotenvx/dotenvx": "^1.48.4", + "@modelcontextprotocol/sdk": "^1.26.0", + "@types/validate-npm-package-name": "^4.0.2", + "browserslist": "^4.26.2", + "commander": "^14.0.0", + "cosmiconfig": "^9.0.0", + "dedent": "^1.6.0", + "deepmerge": "^4.3.1", + "diff": "^8.0.2", + "execa": "^9.6.0", + "fast-glob": "^3.3.3", + "fs-extra": "^11.3.1", + "fuzzysort": "^3.1.0", + "kleur": "^4.1.5", + "open": "^11.0.0", + "ora": "^8.2.0", + "postcss": "^8.5.6", + "postcss-selector-parser": "^7.1.0", + "prompts": "^2.4.2", + "recast": "^0.23.11", + "stringify-object": "^5.0.0", + "tailwind-merge": "^3.0.1", + "ts-morph": "^26.0.0", + "tsconfig-paths": "^4.2.0", + "undici": "^7.27.2", + "validate-npm-package-name": "^7.0.1", + "zod": "^3.24.1", + "zod-to-json-schema": "^3.24.6" + }, + "bin": { + "shadcn": "dist/index.js" + }, + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/shadcn/node_modules/commander": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/shadcn/node_modules/open": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/open/-/open-11.0.0.tgz", + "integrity": "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==", + "license": "MIT", + "dependencies": { + "default-browser": "^5.4.0", + "define-lazy-prop": "^3.0.0", + "is-in-ssh": "^1.0.0", + "is-inside-container": "^1.0.0", + "powershell-utils": "^0.1.0", + "wsl-utils": "^0.3.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/section-matter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", - "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "node_modules/shadcn/node_modules/wsl-utils": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.3.1.tgz", + "integrity": "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==", "license": "MIT", "dependencies": { - "extend-shallow": "^2.0.1", - "kind-of": "^6.0.0" + "is-wsl": "^3.1.0", + "powershell-utils": "^0.1.0" }, "engines": { - "node": ">=4" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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/shadcn/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" } }, "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" @@ -6488,7 +12685,6 @@ "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" @@ -6511,7 +12707,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -6531,7 +12726,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -6548,7 +12742,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -6567,7 +12760,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -6583,6 +12775,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -6638,6 +12837,12 @@ "simple-concat": "^1.0.0" } }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "license": "MIT" + }, "node_modules/slash": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", @@ -6679,6 +12884,34 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/sonner": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.7.tgz", + "integrity": "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==", + "license": "MIT", + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" + } + }, + "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==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/spdx-correct": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", @@ -6738,6 +12971,41 @@ "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/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "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/stdin-discarder": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", + "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -6775,6 +13043,35 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/stringify-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-5.0.0.tgz", + "integrity": "sha512-zaJYxz2FtcMb4f+g60KsRNFOpVMUyuJgA51Zi5Z1DOTC3S59+OQiVOzE9GZt0x72uBGWKsQIuBKeF9iusmKFsg==", + "license": "BSD-2-Clause", + "dependencies": { + "get-own-enumerable-keys": "^1.0.0", + "is-obj": "^3.0.0", + "is-regexp": "^3.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/yeoman/stringify-object?sponsor=1" + } + }, + "node_modules/stringify-object/node_modules/is-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-3.0.0.tgz", + "integrity": "sha512-IlsXEHOjtKhpN8r/tRFj2nDyTmHvcfNeu/nrRIcXE17ROeatXchkojffa1SpdqW4cr/Fj6QkEf/Gn4zf6KKvEQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/strip-ansi": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", @@ -6790,6 +13087,15 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/strip-bom-string": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", @@ -6799,6 +13105,31 @@ "node": ">=0.10.0" } }, + "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==", + "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", @@ -6852,6 +13183,39 @@ "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" } }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/systeminformation": { + "version": "5.31.11", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.31.11.tgz", + "integrity": "sha512-I6O7iaUj23AXRgCPDDnvi3xHvdOLp4+1YMbF+X194lJwY1NeWojgHJPhslVKcmTtrLTguRk3QJK+xEdTiI3P0w==", + "license": "MIT", + "os": [ + "darwin", + "linux", + "win32", + "freebsd", + "openbsd", + "netbsd", + "sunos", + "android" + ], + "bin": { + "systeminformation": "lib/cli.js" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "Buy me a coffee", + "url": "https://www.buymeacoffee.com/systeminfo" + } + }, "node_modules/table": { "version": "6.9.0", "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", @@ -6978,6 +13342,37 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/tailwind-merge": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.6.0.tgz", + "integrity": "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.1.tgz", + "integrity": "sha512-hk+TB1m+K8CYNrP6rjQaq/Y+4Zylwpa87mLYBKCunwnnQ9p+fHb7kmSfGqyEJoxF/O6CDyABWVFEafNSYKll+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/tar-fs": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", @@ -7062,6 +13457,19 @@ "url": "https://bevry.me/fund" } }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, + "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/tinycolor2": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", @@ -7105,6 +13513,36 @@ "tinycolor2": "^1.0.0" } }, + "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/tldts": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.7.tgz", + "integrity": "sha512-56L0/9HELHSsG1bFCzay8UoLxzRL7kpFf7Wl5q/kSYwiSJGACvro61xnKzPNM+SadxllzdtXsKDSXE7HPeqIAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^7.4.7" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.7.tgz", + "integrity": "sha512-rNlAI8fKn/JckBMUSbNL/ES2kmDiurWaE49l+ikwEc9A6lFR7gMx9AhgQMQKBK4H5w4pKLH64JzZfB99uRsGNQ==", + "dev": true, + "license": "MIT" + }, "node_modules/tmp": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz", @@ -7119,7 +13557,6 @@ "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" @@ -7128,6 +13565,41 @@ "node": ">=8.0" } }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.2.tgz", + "integrity": "sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^7.0.5" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", + "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/ts-api-utils": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", @@ -7141,11 +13613,34 @@ "typescript": ">=4.8.4" } }, + "node_modules/ts-morph": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-26.0.0.tgz", + "integrity": "sha512-ztMO++owQnz8c/gIENcM9XfCEzgoGphTv+nKpYNM1bgsdOVC/jRZuEBf6N+mLLDNg68Kl+GgUZfOySaRiG1/Ug==", + "license": "MIT", + "dependencies": { + "@ts-morph/common": "~0.27.0", + "code-block-writer": "^13.0.3" + } + }, + "node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "license": "MIT", + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "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==", - "dev": true, "license": "0BSD" }, "node_modules/tsx": { @@ -7191,6 +13686,16 @@ "node": "*" } }, + "node_modules/tw-animate-css": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.4.0.tgz", + "integrity": "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Wombosvideo" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -7204,19 +13709,75 @@ "node": ">= 0.8.0" } }, - "node_modules/type-fest": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.7.0.tgz", - "integrity": "sha512-1URUxUqfHFM1c+zfSPsa3gnkO7Aq21qyH75SIduNYz4SzY964rn1X2vCMQaHSHhktiw+0kPa2iyb6PUpXqB6Vg==", - "license": "(MIT OR CC0-1.0)", + "node_modules/type-fest": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.7.0.tgz", + "integrity": "sha512-1URUxUqfHFM1c+zfSPsa3gnkO7Aq21qyH75SIduNYz4SzY964rn1X2vCMQaHSHhktiw+0kPa2iyb6PUpXqB6Vg==", + "license": "(MIT OR CC0-1.0)", + "dependencies": { + "tagged-tag": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", + "license": "MIT", + "dependencies": { + "content-type": "^2.0.0", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", "dependencies": { - "tagged-tag": "^1.0.0" + "mime-db": "^1.54.0" }, "engines": { - "node": ">=20" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/typed-rest-client": { @@ -7235,7 +13796,7 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -7302,7 +13863,6 @@ "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" @@ -7315,17 +13875,24 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 10.0.0" } }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "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", @@ -7369,13 +13936,54 @@ "dev": true, "license": "MIT" }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "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", - "optional": true + "license": "MIT" }, "node_modules/validate-npm-package-license": { "version": "3.0.4", @@ -7387,6 +13995,37 @@ "spdx-expression-parse": "^3.0.0" } }, + "node_modules/validate-npm-package-name": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-7.0.2.tgz", + "integrity": "sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==", + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vaul": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vaul/-/vaul-1.1.2.tgz", + "integrity": "sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-dialog": "^1.1.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" + } + }, "node_modules/version-range": { "version": "4.15.0", "resolved": "https://registry.npmjs.org/version-range/-/version-range-4.15.0.tgz", @@ -7400,6 +14039,194 @@ "url": "https://bevry.me/fund" } }, + "node_modules/vite": { + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.6.tgz", + "integrity": "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0 || ^0.28.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "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/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/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", + "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } + }, "node_modules/whatwg-encoding": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", @@ -7424,11 +14251,25 @@ "node": ">=18" } }, + "node_modules/whatwg-url": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz", + "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.11.0", + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, "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" @@ -7440,6 +14281,23 @@ "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/widest-line": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-6.0.0.tgz", @@ -7498,9 +14356,7 @@ "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", - "optional": true + "license": "ISC" }, "node_modules/ws": { "version": "8.21.0", @@ -7539,6 +14395,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, "node_modules/xml2js": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", @@ -7563,6 +14429,13 @@ "node": ">=4.0" } }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -7576,7 +14449,6 @@ "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": { @@ -7675,6 +14547,33 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/yocto-spinner": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/yocto-spinner/-/yocto-spinner-1.2.0.tgz", + "integrity": "sha512-Yw0hUB6UA3o4YUgKy3oSe9a4cxoaZ9sBfYDw+JSxo6Id0KoJGoxzPA24qqUXYKBWABs/zDSGTz9kww7t3F0XGw==", + "license": "MIT", + "dependencies": { + "yoctocolors": "^2.1.1" + }, + "engines": { + "node": ">=18.19" + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/yoga-layout": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/yoga-layout/-/yoga-layout-3.2.1.tgz", @@ -7690,6 +14589,15 @@ "url": "https://github.com/sponsors/colinhacks" } }, + "node_modules/zod-to-json-schema": { + "version": "3.25.2", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", + "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.25.28 || ^4" + } + }, "node_modules/zod-validation-error": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", @@ -7786,20 +14694,144 @@ }, "packages/vscode-ide-companion": { "name": "deepcode-vscode", - "version": "0.1.23", + "version": "0.2.0", + "license": "MIT", + "dependencies": { + "@fontsource-variable/inter": "^5.2.8", + "@hookform/resolvers": "^5.4.0", + "@radix-ui/react-collapsible": "^1.1.14", + "@radix-ui/react-popover": "^1.1.17", + "@radix-ui/react-scroll-area": "^1.2.12", + "@radix-ui/react-separator": "^1.1.10", + "@radix-ui/react-slot": "^1.3.0", + "@radix-ui/react-tooltip": "^1.2.10", + "@tanstack/react-query": "^5.90.11", + "@vegamo/deepcode-core": "file:../core", + "@webview-rpc/client": "^1.0.17", + "@webview-rpc/host": "^1.0.17", + "@webview-rpc/react-query": "^1.0.17", + "cmdk": "^1.1.1", + "framer-motion": "^12.42.2", + "lucide-react": "^1.21.0", + "markdown-it": "^14.2.0", + "radix-ui": "^1.6.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "react-hook-form": "^7.81.0", + "shadcn": "^4.12.0", + "sonner": "^2.0.7", + "vaul": "^1.1.2", + "zod": "^4.1.13" + }, + "devDependencies": { + "@tailwindcss/vite": "^4.3.1", + "@testing-library/dom": "^10.4.1", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.2", + "@types/markdown-it": "^14.1.1", + "@types/node": "22.x", + "@types/react": "^19.2.2", + "@types/react-dom": "^19.2.2", + "@types/vscode": "^1.85.0", + "@vitejs/plugin-react-swc": "^4.2.1", + "@vscode/vsce": "^3.6.0", + "autoprefixer": "^10.5.0", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "esbuild": "^0.28.1", + "jsdom": "^29.1.1", + "postcss": "^8.5.15", + "tailwind-merge": "^3.6.0", + "tailwindcss": "^4.3.1", + "tw-animate-css": "^1.4.0", + "typescript": "^5.9.2", + "vite": "^7.2.2", + "vitest": "^4.1.10" + }, + "engines": { + "vscode": "^1.85.0" + } + }, + "packages/vscode-ide-companion-v2": { + "name": "deepcode-vscode-v2", + "version": "0.2.0", + "extraneous": true, "license": "MIT", "dependencies": { + "@fontsource-variable/inter": "^5.2.8", + "@radix-ui/react-collapsible": "^1.1.14", + "@radix-ui/react-popover": "^1.1.17", + "@radix-ui/react-scroll-area": "^1.2.12", + "@radix-ui/react-separator": "^1.1.10", + "@radix-ui/react-slot": "^1.3.0", + "@radix-ui/react-tooltip": "^1.2.10", + "@tanstack/react-query": "^5.90.11", "@vegamo/deepcode-core": "file:../core", - "markdown-it": "^14.2.0" + "@webview-rpc/client": "^1.0.17", + "@webview-rpc/host": "^1.0.17", + "@webview-rpc/react-query": "^1.0.17", + "lucide-react": "^1.21.0", + "markdown-it": "^14.2.0", + "radix-ui": "^1.6.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "shadcn": "^4.12.0", + "zod": "^4.1.13" }, "devDependencies": { + "@tailwindcss/vite": "^4.3.1", "@types/markdown-it": "^14.1.1", + "@types/node": "22.x", + "@types/react": "^19.2.2", + "@types/react-dom": "^19.2.2", "@types/vscode": "^1.85.0", - "@vscode/vsce": "^3.6.0" + "@vitejs/plugin-react-swc": "^4.2.1", + "@vscode/vsce": "^3.6.0", + "autoprefixer": "^10.5.0", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "esbuild": "^0.28.1", + "postcss": "^8.5.15", + "tailwind-merge": "^3.6.0", + "tailwindcss": "^4.3.1", + "tw-animate-css": "^1.4.0", + "typescript": "^5.9.2", + "vite": "^7.2.2" }, "engines": { "vscode": "^1.85.0" } + }, + "packages/vscode-ide-companion/node_modules/@types/node": { + "version": "22.20.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.0.tgz", + "integrity": "sha512-QWlFW2wf3nTjC13/DqRnBpR4ZO36VJH/JVBkA/vcnmbTBNQIlnObqyqZE1tUR7+Ni23Lda8R1BxMfbXRpCUx5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "packages/vscode-ide-companion/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" + } + }, + "packages/vscode-ide-companion/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" } } } diff --git a/packages/vscode-ide-companion/.vscode/launch.json b/packages/vscode-ide-companion/.vscode/launch.json new file mode 100644 index 00000000..d2964591 --- /dev/null +++ b/packages/vscode-ide-companion/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug VS Code Companion", + "type": "extensionHost", + "request": "launch", + "args": ["--extensionDevelopmentPath=${workspaceFolder}"], + "outFiles": ["${workspaceFolder}/dist/**/*.js"], + "preLaunchTask": "npm: dev:webview", + "presentation": { + "group": "deepcode" + } + } + ] +} diff --git a/packages/vscode-ide-companion/.vscode/tasks.json b/packages/vscode-ide-companion/.vscode/tasks.json new file mode 100644 index 00000000..2b548770 --- /dev/null +++ b/packages/vscode-ide-companion/.vscode/tasks.json @@ -0,0 +1,42 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "type": "npm", + "script": "dev:webview", + "isBackground": true, + "problemMatcher": { + "owner": "custom", + "pattern": { + "regexp": "^$" + }, + "background": { + "activeOnStart": true, + "beginsPattern": "^.*VITE.*$", + "endsPattern": "^.*ready in.*$" + } + }, + "group": { + "kind": "none", + "isDefault": true + } + }, + { + "type": "npm", + "script": "watch", + "isBackground": true, + "problemMatcher": { + "owner": "custom", + "pattern": { + "regexp": "^$" + }, + "background": { + "activeOnStart": true, + "beginsPattern": "^.*Watching.*$", + "endsPattern": "^$" + } + }, + "group": "none" + } + ] +} diff --git a/packages/vscode-ide-companion/.vscodeignore b/packages/vscode-ide-companion/.vscodeignore new file mode 100644 index 00000000..c9315412 --- /dev/null +++ b/packages/vscode-ide-companion/.vscodeignore @@ -0,0 +1,12 @@ +.vscode/** +.vscode-test/** +src/** +node_modules/** +.eslintrc* +.gitignore +tsconfig.json +tsconfig.webview.json +vite.config.ts +esbuild.config.mjs +components.json +vitest.config.ts diff --git a/packages/vscode-ide-companion/README.md b/packages/vscode-ide-companion/README.md deleted file mode 100644 index ee11be0f..00000000 --- a/packages/vscode-ide-companion/README.md +++ /dev/null @@ -1,94 +0,0 @@ -# Deep Code - -[Deep Code](https://marketplace.visualstudio.com/items?itemName=vegamo.deepcode-vscode) 是 Visual Studio Code 的 AI 编码助手扩展,专门为最新的 `deepseek-v4` 模型优化。 - -## 配置 - -创建 `~/.deepcode/settings.json` 文件,内容如下: - -```json -{ - "env": { - "MODEL": "deepseek-v4-pro", - "BASE_URL": "https://api.deepseek.com", - "API_KEY": "sk-..." - }, - "thinkingEnabled": true, - "reasoningEffort": "max" -} -``` - -## 主要功能 - -### **Skills** -Deep Code 支持 agent skills,允许您扩展助手的能力: - -- **User-level Skills**:从 `~/.agents/skills/` 目录中发现并激活 skills。 -- **Project-level Skills**:从 `./.agents/skills/` 目录中加载项目专属 skills,并兼容旧的 `./.deepcode/skills/` 目录。 - -### **为 DeepSeek 优化** -- 专门为 DeepSeek 模型性能调优。 -- 通过使用[上下文缓存](https://api-docs.deepseek.com/guides/kv_cache)来降低成本。 -- 原生支持[思考模式](https://api-docs.deepseek.com/guides/thinking_mode)和思考强度控制。 - -## 支持的模型 - -- `deepseek-v4-pro`(推荐使用) -- `deepseek-v4-flash` -- 任何其他 OpenAI 兼容模型 - -## 截图示例 - -![screenshot](resources/deepcode_screenshot.png) - -## Deep Code CLI - -```bash -npm install -g @vegamo/deepcode-cli -``` - -![intro1](https://raw.githubusercontent.com/lessweb/deepcode-cli/main/resources/intro1.png) - -> VSCode插件和CLI共享配置文件和数据,但运行时没有依赖。 - -- GitHub: https://github.com/lessweb/deepcode-cli - -## 常见问题 - -### 如何将 Deep Code 从左侧边栏移动到右侧边栏(Secondary Side Bar)? - -![faq1](resources/faq1.gif) - -### Deep Code是否支持理解图片? - -Deep Code支持多模态,但目前deepseek-v4不支持多模态。有些模型虽然有多模态能力,但对多轮对话请求的限制太严。目前多模态输入推荐使用火山方舟的Doubao-Seed-2.0-pro模型,适配效果最好。 - -### 怎样在任务完成后自动给Slack发消息? - -编写一个调用Slack webhook的Shell通知脚本,然后在`~/.deepcode/settings.json`中将`notify`字段设为该脚本的完整路径即可。详细步骤可参考:https://binfer.net/share/jby5xnc-so6g - -### 是否支持Coding Plan? - -支持。只要把`~/.deepcode/settings.json`的env.BASE_URL配置为OpenAI兼容的接口地址就行。以火山方舟的Coding Plan为例,`~/.deepcode/settings.json`这样配置: - -```json -{ - "env": { - "MODEL": "ark-code-latest", - "BASE_URL": "https://ark.cn-beijing.volces.com/api/coding/v3", - "API_KEY": "**************" - }, - "thinkingEnabled": true -} -``` - -## 获取帮助 -- 在 GitHub Issues 上报告错误或请求功能 (https://github.com/lessweb/deepcode/issues) - -## 支持我们 - -如果你觉得这个插件对你有帮助,请考虑通过以下方式支持我们: - -- 在 GitHub 上给我们一个 Star (https://github.com/lessweb/deepcode) -- 向我们提交反馈和建议 -- 分享给你的朋友和同事 diff --git a/packages/vscode-ide-companion/README_cn.md b/packages/vscode-ide-companion/README_cn.md deleted file mode 100644 index ee11be0f..00000000 --- a/packages/vscode-ide-companion/README_cn.md +++ /dev/null @@ -1,94 +0,0 @@ -# Deep Code - -[Deep Code](https://marketplace.visualstudio.com/items?itemName=vegamo.deepcode-vscode) 是 Visual Studio Code 的 AI 编码助手扩展,专门为最新的 `deepseek-v4` 模型优化。 - -## 配置 - -创建 `~/.deepcode/settings.json` 文件,内容如下: - -```json -{ - "env": { - "MODEL": "deepseek-v4-pro", - "BASE_URL": "https://api.deepseek.com", - "API_KEY": "sk-..." - }, - "thinkingEnabled": true, - "reasoningEffort": "max" -} -``` - -## 主要功能 - -### **Skills** -Deep Code 支持 agent skills,允许您扩展助手的能力: - -- **User-level Skills**:从 `~/.agents/skills/` 目录中发现并激活 skills。 -- **Project-level Skills**:从 `./.agents/skills/` 目录中加载项目专属 skills,并兼容旧的 `./.deepcode/skills/` 目录。 - -### **为 DeepSeek 优化** -- 专门为 DeepSeek 模型性能调优。 -- 通过使用[上下文缓存](https://api-docs.deepseek.com/guides/kv_cache)来降低成本。 -- 原生支持[思考模式](https://api-docs.deepseek.com/guides/thinking_mode)和思考强度控制。 - -## 支持的模型 - -- `deepseek-v4-pro`(推荐使用) -- `deepseek-v4-flash` -- 任何其他 OpenAI 兼容模型 - -## 截图示例 - -![screenshot](resources/deepcode_screenshot.png) - -## Deep Code CLI - -```bash -npm install -g @vegamo/deepcode-cli -``` - -![intro1](https://raw.githubusercontent.com/lessweb/deepcode-cli/main/resources/intro1.png) - -> VSCode插件和CLI共享配置文件和数据,但运行时没有依赖。 - -- GitHub: https://github.com/lessweb/deepcode-cli - -## 常见问题 - -### 如何将 Deep Code 从左侧边栏移动到右侧边栏(Secondary Side Bar)? - -![faq1](resources/faq1.gif) - -### Deep Code是否支持理解图片? - -Deep Code支持多模态,但目前deepseek-v4不支持多模态。有些模型虽然有多模态能力,但对多轮对话请求的限制太严。目前多模态输入推荐使用火山方舟的Doubao-Seed-2.0-pro模型,适配效果最好。 - -### 怎样在任务完成后自动给Slack发消息? - -编写一个调用Slack webhook的Shell通知脚本,然后在`~/.deepcode/settings.json`中将`notify`字段设为该脚本的完整路径即可。详细步骤可参考:https://binfer.net/share/jby5xnc-so6g - -### 是否支持Coding Plan? - -支持。只要把`~/.deepcode/settings.json`的env.BASE_URL配置为OpenAI兼容的接口地址就行。以火山方舟的Coding Plan为例,`~/.deepcode/settings.json`这样配置: - -```json -{ - "env": { - "MODEL": "ark-code-latest", - "BASE_URL": "https://ark.cn-beijing.volces.com/api/coding/v3", - "API_KEY": "**************" - }, - "thinkingEnabled": true -} -``` - -## 获取帮助 -- 在 GitHub Issues 上报告错误或请求功能 (https://github.com/lessweb/deepcode/issues) - -## 支持我们 - -如果你觉得这个插件对你有帮助,请考虑通过以下方式支持我们: - -- 在 GitHub 上给我们一个 Star (https://github.com/lessweb/deepcode) -- 向我们提交反馈和建议 -- 分享给你的朋友和同事 diff --git a/packages/vscode-ide-companion/README_en.md b/packages/vscode-ide-companion/README_en.md deleted file mode 100644 index 40b199bc..00000000 --- a/packages/vscode-ide-companion/README_en.md +++ /dev/null @@ -1,87 +0,0 @@ -# Deep Code - -[Deep Code](https://marketplace.visualstudio.com/items?itemName=vegamo.deepcode-vscode) is an AI coding assistant extension for Visual Studio Code, specifically optimized for the latest `deepseek-v4` model. - -## Configuration - -Create `~/.deepcode/settings.json` with: - -```json -{ - "env": { - "MODEL": "deepseek-v4-pro", - "BASE_URL": "https://api.deepseek.com", - "API_KEY": "sk-..." - }, - "thinkingEnabled": true, - "reasoningEffort": "max" -} -``` - -## Key Features - -### **Skills** -Deep Code supports agent skills that allows you to extend the assistant's capabilities: - -- **User-level Skills**: discovered and activated from `~/.agents/skills/`. -- **Project-level Skills**: loaded from `./.agents/skills/` for project-specific workflows, with legacy `./.deepcode/skills/` compatibility. - -### **Optimized for DeepSeek** -- Specifically tuned for DeepSeek model performance. -- Reduce costs by using [Context Caching](https://api-docs.deepseek.com/guides/kv_cache). -- Natively supports [Thinking Mode](https://api-docs.deepseek.com/guides/thinking_mode) and Thinking Effort Control. - -## Supported Models - -- `deepseek-v4-pro` (Recommended) -- `deepseek-v4-flash` -- `deepseek-chat` -- Any other OpenAI-compatible model - -## Screenshot - -![screenshot](resources/deepcode_screenshot.png) - -## Deep Code CLI - -```bash -npm install -g @vegamo/deepcode-cli -``` - -![intro1](https://raw.githubusercontent.com/lessweb/deepcode-cli/main/resources/intro1.png) - -> The VSCode plugin and CLI share configuration and data, but they have no dependencies at runtime. - -- GitHub: https://github.com/lessweb/deepcode-cli - -## FAQ - -### How can I move Deep Code from the left sidebar to the right (Secondary Side Bar) in VS Code? - -![faq1](resources/faq1.gif) - -### Does Deep Code support understanding images? - -Deep Code supports multimodal, but `deepseek-v4` does not support multimodal yet. Some models have multimodal capabilities but impose strict limits on multi-turn dialogue requests. For multimodal input, we recommend using the Volcano Ark `Doubao-Seed-2.0-pro` model, which has the best integration. - -### How to automatically send a Slack message after a task completes? - -Write a shell notification script that calls a Slack webhook, then set the `notify` field in `~/.deepcode/settings.json` to the full path of the script. For detailed steps, refer to: https://binfer.net/share/jby5xnc-so6g - -### Does it support Coding Plan? - -Yes. Just set `env.BASE_URL` in `~/.deepcode/settings.json` to an OpenAI-compatible API endpoint. Take Volcano Ark's Coding Plan as an example, configure `~/.deepcode/settings.json` as follows: - -```json -{ - "env": { - "MODEL": "ark-code-latest", - "BASE_URL": "https://ark.cn-beijing.volces.com/api/coding/v3", - "API_KEY": "**************" - }, - "thinkingEnabled": true -} -``` - -## Getting Help -- Report bugs or request features on GitHub Issues (https://github.com/lessweb/deepcode/issues) diff --git a/packages/vscode-ide-companion/resources/deepcoding_icon.png b/packages/vscode-ide-companion/assets/deepcoding_icon.png similarity index 100% rename from packages/vscode-ide-companion/resources/deepcoding_icon.png rename to packages/vscode-ide-companion/assets/deepcoding_icon.png diff --git a/packages/vscode-ide-companion/resources/deepcoding_icon.svg b/packages/vscode-ide-companion/assets/deepcoding_icon.svg similarity index 100% rename from packages/vscode-ide-companion/resources/deepcoding_icon.svg rename to packages/vscode-ide-companion/assets/deepcoding_icon.svg diff --git a/packages/vscode-ide-companion/assets/theme.svg b/packages/vscode-ide-companion/assets/theme.svg new file mode 100644 index 00000000..867c46d2 --- /dev/null +++ b/packages/vscode-ide-companion/assets/theme.svg @@ -0,0 +1 @@ + diff --git a/packages/vscode-ide-companion/components.json b/packages/vscode-ide-companion/components.json new file mode 100644 index 00000000..f6f78e8e --- /dev/null +++ b/packages/vscode-ide-companion/components.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "radix-vega", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "", + "css": "src/webview/index.css", + "baseColor": "mauve", + "cssVariables": true, + "prefix": "" + }, + "iconLibrary": "lucide", + "rtl": false, + "aliases": { + "components": "@/webview/components", + "utils": "@/webview/lib/utils", + "ui": "@/webview/components/ui", + "lib": "@/webview/lib", + "hooks": "@/webview/hooks" + }, + "menuColor": "default", + "menuAccent": "subtle", + "registries": {} +} diff --git a/packages/vscode-ide-companion/esbuild.config.mjs b/packages/vscode-ide-companion/esbuild.config.mjs new file mode 100644 index 00000000..ee19c992 --- /dev/null +++ b/packages/vscode-ide-companion/esbuild.config.mjs @@ -0,0 +1,49 @@ +/* global console, process */ +import * as esbuild from "esbuild"; +import { cpSync, existsSync, rmSync } from "node:fs"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const root = join(__dirname); +const packagesRoot = join(__dirname, ".."); +const coreTemplates = join(packagesRoot, "core", "templates"); +const localTemplates = join(root, "templates"); + +// Copy templates from core for development +if (existsSync(coreTemplates)) { + if (existsSync(localTemplates)) { + rmSync(localTemplates, { recursive: true, force: true }); + } + cpSync(coreTemplates, localTemplates, { recursive: true, dereference: true }); + console.log("✅ Copied core/templates/ → templates/ (for development)"); +} + +const isWatch = process.argv.includes("--watch"); + +/** @type {import('esbuild').BuildOptions} */ +const options = { + entryPoints: ["src/extension.ts"], + outfile: "dist/extension.js", + bundle: true, + format: "esm", + platform: "node", + target: "ES2022", + sourcemap: true, + minify: !isWatch, + external: ["vscode"], + // Inject a `require` function via createRequire so that dynamic require() + // calls from bundled CJS dependencies work in VSCode's ESM extension host. + banner: { + js: `import { createRequire as __deepcodeCreateRequire } from "node:module";var require = __deepcodeCreateRequire(import.meta.url);`, + }, +}; + +if (isWatch) { + const ctx = await esbuild.context(options); + await ctx.watch(); + console.log("Watching for changes..."); +} else { + await esbuild.build(options); + console.log("\n✅ dist/extension.js built successfully\n"); +} diff --git a/packages/vscode-ide-companion/eslint.config.mjs b/packages/vscode-ide-companion/eslint.config.mjs new file mode 100644 index 00000000..ee788d17 --- /dev/null +++ b/packages/vscode-ide-companion/eslint.config.mjs @@ -0,0 +1,38 @@ +import typescriptEslint from "@typescript-eslint/eslint-plugin"; +import tsParser from "@typescript-eslint/parser"; +import prettierConfig from "eslint-config-prettier"; + +export default [ + { + files: ["**/*.ts", "**/*.tsx"], + }, + { + plugins: { + "@typescript-eslint": typescriptEslint, + }, + + languageOptions: { + parser: tsParser, + parserOptions: { + jsx: true, + }, + ecmaVersion: 2022, + sourceType: "module", + }, + + rules: { + "@typescript-eslint/naming-convention": [ + "warn", + { + selector: "import", + format: ["camelCase", "PascalCase"], + }, + ], + + curly: "warn", + eqeqeq: "warn", + "no-throw-literal": "warn", + }, + }, + prettierConfig, // 禁用与 Prettier 冲突的 ESLint 规则 +]; diff --git a/packages/vscode-ide-companion/package.json b/packages/vscode-ide-companion/package.json index fc7f8118..34462888 100644 --- a/packages/vscode-ide-companion/package.json +++ b/packages/vscode-ide-companion/package.json @@ -1,12 +1,12 @@ { "name": "deepcode-vscode", - "version": "0.1.23", + "version": "0.2.0", "publisher": "vegamo", "displayName": "Deep Code", "description": "Deep Code VSCode companion — AI-assisted development in your editor", "license": "MIT", - "type": "commonjs", - "main": "./out/extension.js", + "type": "module", + "main": "./dist/extension.js", "preview": true, "repository": { "type": "git", @@ -29,16 +29,10 @@ "ide integration", "ide companion" ], - "icon": "resources/deepcoding_icon.png", - "activationEvents": [], - "files": [ - "out/extension.js", - "resources/**", - "templates/**", - "README.md", - "README_cn.md", - "README_en.md", - "LICENSE" + "icon": "assets/deepcoding_icon.png", + "activationEvents": [ + "onStartupFinished", + "onView:deepcode.chatView" ], "contributes": { "commands": [ @@ -46,8 +40,8 @@ "command": "deepcode.openView", "title": "Open Deep Code", "icon": { - "light": "resources/deepcoding_icon.svg", - "dark": "resources/deepcoding_icon.svg" + "light": "assets/deepcoding_icon.svg", + "dark": "assets/deepcoding_icon.svg" } } ], @@ -56,7 +50,7 @@ { "id": "deepcode", "title": "Deep Code", - "icon": "resources/deepcoding_icon.png" + "icon": "assets/deepcoding_icon.png" } ] }, @@ -65,7 +59,7 @@ { "id": "deepcode.chatView", "name": "Deep Code", - "icon": "resources/deepcoding_icon.png", + "icon": "assets/deepcoding_icon.png", "type": "webview" } ] @@ -80,19 +74,68 @@ } }, "scripts": { - "typecheck": "tsc -p ./ --noEmit", - "build": "node ../../scripts/esbuild-vscode.config.js", - "prepublishOnly": "npm run build", - "package": "vsce package --no-dependencies", - "test": "node src/tests/run-tests.mjs" + "typecheck": "tsc -p ./ --noEmit && tsc -p tsconfig.webview.json --noEmit", + "dev:webview": "vite", + "watch": "node esbuild.config.mjs --watch", + "build:webview": "vite build", + "build": "node scripts/copy-templates.js && node esbuild.config.mjs", + "vscode:prepublish": "npm run build:webview && npm run build", + "package": "vsce package --no-dependencies --allow-missing-repository", + "test": "vitest run", + "test:watch": "vitest", + "test:ui": "vitest --ui", + "test:coverage": "vitest run --coverage" }, "dependencies": { + "@fontsource-variable/inter": "^5.2.8", + "@hookform/resolvers": "^5.4.0", + "@radix-ui/react-collapsible": "^1.1.14", + "@radix-ui/react-popover": "^1.1.17", + "@radix-ui/react-scroll-area": "^1.2.12", + "@radix-ui/react-separator": "^1.1.10", + "@radix-ui/react-slot": "^1.3.0", + "@radix-ui/react-tooltip": "^1.2.10", + "@tanstack/react-query": "^5.90.11", "@vegamo/deepcode-core": "file:../core", - "markdown-it": "^14.2.0" + "@webview-rpc/client": "^1.0.17", + "@webview-rpc/host": "^1.0.17", + "@webview-rpc/react-query": "^1.0.17", + "cmdk": "^1.1.1", + "framer-motion": "^12.42.2", + "lucide-react": "^1.21.0", + "markdown-it": "^14.2.0", + "radix-ui": "^1.6.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "react-hook-form": "^7.81.0", + "shadcn": "^4.12.0", + "sonner": "^2.0.7", + "vaul": "^1.1.2", + "zod": "^4.1.13" }, "devDependencies": { + "@tailwindcss/vite": "^4.3.1", + "@testing-library/dom": "^10.4.1", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.2", "@types/markdown-it": "^14.1.1", + "@types/node": "22.x", + "@types/react": "^19.2.2", + "@types/react-dom": "^19.2.2", "@types/vscode": "^1.85.0", - "@vscode/vsce": "^3.6.0" + "@vitejs/plugin-react-swc": "^4.2.1", + "@vscode/vsce": "^3.6.0", + "autoprefixer": "^10.5.0", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "esbuild": "^0.28.1", + "jsdom": "^29.1.1", + "postcss": "^8.5.15", + "tailwind-merge": "^3.6.0", + "tailwindcss": "^4.3.1", + "tw-animate-css": "^1.4.0", + "typescript": "^5.9.2", + "vite": "^7.2.2", + "vitest": "^4.1.10" } } diff --git a/packages/vscode-ide-companion/resources/deepcode_screenshot.png b/packages/vscode-ide-companion/resources/deepcode_screenshot.png deleted file mode 100644 index 3e1f2a9d4cfbb0390034474d1daddd1897cf6568..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 357519 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 z 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%0D24v6 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ÄutX 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%0AY4-%#+&uKg;9Rbbb=< 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ÒSH8jAuPoT5xQOjUtomB(r)!!7>o#(F0UPw7D11g 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

d<(5R zfWVOdlj6ccMrP*kqy)cP|L^9mW|0CioiDKo39Gu5x)3!%&>Kz4Vpe!#OS?RU&}AnL z+iz0(2jRF2Kj=JvQXl8NpJuE~QCs3aO)aO#9e&WCc+3fmCde9AzBiyZq0BpJrya>n z>tDdVoNT58KEFlph!J=N7od@mxnigOz#f@LH4H;K9`6 zi*>$HLOPOr(({+)z+k;r#Mk`~TGV3;ydcOa=U|-=&E1F=rVyd$^${YbsB!UFXhu{i zm^0I>7B=tdIrLd1eHu6`B+&xukBP&;I>Pmb5;HVYF7~8dAd%&wu({$nbG<^n)54d0 zOIE1I3&~I!_gL=D`2gZ65!kOBd6f6RnG^olABP?RtB}p>=y9tW@(3x8WP{%>Jzk4= zL{#yLpNBuG5du1RLm+@WQB5I$=^kgAY&a0irsFFe8hT!6oV zT_KcO$aq57elJ~0N6%_xg2kBU=NREuO^P$6tvbapSiet<^J;|f77nA2>i8*`#GcmU zBPayd%`HFqYZ-KIM3bKAzWI%?9V4!dv{&t0{8}N%t@Qd>|{O L2r85K`04)vaX67( diff --git a/packages/vscode-ide-companion/resources/faq1.gif b/packages/vscode-ide-companion/resources/faq1.gif deleted file mode 100644 index 93d694497af26e6122e1e3ff50940990bbf84953..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 186246 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⪙ouSZ)M+%iGF!$ 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 { - const reader = new FileReader(); - reader.onload = () => resolve(typeof reader.result === "string" ? reader.result : ""); - reader.onerror = () => reject(reader.error || new Error("Failed to read file.")); - reader.readAsDataURL(file); - }); - } - - function pickImageFileFromClipboard(event) { - const items = Array.from(event.clipboardData?.items || []); - for (const item of items) { - if (item.kind !== "file") { - continue; - } - const file = item.getAsFile(); - if (isImageFile(file)) { - return file; - } - } - return null; - } - - function createPromptAttachmentManager(options) { - const promptInput = options?.promptInput; - const inputWrap = options?.inputWrap; - const toolsLine = options?.toolsLine; - const onAttachmentChange = - typeof options?.onAttachmentChange === "function" ? options.onAttachmentChange : function () {}; - - if (!promptInput || !inputWrap || !toolsLine) { - throw new Error("Prompt attachment manager requires promptInput, inputWrap, and toolsLine."); - } - - let attachments = []; - let nextAttachmentId = 0; - let previewPopup = null; - let previewImage = null; - let previewAnchor = null; - - function ensurePreviewPopup() { - if (previewPopup) { - return; - } - - previewPopup = createElement("div", "chat-attached-context-preview"); - previewImage = createElement("img", "chat-attached-context-preview-image"); - previewImage.alt = ATTACHMENT_LABEL; - previewPopup.appendChild(previewImage); - document.body.appendChild(previewPopup); - } - - function hidePreview() { - if (!previewPopup) { - return; - } - previewAnchor = null; - previewPopup.classList.remove("show"); - } - - function updatePreviewPosition(anchor) { - if (!previewPopup || !anchor) { - return; - } - - const rect = anchor.getBoundingClientRect(); - const popupRect = previewPopup.getBoundingClientRect(); - const viewportWidth = window.innerWidth; - const viewportHeight = window.innerHeight; - - let left = rect.left; - let top = rect.top - popupRect.height - PREVIEW_OFFSET; - - if (left + popupRect.width > viewportWidth - 12) { - left = viewportWidth - popupRect.width - 12; - } - if (left < 12) { - left = 12; - } - if (top < 12) { - top = rect.bottom + PREVIEW_OFFSET; - } - if (top + popupRect.height > viewportHeight - 12) { - top = Math.max(12, viewportHeight - popupRect.height - 12); - } - - previewPopup.style.left = left + "px"; - previewPopup.style.top = top + "px"; - } - - function showPreview(anchor, attachment) { - if (!attachment) { - return; - } - - ensurePreviewPopup(); - previewAnchor = anchor; - previewImage.src = attachment.dataUrl; - previewPopup.classList.add("show"); - updatePreviewPosition(anchor); - } - - function emitChange() { - onAttachmentChange({ - hasAttachments: attachments.length > 0, - attachments: attachments.slice(), - }); - } - - function clear() { - attachments = []; - toolsLine.innerHTML = ""; - toolsLine.classList.remove("has-attachment"); - hidePreview(); - emitChange(); - } - - function removeAttachment(id) { - const nextAttachments = attachments.filter((attachment) => attachment.id !== id); - if (nextAttachments.length === attachments.length) { - return; - } - attachments = nextAttachments; - render(); - emitChange(); - } - - function createAttachmentNode(attachment) { - const wrapper = createElement("div", "chat-attached-context-attachment show-file-icons"); - wrapper.tabIndex = 0; - wrapper.setAttribute("role", "button"); - wrapper.setAttribute("aria-label", ATTACHMENT_LABEL + " (删除)"); - wrapper.dataset.attachmentId = String(attachment.id); - wrapper.draggable = true; - - const removeButton = createElement("a", "monaco-button codicon codicon-close"); - removeButton.tabIndex = -1; - removeButton.setAttribute("role", "button"); - removeButton.setAttribute("aria-label", "从上下文中移除"); - removeButton.href = "#"; - removeButton.textContent = "×"; - removeButton.addEventListener("click", (event) => { - event.preventDefault(); - event.stopPropagation(); - removeAttachment(attachment.id); - }); - - const iconLabel = createElement("div", "monaco-icon-label"); - const iconLabelContainer = createElement("div", "monaco-icon-label-container"); - const iconNameContainer = createElement("span", "monaco-icon-name-container"); - iconLabelContainer.appendChild(iconNameContainer); - iconLabel.appendChild(iconLabelContainer); - - const pill = createElement("div", "chat-attached-context-pill"); - const image = createElement("img", "chat-attached-context-pill-image"); - image.src = attachment.dataUrl; - image.alt = ATTACHMENT_LABEL; - pill.appendChild(image); - - const text = createElement("span", "chat-attached-context-custom-text"); - text.textContent = ATTACHMENT_LABEL; - - wrapper.appendChild(removeButton); - wrapper.appendChild(iconLabel); - wrapper.appendChild(pill); - wrapper.appendChild(text); - - const show = () => showPreview(wrapper, attachment); - wrapper.addEventListener("mouseenter", show); - wrapper.addEventListener("focus", show); - wrapper.addEventListener("mouseleave", hidePreview); - wrapper.addEventListener("blur", hidePreview); - wrapper.addEventListener("dragstart", (event) => { - event.preventDefault(); - }); - wrapper.addEventListener("keydown", (event) => { - if (event.key === "Delete" || event.key === "Backspace") { - event.preventDefault(); - removeAttachment(attachment.id); - } - }); - - return wrapper; - } - - function render() { - toolsLine.innerHTML = ""; - toolsLine.classList.toggle("has-attachment", attachments.length > 0); - if (attachments.length === 0) { - hidePreview(); - return; - } - for (const attachment of attachments) { - toolsLine.appendChild(createAttachmentNode(attachment)); - } - if (previewAnchor && !toolsLine.contains(previewAnchor)) { - hidePreview(); - } - } - - function addAttachmentData(data) { - if (!data?.dataUrl) { - return false; - } - - nextAttachmentId += 1; - attachments.push({ - id: nextAttachmentId, - name: data.name || ATTACHMENT_LABEL, - mimeType: data.mimeType || "image/png", - dataUrl: data.dataUrl, - label: ATTACHMENT_LABEL, - }); - render(); - emitChange(); - return true; - } - - async function addAttachmentFromFile(file) { - if (!isImageFile(file)) { - return false; - } - - const dataUrl = await readFileAsDataUrl(file); - return addAttachmentData({ - name: file.name || ATTACHMENT_LABEL, - mimeType: file.type || "image/png", - dataUrl, - label: ATTACHMENT_LABEL, - }); - } - - async function handlePaste(event) { - const file = pickImageFileFromClipboard(event); - if (!file) { - return; - } - - event.preventDefault(); - try { - await addAttachmentFromFile(file); - } catch (error) { - console.error("Failed to attach pasted image.", error); - } - } - - promptInput.addEventListener("paste", handlePaste); - - window.addEventListener("resize", () => { - if (previewPopup?.classList.contains("show") && previewAnchor) { - updatePreviewPosition(previewAnchor); - } - }); - - window.addEventListener( - "scroll", - () => { - if (previewPopup?.classList.contains("show") && previewAnchor) { - updatePreviewPosition(previewAnchor); - } - }, - true - ); - - return { - clear, - hasAttachments() { - return attachments.length > 0; - }, - getImageUrls() { - return attachments.map((attachment) => attachment.dataUrl); - }, - }; - } - - window.createPromptAttachmentManager = createPromptAttachmentManager; -})(); diff --git a/packages/vscode-ide-companion/resources/webview.css b/packages/vscode-ide-companion/resources/webview.css deleted file mode 100644 index 98ffa62e..00000000 --- a/packages/vscode-ide-companion/resources/webview.css +++ /dev/null @@ -1,1605 +0,0 @@ -/* CSS Variables */ -:root { - --bg: var(--vscode-editor-background); - --panel: var(--vscode-sideBar-background); - --panel-2: var(--vscode-editor-inactiveSelectionBackground); - --muted: var(--vscode-descriptionForeground); - --accent: var(--vscode-focusBorder); - --accent-2: var(--vscode-button-background); - --danger: var(--vscode-errorForeground); - --shadow: rgba(0, 0, 0, 0.15); - --border-color: var(--vscode-panel-border); - --prompt-line-height: 18px; - --prompt-min-height: calc(var(--prompt-line-height) * 3 + 20px); - --prompt-max-height: calc(var(--prompt-line-height) * 10 + 20px); -} - -/* Global Styles */ -* { - box-sizing: border-box; -} - -body { - margin: 0; - padding: 0; - height: 100vh; - overflow-x: hidden; - background: var(--bg); - color: var(--vscode-foreground); - font-family: var(--vscode-font-family); - font-size: var(--vscode-font-size); -} - -/* App Container */ -.app { - height: 100vh; - display: flex; - flex-direction: column; - position: relative; - overflow-x: hidden; -} - -/* Header Container */ -.header-container { - display: flex; - align-items: center; - justify-content: space-between; - gap: 8px; - padding: 4px 16px; - background: var(--vscode-sideBar-background); - border-bottom: 1px solid var(--border-color); - flex-shrink: 0; - position: relative; -} - -.header-left { - position: relative; - min-width: 0; -} - -/* Session Selector */ -.session-selector { - display: flex; - align-items: center; - gap: 8px; - padding: 6px 10px; - background: transparent; - border: none; - border-radius: 4px; - cursor: pointer; - transition: background 0.2s; - width: 100%; -} - -.session-selector:hover { - background: var(--vscode-toolbar-hoverBackground); -} - -.session-selector.open .session-selector-icon { - transform: rotate(180deg); -} - -.session-selector-title { - display: flex; - align-items: center; - gap: 8px; - font-size: 13px; - color: var(--vscode-foreground); - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - text-align: left; -} - -.session-logo { - width: 16px; - height: 16px; - flex-shrink: 0; -} - -.session-title-text { - min-width: 0; - overflow: hidden; - text-overflow: ellipsis; -} - -.session-selector-icon { - width: 16px; - height: 16px; - fill: var(--vscode-foreground); - transition: transform 0.2s; - flex-shrink: 0; -} - -/* Header New Button */ -.header-new-btn { - border: none; - border-radius: 4px; - cursor: pointer; - font-size: 12px; - transition: background 0.2s; - background: none; - display: flex; - align-items: center; - justify-content: center; - padding: 6px; - flex-shrink: 0; -} - -.header-new-btn:hover { - background: var(--vscode-toolbar-hoverBackground); -} - -.header-new-icon { - width: 16px; - height: 16px; - fill: var(--vscode-foreground); -} - -/* Session Dropdown */ -.session-dropdown { - position: absolute; - top: calc(100% + 8px); - left: 16px; - right: 16px; - background: var(--vscode-dropdown-background); - border: 1px solid var(--border-color); - border-radius: 4px; - max-height: 400px; - z-index: 10000; - display: none; - box-shadow: 0 4px 12px var(--shadow); - flex-direction: column; -} - -.session-dropdown.show { - display: flex; -} - -.session-search-box { - padding: 8px; - flex-shrink: 0; -} - -.session-search-input { - width: 100%; - padding: 6px 10px; - background: var(--vscode-input-background); - color: var(--vscode-input-foreground); - border: 1px solid var(--vscode-input-border); - border-radius: 4px; - font-size: 13px; - outline: none; - font-family: var(--vscode-font-family); - outline: none; -} - -.session-search-input:focus { - border-color: var(--vscode-focusBorder); - outline: none; -} - -.session-search-input::placeholder { - color: var(--vscode-input-placeholderForeground); -} - -.session-dropdown-list { - flex: 1; - overflow-y: auto; - min-height: 0; - padding: 8px 12px 12px; -} - -.session-dropdown-group { - margin-bottom: 12px; -} - -.session-dropdown-group:last-child { - margin-bottom: 0; -} - -.session-dropdown-group-title { - font-size: 11px; - font-weight: 500; - color: var(--vscode-descriptionForeground); - letter-spacing: 0.5px; - padding: 6px 6px 8px; - margin-bottom: 2px; -} - -.session-dropdown-empty { - padding: 20px; - text-align: center; - color: var(--vscode-descriptionForeground); - font-size: 13px; -} - -.session-dropdown-item { - padding: 6px; - cursor: pointer; - transition: background 0.2s; - display: flex; - gap: 12px; - margin-bottom: 6px; - border-radius: 4px; - align-items: center; -} - -.session-dropdown-item:last-child { - margin-bottom: 0; -} - -.session-dropdown-item:hover { - background: var(--vscode-list-hoverBackground); -} - -.session-dropdown-item.active { - background: var(--vscode-list-activeSelectionBackground); -} - -.session-dropdown-item.active .session-dropdown-summary { - color: var(--vscode-list-activeSelectionForeground); -} - -.session-dropdown-item.active .session-dropdown-time { - color: var(--vscode-list-activeSelectionForeground); - opacity: 0.8; -} - -.session-dropdown-summary { - font-size: 13px; - color: var(--vscode-foreground); - margin-bottom: 4px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - flex: 1; - font-weight: 500; -} - -.session-dropdown-time { - font-size: 11px; - color: var(--vscode-descriptionForeground); -} - -.session-dropdown-summary mark { - background-color: var(--vscode-editor-findMatchHighlightBackground); - color: var(--vscode-editor-foreground); - padding: 0 2px; - border-radius: 2px; -} - -/* Chat Container */ -.chat-container { - display: flex; - flex-direction: column; - flex: 1; - overflow: hidden; - overflow-x: hidden; -} - -.chat-container.hidden { - display: none; -} - -/* Messages */ -.messages { - flex: 1; - overflow-y: auto; - overflow-x: hidden; - padding: 16px; - display: flex; - flex-direction: column; - gap: 1px; - background: var(--vscode-sideBar-background); -} - -/* Message Bubbles */ -.bubble { - padding: 16px; - font-size: 13px; - width: 100%; - border: 1px solid transparent; - color: var(--vscode-foreground); - border-radius: 6px; - position: relative; - overflow-wrap: break-word; - word-break: break-word; -} - -/* Collapsible Bubble */ -.bubble-collapsible-header { - display: flex; - align-items: flex-start; - gap: 8px; - cursor: pointer; - user-select: none; - padding: 4px 0; - position: relative; -} - -.bubble-collapsible-header:hover .bubble-title-text { - opacity: 0.8; -} - -.bubble-dot { - width: 8px; - height: 8px; - border-radius: 50%; - background-color: var(--vscode-descriptionForeground); - flex-shrink: 0; - margin-top: 6px; - position: relative; - z-index: 3; -} - -.bubble-dot.success { - background-color: var(--vscode-terminal-ansiGreen); -} - -.bubble-dot.error { - background-color: var(--vscode-terminal-ansiRed); -} - -/* 连接线:只在有 connect-to-prev class 时显示向上的连接线 */ -.bubble-dot.connect-to-prev::before { - content: ""; - position: absolute; - left: 3.5px; - bottom: 8px; - width: 1px; - height: var(--line-height, 0px); - background-color: var(--vscode-panel-border); - z-index: 0; -} - -.bubble-title { - flex: 1; - font-size: 13px; - color: var(--vscode-foreground); - display: flex; - align-items: center; - gap: 6px; - flex-wrap: nowrap; - min-width: 0; - overflow: visible; -} - -.bubble-title-text { - display: inline-flex; - align-items: center; - gap: 6px; - flex: 1; - min-width: 0; - overflow: visible; -} - -.bubble-title-text b { - text-transform: capitalize; - flex-shrink: 0; -} - -.bubble-title .tool-params { - color: var(--vscode-descriptionForeground); - font-weight: normal; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - flex: 1; - min-width: 0; - position: relative; - display: inline-block; -} - -/* Tooltip styles */ -.tooltip { - position: fixed; - padding: 4px 8px; - background: var(--vscode-editorHoverWidget-background); - color: var(--vscode-editorHoverWidget-foreground); - border: 1px solid var(--vscode-editorHoverWidget-border); - border-radius: 4px; - font-size: 12px; - white-space: normal; - word-break: break-word; - max-width: 400px; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); - z-index: 10000; - pointer-events: none; - opacity: 0; - visibility: hidden; - transition: - opacity 0.5s, - visibility 0.5s; -} - -.tooltip.show { - opacity: 1; - visibility: visible; -} - -.bubble-toggle { - display: inline-flex; - align-items: center; - justify-content: center; - width: 16px; - height: 16px; - flex-shrink: 0; - color: var(--vscode-descriptionForeground); - font-size: 12px; -} - -.bubble-toggle svg { - width: 12px; - height: 12px; - fill: var(--vscode-descriptionForeground); - transition: transform 0.2s; -} - -.bubble-toggle.expanded svg { - transform: rotate(180deg); -} - -.bubble-collapsible-content { - margin-top: 8px; - margin-left: 24px; - padding: 8px 12px; - background: var(--vscode-textCodeBlock-background); - border: 1px solid var(--border-color); - border-radius: 4px; - overflow: auto; - max-width: calc(100% - 24px); - font-family: var(--vscode-editor-font-family); - font-size: 12px; - white-space: pre-wrap; - word-break: break-word; - max-height: 300px; -} - -.tool-result-details { - display: flex; - flex-direction: column; - gap: 10px; - font-family: var(--vscode-font-family); - white-space: normal; -} - -.tool-result-summary { - color: var(--vscode-foreground); - line-height: 1.5; -} - -.update-plan-result { - border: 1px solid var(--border-color); - border-radius: 6px; - background: var(--vscode-editor-background); - color: var(--vscode-editor-foreground); - font-family: var(--vscode-font-family); - font-size: 13px; - line-height: 1.45; - padding: 10px; - white-space: normal; -} - -.update-plan-heading { - color: var(--vscode-foreground); - font-size: 13px; - font-weight: 650; - line-height: 1.35; - margin: 0 0 8px; -} - -.update-plan-heading:not(:first-child) { - margin-top: 12px; -} - -.update-plan-spacer { - height: 6px; -} - -.update-plan-paragraph { - margin: 4px 0; -} - -.update-plan-task, -.update-plan-bullet { - display: grid; - grid-template-columns: 18px 1fr; - gap: 8px; - align-items: flex-start; - margin: 5px 0; - padding-left: calc(var(--plan-indent, 0) * 18px); -} - -.update-plan-status { - width: 14px; - height: 14px; - margin-top: 2px; - border: 1px solid var(--vscode-descriptionForeground); - border-radius: 50%; - color: var(--vscode-editor-background); - display: inline-flex; - align-items: center; - justify-content: center; - font-size: 10px; - font-weight: 700; - line-height: 1; -} - -.update-plan-task.status-done .update-plan-status { - background: var(--vscode-testing-iconPassed, #2ea043); - border-color: var(--vscode-testing-iconPassed, #2ea043); -} - -.update-plan-task.status-active .update-plan-status { - background: var(--vscode-charts-blue, #3794ff); - border-color: var(--vscode-charts-blue, #3794ff); -} - -.update-plan-task.status-attention .update-plan-status { - background: var(--vscode-testing-iconFailed, #f85149); - border-color: var(--vscode-testing-iconFailed, #f85149); -} - -.update-plan-task.status-todo .update-plan-status { - background: transparent; -} - -.update-plan-task.status-done .update-plan-task-text { - color: var(--vscode-descriptionForeground); - text-decoration: line-through; -} - -.update-plan-bullet-marker { - color: var(--vscode-descriptionForeground); - line-height: 1.45; - text-align: center; -} - -.update-plan-markdown code { - border-radius: 3px; - background: var(--vscode-textCodeBlock-background); - font-family: var(--vscode-editor-font-family); - font-size: 0.92em; - padding: 1px 4px; -} - -.tool-result-file-row { - display: flex; - align-items: center; - gap: 8px; - flex-wrap: wrap; -} - -.tool-result-label { - color: var(--vscode-descriptionForeground); - font-size: 11px; - font-weight: 600; - letter-spacing: 0.04em; - text-transform: uppercase; -} - -.tool-result-filepath { - border: none; - background: none; - color: var(--vscode-textLink-foreground, var(--vscode-button-background)); - cursor: pointer; - font: inherit; - padding: 0; - text-decoration: underline; - text-underline-offset: 2px; - word-break: break-all; -} - -.tool-result-filepath:hover { - color: var(--vscode-textLink-activeForeground, var(--vscode-button-hoverBackground)); -} - -.tool-result-diff { - display: flex; - flex-direction: column; - gap: 6px; -} - -.diff-preview { - border: 1px solid var(--border-color); - border-radius: 6px; - overflow: hidden; - background: var(--vscode-editor-background); -} - -.diff-line { - display: grid; - grid-template-columns: 20px 1fr; - gap: 0; - font-family: var(--vscode-editor-font-family); - font-size: 12px; - line-height: 1.2; -} - -.diff-line-marker { - display: flex; - align-items: flex-start; - justify-content: center; - padding: 1px 0; - color: var(--vscode-descriptionForeground); - user-select: none; -} - -.diff-line-content { - display: block; - padding: 1px 10px 1px 0; - white-space: pre-wrap; - word-break: break-word; -} - -.diff-line.added { - background: color-mix( - in srgb, - var(--vscode-diffEditor-insertedLineBackground, rgba(46, 160, 67, 0.18)) 100%, - transparent - ); -} - -.diff-line.removed { - background: color-mix( - in srgb, - var(--vscode-diffEditor-removedLineBackground, rgba(248, 81, 73, 0.16)) 100%, - transparent - ); -} - -.diff-line.context { - background: var(--vscode-editor-background); -} - -/* assistant 角色的展开内容无边框 */ -.bubble.assistant .bubble-collapsible-content { - border: none; - background: transparent; - padding: 8px 0; -} - -.bubble-collapsible-content.collapsed { - display: none; -} - -/* 普通assistant气泡布局 */ -.bubble.assistant:has(.bubble-normal-content) { - display: flex; - align-items: flex-start; - gap: 8px; -} - -.bubble.assistant:has(.bubble-normal-content) > .bubble-dot { - margin-top: 6px; -} - -.bubble-normal-content { - flex: 1; - min-width: 0; -} - -/* 复制按钮 */ -.bubble-copy-btn { - display: none; - position: absolute; - top: 8px; - right: 8px; - width: 26px; - height: 26px; - border: 1px solid var(--border-color); - border-radius: 4px; - background: var(--vscode-editor-background); - color: var(--vscode-descriptionForeground); - cursor: pointer; - align-items: center; - justify-content: center; - transition: - opacity 0.15s, - background 0.15s; - z-index: 5; -} - -.bubble-copy-btn:hover { - background: var(--vscode-toolbar-hoverBackground); - color: var(--vscode-foreground); -} - -.bubble-copy-btn.copied { - color: var(--vscode-testing-iconPassed, #2ea043); - border-color: var(--vscode-testing-iconPassed, #2ea043); -} - -.bubble-copy-btn svg { - width: 14px; - height: 14px; - fill: currentColor; - pointer-events: none; -} - -.bubble.assistant:hover .bubble-copy-btn { - display: flex; -} - -.bubble.user { - background: var(--vscode-editor-background); - border-color: var(--vscode-panel-border); - padding: 4px 6px; - margin: 12px 0 12px auto; - white-space: pre-wrap; - word-break: break-word; - width: fit-content; - max-width: 80%; -} - -.bubble.system { - background: transparent; - border-color: transparent; - padding: 4px 16px; -} - -.bubble.assistant { - background: transparent; - border-color: transparent; - padding: 4px 16px; -} - -.bubble.tool { - background: transparent; - border-color: transparent; - padding: 4px 16px; -} - -.bubble p { - margin: 8px 0; - overflow-wrap: break-word; - word-break: break-word; -} - -.bubble p:first-of-type { - margin-top: 0; -} - -.bubble p:last-of-type { - margin-bottom: 0; -} - -.bubble pre { - padding: 12px; - border-radius: 4px; - overflow-x: auto; - max-width: 100%; - color: var(--vscode-editor-foreground); - background: var(--vscode-textCodeBlock-background); - margin: 8px 0; - border: 1px solid var(--vscode-panel-border); - white-space: pre-wrap; - word-break: break-word; -} - -.bubble code { - font-family: var(--vscode-editor-font-family); - font-size: 12px; - color: var(--vscode-editor-foreground); - background-color: unset; - overflow-wrap: break-word; - word-break: break-word; -} - -.ask-user-question { - display: flex; - flex-direction: column; - gap: 12px; - font-family: var(--vscode-font-family); - font-size: 13px; - white-space: normal; -} - -.ask-user-question-intro { - color: var(--vscode-descriptionForeground); -} - -.ask-user-question-form { - display: flex; - flex-direction: column; - gap: 12px; -} - -.ask-user-question-content { - overflow: visible; - max-height: none; -} - -.ask-user-question-block { - border: 1px solid var(--border-color); - border-radius: 6px; - padding: 12px; - margin: 0; - display: flex; - flex-direction: column; - gap: 8px; -} - -.ask-user-question-title { - padding: 0 4px; - font-weight: 600; -} - -.ask-user-question-option { - display: flex; - align-items: flex-start; - gap: 8px; - cursor: pointer; -} - -.ask-user-question-option input { - margin: 2px 0 0; -} - -.ask-user-question-option-text { - display: flex; - flex-direction: column; - gap: 2px; -} - -.ask-user-question-option-description { - color: var(--vscode-descriptionForeground); - font-size: 12px; -} - -.ask-user-question-other { - display: flex; - flex-direction: column; - gap: 6px; -} - -.ask-user-question-other-label { - font-size: 12px; - color: var(--vscode-descriptionForeground); -} - -.ask-user-question-other textarea { - min-height: 56px; - max-height: 120px; - resize: none; - padding: 8px 10px; - border: 1px solid var(--border-color); - border-radius: 4px; - background: var(--vscode-input-background); - color: var(--vscode-input-foreground); -} - -.ask-user-question-actions { - margin-top: 10px; -} - -.ask-user-question-error { - color: var(--vscode-errorForeground); - font-size: 12px; - display: none; - margin-bottom: 6px; -} - -.ask-user-question-error:not(:empty) { - display: block; -} - -.ask-user-question-submit { - align-self: flex-start; - border: 1px solid transparent; - border-radius: 4px; - background: var(--vscode-button-background); - color: var(--vscode-button-foreground); - padding: 6px 12px; - cursor: pointer; - font-size: 12px; -} - -.ask-user-question-submit:disabled { - opacity: 0.6; - cursor: not-allowed; -} - -.ask-user-question-empty { - color: var(--vscode-descriptionForeground); -} - -.permission-prompt-host { - margin-bottom: 10px; -} - -.permission-card { - border: 1px solid var(--vscode-panel-border); - border-left: 3px solid var(--vscode-notificationsWarningIcon-foreground, #f59e0b); - border-radius: 6px; - background: var(--vscode-input-background); - box-shadow: 0 4px 14px var(--shadow); - padding: 12px; -} - -.permission-header { - display: flex; - align-items: flex-start; - justify-content: space-between; - gap: 12px; -} - -.permission-title { - color: var(--vscode-notificationsWarningIcon-foreground, #f59e0b); - font-weight: 700; -} - -.permission-progress { - margin-top: 2px; - color: var(--vscode-descriptionForeground); - font-size: 11px; -} - -.permission-close { - border: none; - border-radius: 4px; - background: transparent; - color: var(--vscode-descriptionForeground); - cursor: pointer; - font-size: 18px; - line-height: 1; - padding: 0 4px; -} - -.permission-close:hover { - background: var(--vscode-toolbar-hoverBackground); - color: var(--vscode-foreground); -} - -.permission-tool { - margin-top: 10px; - font-weight: 700; -} - -.permission-command { - margin-top: 6px; - border-radius: 4px; - background: var(--vscode-textCodeBlock-background); - color: var(--vscode-editor-foreground); - font-family: var(--vscode-editor-font-family); - font-size: 12px; - line-height: 1.45; - padding: 8px; - white-space: pre-wrap; - word-break: break-word; -} - -.permission-description { - margin-top: 8px; - color: var(--vscode-descriptionForeground); - line-height: 1.45; -} - -.permission-scope { - display: inline-flex; - align-items: center; - margin-top: 10px; - border-radius: 999px; - font-size: 11px; - font-weight: 700; - padding: 3px 8px; -} - -.permission-scope.risk-low { - background: rgba(34, 197, 94, 0.14); - color: #22c55e; -} - -.permission-scope.risk-medium { - background: rgba(245, 158, 11, 0.14); - color: #f59e0b; -} - -.permission-scope.risk-high { - background: rgba(239, 68, 68, 0.14); - color: #ef4444; -} - -.permission-question { - margin-top: 10px; - font-weight: 600; -} - -.permission-actions { - display: flex; - flex-wrap: wrap; - gap: 8px; - margin-top: 10px; -} - -.permission-action { - border: 1px solid var(--vscode-button-border, transparent); - border-radius: 4px; - background: var(--vscode-button-secondaryBackground); - color: var(--vscode-button-secondaryForeground); - cursor: pointer; - font-size: 12px; - padding: 6px 10px; -} - -.permission-action:hover { - background: var(--vscode-button-secondaryHoverBackground); -} - -.permission-allow, -.permission-always { - background: var(--vscode-button-background); - color: var(--vscode-button-foreground); -} - -.permission-allow:hover, -.permission-always:hover { - background: var(--vscode-button-hoverBackground); -} - -.permission-deny { - border-color: var(--vscode-inputValidation-errorBorder, #ef4444); - color: var(--vscode-errorForeground, #ef4444); -} - -.permission-denied-card { - border-left-color: var(--vscode-errorForeground, #ef4444); -} - -.permission-denied-card .permission-title { - color: var(--vscode-errorForeground, #ef4444); -} - -/* Spinner dot for live thinking bubble */ -.bubble-dot.spinner-dot { - background: transparent !important; -} - -/* 旋转环用 ::after 实现,不影响 ::before 连线 */ -.bubble-dot.spinner-dot::after { - content: ""; - position: absolute; - top: -2px; - left: -2px; - width: calc(100% + 4px); - height: calc(100% + 4px); - border-radius: 50%; - border: 2px solid var(--vscode-progressBar-background); - border-top-color: var(--accent); - animation: spin 0.8s linear infinite; - box-sizing: border-box; - pointer-events: none; - z-index: 1; -} - -/* Thinking bubble: 标题和内容同行显示 */ -.bubble[data-thinking-live="true"] .thinking-status { - color: var(--vscode-descriptionForeground); - font-weight: normal; - font-size: 12px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - flex: 1; - min-width: 0; -} - -@keyframes spin { - to { - transform: rotate(360deg); - } -} - -/* Composer */ -.composer { - position: relative; - padding: 12px 16px 16px; - background: var(--vscode-sideBar-background); - flex-shrink: 0; -} - -.input-wrap { - position: relative; - display: flex; - flex-direction: column; - min-height: calc(var(--prompt-min-height) + 42px); - border-radius: 4px; - border: 1px solid var(--border-color); - background: var(--vscode-input-background); - transition: - border-color 0.15s ease, - outline-color 0.15s ease, - background-color 0.15s ease; -} - -.input-wrap:focus-within { - border-color: var(--vscode-focusBorder); - outline: 1px solid var(--vscode-focusBorder); -} - -.tools-line { - display: none; - align-items: center; - flex-wrap: wrap; - gap: 8px; - min-height: 0; - padding: 0 12px; -} - -.tools-line.has-attachment { - display: flex; - min-height: 34px; - padding: 10px 12px 0; -} - -.composer-footer { - display: flex; - height: 42px; - width: 100%; - align-items: center; - justify-content: space-between; - gap: 8px; - padding: 6px 12px; - position: relative; -} - -/* Textarea */ -textarea { - width: 100%; - min-height: var(--prompt-min-height); - max-height: var(--prompt-max-height); - resize: none; - overflow-y: hidden; - border: none; - border-radius: 4px; - background: var(--vscode-input-background); - color: var(--vscode-input-foreground); - padding: 10px 12px; - font-size: 13px; - line-height: var(--prompt-line-height); - outline: none; - font-family: var(--vscode-font-family); -} - -textarea:focus { - outline: none; -} - -textarea::placeholder { - color: var(--vscode-input-placeholderForeground); -} - -.chat-attached-context-attachment { - display: inline-flex; - align-items: center; - gap: 6px; - min-width: 0; - max-width: 100%; - padding: 4px; - border: 1px solid var(--vscode-editorWidget-background, var(--vscode-input-background)); - border-radius: 6px; - color: var(--vscode-foreground); -} - -.chat-attached-context-attachment:hover { - border-color: var(--vscode-focusBorder); -} - -.chat-attached-context-attachment .monaco-button.codicon-close { - display: inline-flex; - justify-content: center; - width: 18px; - height: 18px; - border-radius: 50%; - color: var(--vscode-descriptionForeground); - text-decoration: none; - flex-shrink: 0; -} - -.chat-attached-context-attachment .monaco-button.codicon-close:hover { - background: var(--vscode-toolbar-hoverBackground); - color: var(--vscode-foreground); -} - -.monaco-icon-label, -.monaco-icon-label-container, -.monaco-icon-name-container { - display: none; -} - -.chat-attached-context-pill { - width: 13px; - height: 13px; - border-radius: 4px; - overflow: hidden; - flex-shrink: 0; - background: var(--vscode-editor-background); -} - -.chat-attached-context-pill-image { - display: block; - width: 13px; - height: 13px; - margin: 1.5px; - object-fit: cover; - border-radius: 2px; -} - -.chat-attached-context-custom-text { - font-size: 12px; - line-height: 1.2; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.chat-attached-context-preview { - position: fixed; - display: none; - padding: 10px; - border: 1px solid var(--border-color); - border-radius: 12px; - background: var(--vscode-editorHoverWidget-background, var(--vscode-editorWidget-background)); - box-shadow: 0 8px 24px var(--shadow); - z-index: 10001; - pointer-events: none; -} - -.chat-attached-context-preview.show { - display: block; -} - -.chat-attached-context-preview-image { - display: block; - max-width: min(520px, 70vw); - max-height: min(420px, 65vh); - border-radius: 6px; - object-fit: contain; -} - -/* Send Button */ -.send-button { - width: 30px; - height: 30px; - border-radius: 50%; - border: none; - cursor: pointer; - display: grid; - place-items: center; - background: transparent; -} - -.context-meter { - position: relative; - width: 18px; - height: 18px; - display: grid; - place-items: center; - flex-shrink: 0; - z-index: 3; -} - -.context-meter-ring { - --context-percent: 0%; - width: 14px; - height: 14px; - border-radius: 50%; - background: - radial-gradient(circle at center, var(--vscode-input-background) 36%, transparent 38%), - conic-gradient( - var(--vscode-descriptionForeground) 0 var(--context-percent), - var(--vscode-editorWidget-border, var(--vscode-panel-border)) var(--context-percent) 100% - ); -} - -.context-meter:hover .context-meter-ring { - filter: brightness(1.1); -} - -.context-meter-tooltip { - position: fixed; - left: 16px; - bottom: calc(100% + 10px); - display: none; - width: min(360px, calc(100vw - 32px)); - max-height: min(420px, 70vh); - overflow: auto; - padding: 12px 14px; - border: 1px solid var(--vscode-editorHoverWidget-border, var(--border-color)); - border-radius: 12px; - background: var(--vscode-editorHoverWidget-background, var(--vscode-editorWidget-background)); - color: var(--vscode-editorHoverWidget-foreground, var(--vscode-foreground)); - box-shadow: 0 8px 24px var(--shadow); - font-size: 12px; - line-height: 1.4; - pointer-events: none; - z-index: 10002; -} - -.context-meter:hover .context-meter-tooltip { - display: block; -} - -.context-tooltip-title { - text-align: center; - color: var(--vscode-descriptionForeground); - font-size: 13px; - margin-bottom: 4px; -} - -.context-tooltip-summary { - text-align: center; - font-size: 16px; - font-weight: 600; - margin-bottom: 10px; -} -.context-tooltip-section { - margin-top: 10px; - padding-top: 8px; - border-top: 1px solid var(--border-color); - color: var(--vscode-descriptionForeground); - font-weight: 600; -} - -.context-tooltip-row { - display: flex; - justify-content: space-between; - gap: 12px; - margin-top: 4px; -} - -.context-tooltip-label { - min-width: 0; - color: var(--vscode-descriptionForeground); - overflow-wrap: anywhere; -} - -.context-tooltip-value { - max-width: 55%; - text-align: right; - font-family: var(--vscode-editor-font-family); - overflow-wrap: anywhere; -} - -.send-button:disabled { - opacity: 0.5; - cursor: not-allowed; -} - -.send-icon { - width: 26px; - height: 26px; - fill: currentColor; - color: var(--vscode-foreground); - transition: opacity 0.2s; -} - -#sendIcon { - color: var(--vscode-descriptionForeground); -} - -#stopIcon { - display: none; - color: var(--vscode-foreground); -} - -.send-icon.empty { - opacity: 0.6; -} - -/* Skills Button */ -.skills-button { - height: 22px; - border-radius: 4px; - border: none; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - gap: 4px; - background: transparent; - padding: 0; - transition: opacity 0.2s; - flex-shrink: 0; - color: var(--vscode-foreground); -} - -.skills-button span { - margin-top: 4px; -} - -.skills-button:hover { - opacity: 0.8; -} - -.skills-button svg { - width: 16px; - height: 16px; - fill: var(--vscode-foreground); -} - -/* Skills Popup */ -.skills-popup { - position: absolute; - bottom: calc(100% + 8px); - left: 16px; - right: 16px; - background: var(--vscode-dropdown-background); - border: 1px solid var(--border-color); - border-radius: 4px; - max-height: 300px; - overflow-y: auto; - z-index: 10000; - display: none; - box-shadow: 0 4px 12px var(--shadow); -} - -.skills-popup.show { - display: block; -} - -.skills-popup-header { - padding: 8px 12px; - font-size: 12px; - font-weight: 500; - color: var(--vscode-descriptionForeground); - border-bottom: 1px solid var(--border-color); -} - -.skills-popup-list { - padding: 8px; - display: flex; - flex-direction: column; - gap: 4px; -} - -.skills-popup-empty { - padding: 12px; - text-align: center; - color: var(--vscode-descriptionForeground); - font-size: 13px; -} - -.skills-popup-item { - display: flex; - align-items: center; - padding: 6px 10px; - cursor: pointer; - border-radius: 4px; - font-size: 13px; - transition: background 0.2s; - gap: 8px; -} - -.skills-popup-item:hover { - background: var(--vscode-list-hoverBackground); -} - -.skills-popup-item.selected { - background: var(--vscode-list-activeSelectionBackground); - color: var(--vscode-list-activeSelectionForeground); -} - -.skills-popup-item-name { - flex: 0 0 120px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.skills-popup-item-path { - flex: 1; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - color: var(--vscode-descriptionForeground); - font-size: 12px; -} - -.skills-popup-item:hover .skills-popup-item-path, -.skills-popup-item.selected .skills-popup-item-path { - color: inherit; -} - -.skills-popup-item-loaded { - color: var(--vscode-testing-icon-success); - font-weight: bold; - font-size: 14px; - margin-left: 4px; -} - -/* Skills Bar (contains button and tags) */ -.skills-bar { - display: flex; - align-items: center; - gap: 8px; - width: calc(100% - 60px); -} - -/* Skills Tags */ -.skills-tags { - display: flex; - flex-wrap: wrap; - align-items: center; - gap: 6px; - flex: 1; - min-width: 0; -} - -.skills-tags-inner { - width: 100%; - overflow: auto; - white-space: nowrap; - scrollbar-width: none; - -ms-overflow-style: none; -} - -.skills-tags-inner::-webkit-scrollbar { - width: 0; - height: 0; -} - -.skill-tag { - display: inline-flex; - align-items: center; - gap: 4px; - padding: 2px 6px; - background: var(--vscode-button-background); - color: var(--vscode-button-foreground); - border-radius: 4px; - font-size: 12px; - margin-right: 4px; -} - -.skill-tag-name { - max-width: 120px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.skill-tag-remove { - cursor: pointer; - font-size: 14px; - line-height: 1; - opacity: 0.7; - transition: opacity 0.2s; -} - -.skill-tag-remove:hover { - opacity: 1; -} - -/* Prevent horizontal overflow for all markdown content */ -.bubble table { - display: block; - overflow-x: auto; - max-width: 100%; -} - -.bubble img { - max-width: 100%; - height: auto; -} - -.bubble ul, -.bubble ol { - padding-left: 1.5em; - overflow-wrap: break-word; -} - -.bubble li { - overflow-wrap: break-word; - word-break: break-word; -} - -.bubble blockquote { - overflow-wrap: break-word; - word-break: break-word; -} - -.bubble a { - overflow-wrap: break-word; - word-break: break-all; -} diff --git a/packages/vscode-ide-companion/resources/webview.html b/packages/vscode-ide-companion/resources/webview.html deleted file mode 100644 index 1290f8d6..00000000 --- a/packages/vscode-ide-companion/resources/webview.html +++ /dev/null @@ -1,2354 +0,0 @@ - - - - - - - Deep Code - - - -

- - - - - diff --git a/packages/vscode-ide-companion/scripts/copy-templates.js b/packages/vscode-ide-companion/scripts/copy-templates.js new file mode 100644 index 00000000..e87bb1ba --- /dev/null +++ b/packages/vscode-ide-companion/scripts/copy-templates.js @@ -0,0 +1,28 @@ +import { cpSync, existsSync, mkdirSync, rmSync } from "node:fs"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const root = join(__dirname, ".."); +const packagesRoot = join(root, ".."); +const coreTemplates = join(packagesRoot, "core", "templates"); +const destDir = join(root, "templates"); + +if (!existsSync(coreTemplates)) { + console.error(`Templates directory not found at ${coreTemplates}`); + process.exit(1); +} + +// Remove old templates if exists +if (existsSync(destDir)) { + rmSync(destDir, { recursive: true, force: true }); +} + +// Copy templates to dist/templates +mkdirSync(destDir, { recursive: true }); +cpSync(coreTemplates, destDir, { + recursive: true, + dereference: true, +}); + +console.log(`✅ Copied core/templates/ → templates/`); diff --git a/packages/vscode-ide-companion/src/extension.test.ts b/packages/vscode-ide-companion/src/extension.test.ts new file mode 100644 index 00000000..5e76b0b6 --- /dev/null +++ b/packages/vscode-ide-companion/src/extension.test.ts @@ -0,0 +1,144 @@ +/** + * Unit tests for extension.ts + * + * NOTE: This file is excluded from vitest because vscode module is only + * available as types at compile time. For VS Code extension testing, + * use VS Code's extension test runner instead. + * + * Tests in this file are for type checking only. + */ + +import { describe, it, expect, vi, beforeEach } from "vitest"; +import type * as vscode from "vscode"; + +// Mock vscode module +vi.mock("vscode", () => ({ + workspace: { + workspaceFolders: [{ uri: { fsPath: "/test/workspace" } }], + }, + window: { + activeTextEditor: undefined, + showErrorMessage: vi.fn(), + showTextDocument: vi.fn().mockResolvedValue({ lineCount: 10 }), + onDidChangeActiveTextEditor: vi.fn(() => ({ dispose: vi.fn() })), + }, + commands: { + registerCommand: vi.fn(() => ({ dispose: vi.fn() })), + executeCommand: vi.fn().mockResolvedValue(undefined), + }, + env: { + clipboard: { writeText: vi.fn().mockResolvedValue(undefined) }, + machineId: "test-machine-id", + }, + Uri: { + file: vi.fn((path: string) => ({ fsPath: path })), + }, + Position: vi.fn(), + Selection: vi.fn(), + Range: vi.fn(), + TextEditorRevealType: { + InCenter: 1, + }, + WebviewViewProvider: class {}, + ExtensionContext: class {}, +})); + +vi.mock("@vegamo/deepcode-core", () => ({ + SessionManager: vi.fn().mockImplementation(() => ({ + dispose: vi.fn(), + initMcpServers: vi.fn().mockResolvedValue(undefined), + })), + getCompactPromptTokenThreshold: vi.fn(() => 100000), + resolveSettingsSources: vi.fn(() => ({ + model: "deepseek-v4-pro", + baseURL: "https://api.deepseek.com", + thinkingEnabled: false, + reasoningEffort: "low" as const, + debugLogEnabled: false, + })), + setShellIfWindows: vi.fn(), + DEFAULT_MODEL: "deepseek-v4-pro", + DEFAULT_BASE_URL: "https://api.deepseek.com", +})); + +vi.mock("markdown-it", () => { + return vi.fn().mockImplementation(() => ({ + render: vi.fn((text: string) => `

${text}

`), + })); +}); + +vi.mock("@webview-rpc/host", () => ({ + attachRouterToPanel: vi.fn(), +})); + +vi.mock("./getWebviewContent.js", () => ({ + getWebviewContent: vi.fn().mockResolvedValue("test"), +})); + +vi.mock("node:fs", () => ({ + existsSync: vi.fn(() => false), + readFileSync: vi.fn(() => "{}"), + writeFileSync: vi.fn(), + mkdirSync: vi.fn(), +})); + +// Import after mocks +import { DeepCodeViewProvider, activate, deactivate } from "./extension"; + +describe("DeepCodeViewProvider", () => { + let mockContext: vscode.ExtensionContext; + + beforeEach(() => { + vi.clearAllMocks(); + mockContext = { + extensionPath: "/test/extension", + subscriptions: [], + } as unknown as vscode.ExtensionContext; + }); + + it("creates provider instance", () => { + const provider = new DeepCodeViewProvider(mockContext); + expect(provider).toBeDefined(); + provider.dispose(); + }); + + it("postMessageToWebview handles null webviewView", () => { + const provider = new DeepCodeViewProvider(mockContext); + expect(() => provider.postMessageToWebview({ type: "test" })).not.toThrow(); + provider.dispose(); + }); + + it("dispose does not throw", () => { + const provider = new DeepCodeViewProvider(mockContext); + expect(() => provider.dispose()).not.toThrow(); + }); +}); + +describe("activate", () => { + let mockContext: vscode.ExtensionContext; + + beforeEach(() => { + vi.clearAllMocks(); + mockContext = { + extensionPath: "/test/extension", + subscriptions: [], + } as unknown as vscode.ExtensionContext; + }); + + it("registers webview view provider", () => { + activate(mockContext); + const vscode = require("vscode"); + expect(vscode.commands.registerCommand).toHaveBeenCalled(); + }); + + it("creates subscriptions", () => { + activate(mockContext); + expect(mockContext.subscriptions.length).toBeGreaterThan(0); + }); +}); + +describe("deactivate", () => { + it("does nothing and does not throw", () => { + expect(() => deactivate()).not.toThrow(); + }); +}); diff --git a/packages/vscode-ide-companion/src/extension.ts b/packages/vscode-ide-companion/src/extension.ts index 44542e79..0a6b3a94 100644 --- a/packages/vscode-ide-companion/src/extension.ts +++ b/packages/vscode-ide-companion/src/extension.ts @@ -1,7 +1,7 @@ import * as vscode from "vscode"; -import * as fs from "fs"; -import * as path from "path"; -import * as os from "os"; +import * as fs from "node:fs"; +import * as path from "node:path"; +import * as os from "node:os"; import OpenAI from "openai"; import MarkdownIt from "markdown-it"; import type { SessionMessage } from "@vegamo/deepcode-core"; @@ -9,19 +9,16 @@ import { SessionManager, getCompactPromptTokenThreshold, type LlmStreamProgress, - type PermissionScope, type SessionEntry, - type SkillInfo, - type UserPromptContent, - type UserToolPermission, resolveSettingsSources, type DeepcodingSettings, type ReasoningEffort, type ResolvedDeepcodingSettings, setShellIfWindows, } from "@vegamo/deepcode-core"; -import { getNonce } from "./utils.js"; -import { handleWebviewMessage } from "./provider.js"; +import { getWebviewContent } from "./getWebviewContent.js"; +import { appRouter, type RouterContext } from "./router.js"; +import { attachRouterToPanel } from "@webview-rpc/host"; const DEFAULT_MODEL = "deepseek-v4-pro"; const DEFAULT_BASE_URL = "https://api.deepseek.com"; @@ -51,12 +48,8 @@ export class DeepCodeViewProvider implements vscode.WebviewViewProvider { getResolvedSettings: () => this.resolveCurrentSettings(), renderMarkdown: (text) => this.md.render(text), onAssistantMessage: (message: SessionMessage, shouldConnect: boolean) => { - if (!this.webviewView) { - return; - } - if (message.visible === false) { - return; - } + if (!this.webviewView) return; + if (message.visible === false) return; if (message.role !== "tool") { const reasoningContent = (message.messageParams as ReasoningMessageParams | null)?.reasoning_content; message.html = this.md.render(message.content || reasoningContent || ""); @@ -64,9 +57,7 @@ export class DeepCodeViewProvider implements vscode.WebviewViewProvider { this.webviewView.webview.postMessage({ type: "appendMessage", message, shouldConnect }); }, onSessionEntryUpdated: (entry) => { - if (!this.webviewView) { - return; - } + if (!this.webviewView) return; this.webviewView.webview.postMessage({ type: "sessionStatus", sessionId: entry.id, @@ -77,9 +68,7 @@ export class DeepCodeViewProvider implements vscode.WebviewViewProvider { }); }, onLlmStreamProgress: (progress: LlmStreamProgress) => { - if (!this.webviewView) { - return; - } + if (!this.webviewView) return; this.webviewView.webview.postMessage({ type: "llmStreamProgress", progress, @@ -93,306 +82,68 @@ export class DeepCodeViewProvider implements vscode.WebviewViewProvider { this.sessionManager.dispose(); } + postMessageToWebview(message: unknown): void { + if (this.webviewView) { + this.webviewView.webview.postMessage(message); + } + } + resolveWebviewView(webviewView: vscode.WebviewView): void { this.webviewView = webviewView; webviewView.webview.options = { enableScripts: true, - localResourceRoots: [this.context.extensionUri], + localResourceRoots: [vscode.Uri.file(path.join(this.context.extensionPath, "dist", "webview"))], }; - webviewView.webview.html = this.getWebviewHtml(webviewView.webview); - - webviewView.webview.onDidReceiveMessage(async (message) => { - const msg = message as Record | undefined; - - // openFile requires vscode API, handle here directly - if (msg?.type === "openFile") { - const filePath = String(msg.filePath || "").trim(); - const line = Number(msg.line || 1); - if (filePath) { - await this.openFileInEditor(filePath, line); + // Build RPC context + const rpcContext: RouterContext = { + sessionManager: this.sessionManager, + postMessage: (message) => this.webviewView?.webview.postMessage(message), + renderMarkdown: (text) => this.md.render(text), + copyToClipboard: (text) => void vscode.env.clipboard.writeText(text), + openFileInEditor: (filePath, line) => this.openFileInEditor(filePath, line), + getWorkspaceRoot: () => this.getWorkspaceRoot(), + openSettings: async () => { + // Open project-level settings if exists, otherwise user-level + const projectRoot = this.getWorkspaceRoot(); + const projectSettingsPath = path.join(projectRoot, ".deepcode", "settings.json"); + const userSettingsPath = path.join(os.homedir(), ".deepcode", "settings.json"); + + if (fs.existsSync(projectSettingsPath)) { + await this.openFileInEditor(projectSettingsPath, 1); + } else { + // Ensure user settings directory exists + const userSettingsDir = path.dirname(userSettingsPath); + if (!fs.existsSync(userSettingsDir)) { + fs.mkdirSync(userSettingsDir, { recursive: true }); + } + if (!fs.existsSync(userSettingsPath)) { + fs.writeFileSync(userSettingsPath, JSON.stringify({}, null, 2), "utf8"); + } + await this.openFileInEditor(userSettingsPath, 1); } - return; - } - - const handled = await handleWebviewMessage(message, { - sessionManager: this.sessionManager, - postMessage: (m) => this.webviewView?.webview.postMessage(m), - renderMarkdown: (text) => this.md.render(text), - copyToClipboard: (text) => void vscode.env.clipboard.writeText(text), - }); - - if (!handled) { - // unrecognized message type — no-op - } - }); - } - - private async loadInitialSession(): Promise { - const sessions = this.sessionManager.listSessions(); - const sessionsList = sessions.map((s) => ({ - id: s.id, - summary: s.summary || "Untitled", - createTime: s.createTime, - updateTime: s.updateTime, - status: s.status, - })); - - if (sessions.length === 0) { - // 没有历史会话,显示新对话界面 - this.sendMessage({ - type: "initializeEmpty", - sessions: sessionsList, - status: null, - tokenTelemetry: this.buildTokenTelemetry(null), - }); - return; - } - - // 显示最新的对话 - const latestSession = sessions[0]; - this.loadSession(latestSession.id); - } - - private loadSession(sessionId: string): void { - const session = this.sessionManager.getSession(sessionId); - if (!session) { - return; - } - - // 设置为活动会话 - this.sessionManager.setActiveSessionId(sessionId); - - const messages = this.sessionManager.listSessionMessages(sessionId); - - // 获取所有会话列表 - const sessions = this.sessionManager.listSessions(); - const sessionsList = sessions.map((s) => ({ - id: s.id, - summary: s.summary || "Untitled", - createTime: s.createTime, - updateTime: s.updateTime, - status: s.status, - })); - - // 发送对话信息到 webview - this.sendMessage({ - type: "loadSession", - sessionId, - summary: session.summary || "Untitled", - status: session.status, - askPermissions: session.askPermissions, - processes: this.serializeProcesses(session.processes), - tokenTelemetry: this.buildTokenTelemetry(session), - sessions: sessionsList, - messages: messages - .filter((m) => m.visible) - .map((m) => ({ - role: m.role, - content: m.content, - html: - m.role !== "tool" - ? this.md.render(m.content || (m.messageParams as ReasoningMessageParams | null)?.reasoning_content || "") - : undefined, - meta: m.meta, - })), - }); - } - - private showSessionsList(): void { - const sessions = this.sessionManager.listSessions(); - this.sendMessage({ - type: "showSessionsList", - sessions: sessions.map((s) => ({ - id: s.id, - summary: s.summary || "Untitled", - createTime: s.createTime, - updateTime: s.updateTime, - status: s.status, - })), - }); - } - - private async createNewSession(): Promise { - // 清除当前活动会话 - this.sessionManager.setActiveSessionId(null); + }, + getActiveEditor: () => { + const editor = vscode.window.activeTextEditor; + if (editor?.document) { + return { + fileName: editor.document.fileName, + languageId: editor.document.languageId, + lineCount: editor.document.lineCount, + }; + } + return null; + }, + }; - // 获取所有会话列表 - const sessions = this.sessionManager.listSessions(); - const sessionsList = sessions.map((s) => ({ - id: s.id, - summary: s.summary || "Untitled", - createTime: s.createTime, - updateTime: s.updateTime, - status: s.status, - })); + // Attach RPC router + attachRouterToPanel(appRouter, webviewView as unknown as vscode.WebviewPanel, rpcContext); - this.sendMessage({ - type: "initializeEmpty", - sessions: sessionsList, - status: null, - tokenTelemetry: this.buildTokenTelemetry(null), + // Set HTML content + getWebviewContent(this.context, webviewView.webview).then((html) => { + webviewView.webview.html = html; }); - await this.sendSkillsList(); - } - - private sendMessage(message: unknown): void { - if (!this.webviewView) { - return; - } - this.webviewView.webview.postMessage(message); - } - - private async sendSkillsList(sessionId?: string): Promise { - if (!this.webviewView) { - return; - } - const skills = await this.sessionManager.listSkills( - sessionId ?? this.sessionManager.getActiveSessionId() ?? undefined - ); - this.sendMessage({ type: "skillsList", skills }); - } - - private async handlePrompt( - prompt: string, - skills?: SkillInfo[], - imageUrls?: string[], - options: { permissions?: UserToolPermission[]; alwaysAllows?: PermissionScope[] } = {} - ): Promise { - if (!this.webviewView) { - return; - } - - const webview = this.webviewView.webview; - const normalizedImages = Array.isArray(imageUrls) ? imageUrls.filter(Boolean) : []; - const displayPrompt = prompt || (normalizedImages.length > 0 ? "粘贴的图像" : ""); - const isPermissionContinue = - prompt === "/continue" && - normalizedImages.length === 0 && - ((options.permissions?.length ?? 0) > 0 || (options.alwaysAllows?.length ?? 0) > 0); - - // 先显示用户消息(原始文本,不做 HTML 格式化) - if (displayPrompt && !isPermissionContinue) { - webview.postMessage({ type: "userMessage", content: displayPrompt }); - } - - webview.postMessage({ type: "loading", value: true }); - - try { - const userPrompt: UserPromptContent = { - text: prompt, - skills, - imageUrls: normalizedImages, - permissions: options.permissions, - alwaysAllows: options.alwaysAllows, - }; - await this.sessionManager.handleUserPrompt(userPrompt); - await this.sendSkillsList(); - - const activeSessionId = this.sessionManager.getActiveSessionId(); - const activeSession = activeSessionId ? this.sessionManager.getSession(activeSessionId) : null; - if (activeSessionId && activeSession) { - webview.postMessage({ - type: "sessionStatus", - sessionId: activeSessionId, - status: activeSession.status, - askPermissions: activeSession.askPermissions, - processes: this.serializeProcesses(activeSession.processes), - tokenTelemetry: this.buildTokenTelemetry(activeSession), - }); - } - - // 发送更新后的会话列表(可能创建了新会话) - const sessions = this.sessionManager.listSessions(); - const sessionsList = sessions.map((s) => ({ - id: s.id, - summary: s.summary || "Untitled", - createTime: s.createTime, - updateTime: s.updateTime, - status: s.status, - })); - webview.postMessage({ - type: "showSessionsList", - sessions: sessionsList, - }); - } catch (error) { - const message = error instanceof Error ? error.message : String(error); - webview.postMessage({ - type: "assistant", - html: this.md.render(`Request failed: ${message}`), - }); - } finally { - webview.postMessage({ type: "loading", value: false }); - } - } - - private handlePermissionDenied(sessionId: string): void { - this.sessionManager.denySessionPermission(sessionId); - const session = this.sessionManager.getSession(sessionId); - if (session) { - this.sendMessage({ - type: "sessionStatus", - sessionId, - status: session.status, - askPermissions: session.askPermissions, - processes: this.serializeProcesses(session.processes), - tokenTelemetry: this.buildTokenTelemetry(session), - }); - } - this.showSessionsList(); - } - - private createOpenAIClient(): { - client: OpenAI | null; - model: string; - baseURL: string; - thinkingEnabled: boolean; - reasoningEffort: ReasoningEffort; - debugLogEnabled: boolean; - notify?: string; - webSearchTool?: string; - env?: Record; - machineId?: string; - } { - const settings = this.resolveCurrentSettings(); - - const { apiKey, baseURL, model, thinkingEnabled, reasoningEffort, debugLogEnabled, notify, webSearchTool, env } = - settings; - const machineId = vscode.env.machineId; - - if (!apiKey) { - return { - client: null, - model, - baseURL, - thinkingEnabled, - reasoningEffort, - debugLogEnabled, - notify, - webSearchTool, - env, - machineId, - }; - } - - const client = new OpenAI({ - apiKey, - baseURL: baseURL || undefined, - }); - - return { - client, - model, - baseURL, - thinkingEnabled, - reasoningEffort, - debugLogEnabled, - notify, - webSearchTool, - env, - machineId, - }; } private buildTokenTelemetry(session: SessionEntry | null): { @@ -431,22 +182,17 @@ export class DeepCodeViewProvider implements vscode.WebviewViewProvider { model: DEFAULT_MODEL, baseURL: DEFAULT_BASE_URL, }, - process.env + process.env as Record ); } private readUserSettings(): DeepcodingSettings | null { try { const settingsPath = path.join(os.homedir(), ".deepcode", "settings.json"); - if (!fs.existsSync(settingsPath)) { - return null; - } - + if (!fs.existsSync(settingsPath)) return null; const raw = fs.readFileSync(settingsPath, "utf8"); return JSON.parse(raw) as DeepcodingSettings; - } catch (error) { - const message = error instanceof Error ? error.message : String(error); - vscode.window.showErrorMessage(`Failed to read ~/.deepcode/settings.json: ${message}`); + } catch { return null; } } @@ -455,36 +201,71 @@ export class DeepCodeViewProvider implements vscode.WebviewViewProvider { const workspaceRoot = this.getWorkspaceRoot(); try { const settingsPath = path.join(workspaceRoot, ".deepcode", "settings.json"); - if (!fs.existsSync(settingsPath)) { - return null; - } - + if (!fs.existsSync(settingsPath)) return null; const raw = fs.readFileSync(settingsPath, "utf8"); return JSON.parse(raw) as DeepcodingSettings; - } catch (error) { - const message = error instanceof Error ? error.message : String(error); - vscode.window.showErrorMessage( - `Failed to read ${path.join(workspaceRoot, ".deepcode", "settings.json")}: ${message}` - ); + } catch { return null; } } private getWorkspaceRoot(): string { const workspace = vscode.workspace.workspaceFolders?.[0]; - if (workspace) { - return workspace.uri.fsPath; - } + if (workspace) return workspace.uri.fsPath; return process.cwd(); } + private createOpenAIClient(): { + client: OpenAI | null; + model: string; + baseURL: string; + thinkingEnabled: boolean; + reasoningEffort: ReasoningEffort; + debugLogEnabled: boolean; + notify?: string; + webSearchTool?: string; + env?: Record; + machineId?: string; + } { + const settings = this.resolveCurrentSettings(); + const { apiKey, baseURL, model, thinkingEnabled, reasoningEffort, debugLogEnabled, notify, webSearchTool, env } = + settings; + const machineId = vscode.env.machineId; + + if (!apiKey) { + return { + client: null, + model, + baseURL, + thinkingEnabled, + reasoningEffort, + debugLogEnabled, + notify, + webSearchTool, + env, + machineId, + }; + } + + const client = new OpenAI({ apiKey, baseURL: baseURL || undefined }); + return { + client, + model, + baseURL, + thinkingEnabled, + reasoningEffort, + debugLogEnabled, + notify, + webSearchTool, + env, + machineId, + }; + } + private serializeProcesses( processes: Map | null ): Record | null { - if (!processes || processes.size === 0) { - return null; - } - + if (!processes || processes.size === 0) return null; const serialized: Record = {}; for (const [pid, entry] of processes.entries()) { serialized[pid] = entry; @@ -492,47 +273,16 @@ export class DeepCodeViewProvider implements vscode.WebviewViewProvider { return serialized; } - private getWebviewHtml(webview: vscode.Webview): string { - const nonce = getNonce(); - const csp = webview.cspSource; - - // 读取 HTML 模板文件 - const htmlPath = vscode.Uri.joinPath(this.context.extensionUri, "resources", "webview.html"); - let html = fs.readFileSync(htmlPath.fsPath, "utf8"); - - // 获取 CSS 文件 URI - const cssPath = vscode.Uri.joinPath(this.context.extensionUri, "resources", "webview.css"); - const cssUri = webview.asWebviewUri(cssPath); - const attachmentsJsPath = vscode.Uri.joinPath(this.context.extensionUri, "resources", "prompt-attachments.js"); - const attachmentsJsUri = webview.asWebviewUri(attachmentsJsPath); - - // 获取 Logo 文件 URI - const iconPath = vscode.Uri.joinPath(this.context.extensionUri, "resources", "deepcoding_icon.png"); - const iconUri = webview.asWebviewUri(iconPath); - - // 替换占位符 - html = html.replace(/\{\{nonce\}\}/g, nonce); - html = html.replace(/\{\{cspSource\}\}/g, csp); - html = html.replace(/\{\{cssUri\}\}/g, cssUri.toString()); - html = html.replace(/\{\{attachmentsJsUri\}\}/g, attachmentsJsUri.toString()); - html = html.replace(/\{\{iconUri\}\}/g, iconUri.toString()); - html = html.replace(/\{\{workspaceRoot\}\}/g, JSON.stringify(this.getWorkspaceRoot())); - - return html; - } - private async openFileInEditor(filePath: string, line: number): Promise { const document = await vscode.workspace.openTextDocument(vscode.Uri.file(filePath)); const editor = await vscode.window.showTextDocument(document, { preview: false, preserveFocus: false, }); - const targetLine = Number.isFinite(line) && line > 0 ? Math.floor(line) - 1 : 0; const safeLine = Math.min(Math.max(0, targetLine), Math.max(0, document.lineCount - 1)); const position = new vscode.Position(safeLine, 0); - const selection = new vscode.Selection(position, position); - editor.selection = selection; + editor.selection = new vscode.Selection(position, position); editor.revealRange(new vscode.Range(position, position), vscode.TextEditorRevealType.InCenter); } } @@ -548,7 +298,36 @@ export function activate(context: vscode.ExtensionContext): void { const provider = new DeepCodeViewProvider(context); context.subscriptions.push(provider); - context.subscriptions.push(vscode.window.registerWebviewViewProvider(DeepCodeViewProvider.viewType, provider)); + context.subscriptions.push( + vscode.window.registerWebviewViewProvider(DeepCodeViewProvider.viewType, provider, { + webviewOptions: { retainContextWhenHidden: true }, + }) + ); + + // Listen for active editor changes and send to webview + const sendActiveEditorInfo = () => { + const editor = vscode.window.activeTextEditor; + if (editor?.document) { + const doc = editor.document; + provider.postMessageToWebview({ + type: "activeEditor", + fileName: doc.fileName, + languageId: doc.languageId, + lineCount: doc.lineCount, + }); + } + }; + + // Send initial active editor + sendActiveEditorInfo(); + + // Listen for editor changes + context.subscriptions.push( + vscode.window.onDidChangeActiveTextEditor(() => { + sendActiveEditorInfo(); + }) + ); + context.subscriptions.push( vscode.commands.registerCommand("deepcode.openView", async () => { await vscode.commands.executeCommand("workbench.view.extension.deepcode"); diff --git a/packages/vscode-ide-companion/src/getWebviewContent.ts b/packages/vscode-ide-companion/src/getWebviewContent.ts new file mode 100644 index 00000000..6fccdfff --- /dev/null +++ b/packages/vscode-ide-companion/src/getWebviewContent.ts @@ -0,0 +1,128 @@ +import { randomUUID } from "node:crypto"; +import * as fs from "node:fs"; +import * as path from "node:path"; +import * as vscode from "vscode"; + +const PORT = 5174; + +interface DevUris { + refreshUri: vscode.Uri; + clientUri: vscode.Uri; + entryUri: vscode.Uri; + origin: string; + wsOrigin: string; +} + +function createBaseCSP(webview: vscode.Webview): string[] { + return [ + `default-src 'none'`, + `img-src ${webview.cspSource} https: data:`, + `style-src ${webview.cspSource} 'unsafe-inline'`, + `font-src ${webview.cspSource} https:`, + `frame-src ${webview.cspSource} https:`, + ]; +} + +function createDevCSP(webview: vscode.Webview, nonce: string, origin: string, wsOrigin: string): string { + return ( + [ + `default-src 'none'`, + `img-src ${webview.cspSource} ${origin} http://localhost:${PORT} http://127.0.0.1:${PORT} https: data:`, + `style-src ${webview.cspSource} 'unsafe-inline'`, + `font-src ${webview.cspSource} ${origin} http://localhost:${PORT} http://127.0.0.1:${PORT} https: data:`, + `frame-src ${webview.cspSource} https:`, + `script-src 'nonce-${nonce}' 'unsafe-eval' 'unsafe-inline' ${origin}`, + `connect-src 'self' ${origin} ${wsOrigin} ws://localhost:${PORT} ws://127.0.0.1:${PORT}`, + ].join("; ") + ";" + ); +} + +function createProdCSP(webview: vscode.Webview, nonce: string): string { + return ( + [ + ...createBaseCSP(webview), + `script-src 'nonce-${nonce}' ${webview.cspSource}`, + `connect-src ${webview.cspSource}`, + ].join("; ") + ";" + ); +} + +async function getDevUris(): Promise { + const refreshLocal = vscode.Uri.parse(`http://localhost:${PORT}/@react-refresh`); + const clientLocal = vscode.Uri.parse(`http://localhost:${PORT}/@vite/client`); + const entryLocal = vscode.Uri.parse(`http://localhost:${PORT}/main.tsx`); + + const [refreshUri, clientUri, entryUri] = await Promise.all([ + vscode.env.asExternalUri(refreshLocal), + vscode.env.asExternalUri(clientLocal), + vscode.env.asExternalUri(entryLocal), + ]); + + const origin = `${clientUri.scheme}://${clientUri.authority}`; + const wsOrigin = origin.replace(/^http/, "ws"); + + return { refreshUri, clientUri, entryUri, origin, wsOrigin }; +} + +function createDevHTML(nonce: string, uris: DevUris, csp: string): string { + return ` + + + + + + + Deep Code (Dev) + + +
+ + + + + + + + `; +} + +function processProductionHtml(htmlContent: string, webview: vscode.Webview, distPath: string, nonce: string): string { + const processedHtml = htmlContent.replace(/(href|src)=["']([^"']*)["']/g, (match, attr, url) => { + if (url.startsWith("http") || url.startsWith("data:") || url.startsWith("#") || url === "") { + return match; + } + const clean = url.replace(/^\//, ""); + const onDisk = vscode.Uri.file(path.join(distPath, clean)); + const webviewUri = webview.asWebviewUri(onDisk).toString(); + return `${attr}="${webviewUri}"`; + }); + + const csp = createProdCSP(webview, nonce); + + return processedHtml + .replace("", ``) + .replace(/]*)type="module"([^>]*)>/g, ``); +} + +export async function getWebviewContent(context: vscode.ExtensionContext, webview: vscode.Webview): Promise { + const isDev = context.extensionMode === vscode.ExtensionMode.Development; + const nonce = randomUUID(); + + if (isDev) { + const uris = await getDevUris(); + const csp = createDevCSP(webview, nonce, uris.origin, uris.wsOrigin); + return createDevHTML(nonce, uris, csp); + } + + const htmlPath = path.join(context.extensionPath, "dist", "webview", "index.html"); + const distPath = path.join(context.extensionPath, "dist", "webview"); + const htmlContent = fs.readFileSync(htmlPath, "utf8"); + + return processProductionHtml(htmlContent, webview, distPath, nonce); +} diff --git a/packages/vscode-ide-companion/src/provider.ts b/packages/vscode-ide-companion/src/provider.ts deleted file mode 100644 index 2e3b4ac8..00000000 --- a/packages/vscode-ide-companion/src/provider.ts +++ /dev/null @@ -1,323 +0,0 @@ -/** - * Message handling logic for the Deepcoding webview provider. - * Extracted from extension.ts for testability — no direct vscode dependency. - */ -import type { SessionManager } from "@vegamo/deepcode-core"; -import type { PermissionScope, SkillInfo, UserToolPermission } from "@vegamo/deepcode-core"; -import { parseUserToolPermissions, parsePermissionScopes } from "./utils.js"; - -export interface PostMessageFn { - (message: unknown): void; -} - -export interface ProviderDeps { - sessionManager: Pick< - SessionManager, - | "listSessions" - | "getSession" - | "getActiveSessionId" - | "setActiveSessionId" - | "listSessionMessages" - | "handleUserPrompt" - | "interruptActiveSession" - | "denySessionPermission" - | "listSkills" - >; - postMessage: PostMessageFn; - renderMarkdown: (text: string) => string; - copyToClipboard: (text: string) => void; -} - -export interface SessionSummary { - id: string; - summary: string; - createTime: string; - updateTime: string; - status: string; -} - -function toSessionList( - sessions: Array<{ id: string; summary?: string | null; createTime: string; updateTime: string; status: string }> -): SessionSummary[] { - return sessions.map((s) => ({ - id: s.id, - summary: s.summary || "Untitled", - createTime: s.createTime, - updateTime: s.updateTime, - status: s.status, - })); -} - -/** - * Routes incoming webview messages to the appropriate handler. - * Returns true if the message was handled. - */ -export async function handleWebviewMessage(message: unknown, deps: ProviderDeps): Promise { - const { sessionManager, postMessage, renderMarkdown, copyToClipboard } = deps; - - if (!message || typeof message !== "object") { - return false; - } - - const msg = message as Record; - - if (msg.type === "ready") { - loadInitialSession(sessionManager, postMessage, renderMarkdown); - await sendSkillsList(sessionManager, postMessage); - return true; - } - - if (msg.type === "requestSkills") { - await sendSkillsList(sessionManager, postMessage); - return true; - } - - if (msg.type === "userPrompt") { - const prompt = String(msg.prompt || "").trim(); - const images = Array.isArray(msg.images) - ? (msg.images as unknown[]).filter((image): image is string => typeof image === "string" && image.length > 0) - : []; - const permissions = parseUserToolPermissions(msg.permissions); - const alwaysAllows = parsePermissionScopes(msg.alwaysAllows); - if (!prompt && images.length === 0 && permissions.length === 0 && alwaysAllows.length === 0) { - return true; - } - const skills = (msg.skills as SkillInfo[]) || []; - await handlePrompt(prompt, skills, images, sessionManager, postMessage, renderMarkdown, { - permissions: permissions.length > 0 ? permissions : undefined, - alwaysAllows: alwaysAllows.length > 0 ? alwaysAllows : undefined, - }); - return true; - } - - if (msg.type === "interrupt") { - sessionManager.interruptActiveSession(); - return true; - } - - if (msg.type === "denyPermission") { - const sessionId = String(msg.sessionId || sessionManager.getActiveSessionId() || "").trim(); - if (sessionId) { - handlePermissionDenied(sessionId, sessionManager, postMessage); - } - return true; - } - - if (msg.type === "createNewSession") { - await createNewSession(sessionManager, postMessage); - return true; - } - - if (msg.type === "selectSession") { - const sessionId = String(msg.sessionId || "").trim(); - if (sessionId) { - loadSession(sessionId, sessionManager, postMessage, renderMarkdown); - await sendSkillsList(sessionManager, postMessage, sessionId); - } - return true; - } - - if (msg.type === "backToList") { - showSessionsList(sessionManager, postMessage); - return true; - } - - if (msg.type === "openFile") { - // openFile requires vscode API — handled by the caller - return false; - } - - if (msg.type === "copyText") { - const text = String(msg.text || ""); - if (text) { - copyToClipboard(text); - } - return true; - } - - return false; -} - -function loadInitialSession( - sessionManager: ProviderDeps["sessionManager"], - postMessage: PostMessageFn, - renderMarkdown: (text: string) => string -): void { - const sessions = sessionManager.listSessions(); - const sessionsList = toSessionList(sessions); - - if (sessions.length === 0) { - postMessage({ - type: "initializeEmpty", - sessions: sessionsList, - status: null, - }); - return; - } - - const latestSession = sessions[0]; - loadSession(latestSession.id, sessionManager, postMessage, renderMarkdown); -} - -export function loadSession( - sessionId: string, - sessionManager: ProviderDeps["sessionManager"], - postMessage: PostMessageFn, - renderMarkdown: (text: string) => string -): void { - const session = sessionManager.getSession(sessionId); - if (!session) { - return; - } - - sessionManager.setActiveSessionId(sessionId); - const messages = sessionManager.listSessionMessages(sessionId); - const sessions = sessionManager.listSessions(); - - postMessage({ - type: "loadSession", - sessionId, - summary: session.summary || "Untitled", - status: session.status, - askPermissions: session.askPermissions, - processes: serializeProcesses(session.processes), - sessions: toSessionList(sessions), - messages: messages - .filter((m) => m.visible) - .map((m) => ({ - role: m.role, - content: m.content, - html: - m.role !== "tool" - ? renderMarkdown( - m.content || (m.messageParams as { reasoning_content?: string } | null)?.reasoning_content || "" - ) - : undefined, - meta: m.meta, - })), - }); -} - -function showSessionsList(sessionManager: ProviderDeps["sessionManager"], postMessage: PostMessageFn): void { - const sessions = sessionManager.listSessions(); - postMessage({ - type: "showSessionsList", - sessions: toSessionList(sessions), - }); -} - -async function createNewSession( - sessionManager: ProviderDeps["sessionManager"], - postMessage: PostMessageFn -): Promise { - sessionManager.setActiveSessionId(null); - const sessions = sessionManager.listSessions(); - - postMessage({ - type: "initializeEmpty", - sessions: toSessionList(sessions), - status: null, - }); - await sendSkillsList(sessionManager, postMessage); -} - -async function sendSkillsList( - sessionManager: ProviderDeps["sessionManager"], - postMessage: PostMessageFn, - sessionId?: string -): Promise { - const skills = await sessionManager.listSkills(sessionId ?? sessionManager.getActiveSessionId() ?? undefined); - postMessage({ type: "skillsList", skills }); -} - -async function handlePrompt( - prompt: string, - skills: SkillInfo[], - imageUrls: string[], - sessionManager: ProviderDeps["sessionManager"], - postMessage: PostMessageFn, - renderMarkdown: (text: string) => string, - options: { permissions?: UserToolPermission[]; alwaysAllows?: PermissionScope[] } = {} -): Promise { - const normalizedImages = imageUrls.filter(Boolean); - const displayPrompt = prompt || (normalizedImages.length > 0 ? "粘贴的图像" : ""); - const isPermissionContinue = - prompt === "/continue" && - normalizedImages.length === 0 && - ((options.permissions?.length ?? 0) > 0 || (options.alwaysAllows?.length ?? 0) > 0); - - if (displayPrompt && !isPermissionContinue) { - postMessage({ type: "userMessage", content: displayPrompt }); - } - - postMessage({ type: "loading", value: true }); - - try { - await sessionManager.handleUserPrompt({ - text: prompt, - skills, - imageUrls: normalizedImages, - permissions: options.permissions, - alwaysAllows: options.alwaysAllows, - }); - await sendSkillsList(sessionManager, postMessage); - - const activeSessionId = sessionManager.getActiveSessionId(); - const activeSession = activeSessionId ? sessionManager.getSession(activeSessionId) : null; - if (activeSessionId && activeSession) { - postMessage({ - type: "sessionStatus", - sessionId: activeSessionId, - status: activeSession.status, - askPermissions: activeSession.askPermissions, - processes: serializeProcesses(activeSession.processes), - }); - } - - const sessions = sessionManager.listSessions(); - postMessage({ - type: "showSessionsList", - sessions: toSessionList(sessions), - }); - } catch (error) { - const message = error instanceof Error ? error.message : String(error); - postMessage({ - type: "assistant", - html: renderMarkdown(`Request failed: ${message}`), - }); - } finally { - postMessage({ type: "loading", value: false }); - } -} - -function handlePermissionDenied( - sessionId: string, - sessionManager: ProviderDeps["sessionManager"], - postMessage: PostMessageFn -): void { - sessionManager.denySessionPermission(sessionId); - const session = sessionManager.getSession(sessionId); - if (session) { - postMessage({ - type: "sessionStatus", - sessionId, - status: session.status, - askPermissions: session.askPermissions, - processes: serializeProcesses(session.processes), - }); - } - showSessionsList(sessionManager, postMessage); -} - -function serializeProcesses( - processes: Map | null -): Record | null { - if (!processes || processes.size === 0) { - return null; - } - const serialized: Record = {}; - for (const [pid, entry] of processes.entries()) { - serialized[pid] = entry; - } - return serialized; -} diff --git a/packages/vscode-ide-companion/src/router.ts b/packages/vscode-ide-companion/src/router.ts new file mode 100644 index 00000000..b6584694 --- /dev/null +++ b/packages/vscode-ide-companion/src/router.ts @@ -0,0 +1,255 @@ +import { initWRPC } from "@webview-rpc/host"; +import z from "zod"; +import type { SessionManager, SkillInfo, UserToolPermission, PermissionScope } from "@vegamo/deepcode-core"; + +export interface RouterContext { + sessionManager: SessionManager; + postMessage: (message: unknown) => void; + renderMarkdown: (text: string) => string; + copyToClipboard: (text: string) => void; + openFileInEditor: (filePath: string, line: number) => Promise; + getWorkspaceRoot: () => string; + openSettings: () => Promise; + getActiveEditor: () => { fileName: string; languageId: string; lineCount: number } | null; +} + +export const { router, procedure } = initWRPC.context().create(); + +function toSessionList( + sessions: Array<{ id: string; summary?: string | null; createTime: string; updateTime: string; status: string }> +) { + return sessions.map((s) => ({ + id: s.id, + summary: s.summary || "Untitled", + createTime: s.createTime, + updateTime: s.updateTime, + status: s.status, + })); +} + +function serializeProcesses( + processes: Map | null +): Record | null { + if (!processes || processes.size === 0) return null; + const serialized: Record = {}; + for (const [pid, entry] of processes.entries()) { + serialized[pid] = entry; + } + return serialized; +} + +const sendPromptInput = z.object({ + prompt: z.string().default(""), + skills: z + .array( + z.object({ + name: z.string(), + description: z.string().optional(), + path: z.string().optional(), + isLoaded: z.boolean().optional(), + }) + ) + .default([]), + images: z.array(z.string()).default([]), + permissions: z + .array( + z.object({ + toolCallId: z.string(), + permission: z.enum(["allow", "deny"]), + }) + ) + .optional(), + alwaysAllows: z.array(z.string()).optional(), +}); + +export const appRouter = router({ + // --- Queries --- + + getInitialData: procedure.resolve(({ ctx }) => { + const sessions = ctx.sessionManager.listSessions(); + const sessionsList = toSessionList(sessions); + const activeSessionId = ctx.sessionManager.getActiveSessionId(); + const activeSession = activeSessionId ? ctx.sessionManager.getSession(activeSessionId) : null; + + let messages: Array = []; + if (activeSessionId && activeSession) { + messages = ctx.sessionManager + .listSessionMessages(activeSessionId) + .filter((m) => m.visible) + .map((m) => ({ + role: m.role, + content: m.content, + html: + m.role !== "tool" + ? ctx.renderMarkdown( + m.content || (m.messageParams as { reasoning_content?: string } | null)?.reasoning_content || "" + ) + : undefined, + meta: m.meta, + })); + } + + // Get active editor info + const activeEditor = ctx.getActiveEditor(); + + return { + sessions: sessionsList, + activeSession: activeSession + ? { + id: activeSession.id, + summary: activeSession.summary || "Untitled", + status: activeSession.status, + askPermissions: activeSession.askPermissions, + processes: serializeProcesses(activeSession.processes), + messages, + } + : null, + activeEditor, + }; + }), + + getSkills: procedure.input(z.string().optional()).resolve(async ({ ctx, input }) => { + const skills = await ctx.sessionManager.listSkills(input ?? ctx.sessionManager.getActiveSessionId() ?? undefined); + return { skills }; + }), + + getSessions: procedure.resolve(({ ctx }) => { + const sessions = ctx.sessionManager.listSessions(); + return { sessions: toSessionList(sessions) }; + }), + + // --- Mutations --- + + sendPrompt: procedure.input(sendPromptInput).resolve(async ({ ctx, input }) => { + const { prompt, skills, images, permissions, alwaysAllows } = input; + const normalizedImages = images.filter(Boolean); + + const hasPayload = + prompt || normalizedImages.length > 0 || (permissions?.length ?? 0) > 0 || (alwaysAllows?.length ?? 0) > 0; + if (!hasPayload) { + return { ok: false, error: "Empty prompt" }; + } + + const displayPrompt = prompt || (normalizedImages.length > 0 ? "粘贴的图像" : ""); + const isPermissionContinue = + prompt === "/continue" && + normalizedImages.length === 0 && + ((permissions?.length ?? 0) > 0 || (alwaysAllows?.length ?? 0) > 0); + + // Show user message in webview + if (displayPrompt && !isPermissionContinue) { + ctx.postMessage({ type: "userMessage", content: displayPrompt }); + } + + ctx.postMessage({ type: "loading", value: true }); + + try { + const userPrompt = { + text: prompt, + skills: skills.length > 0 ? (skills as SkillInfo[]) : undefined, + imageUrls: normalizedImages.length > 0 ? normalizedImages : undefined, + permissions: permissions && permissions.length > 0 ? (permissions as UserToolPermission[]) : undefined, + alwaysAllows: alwaysAllows && alwaysAllows.length > 0 ? (alwaysAllows as PermissionScope[]) : undefined, + }; + await ctx.sessionManager.handleUserPrompt(userPrompt); + + return { ok: true }; + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + ctx.postMessage({ + type: "assistant", + html: ctx.renderMarkdown(`Request failed: ${message}`), + }); + return { ok: false, error: message }; + } finally { + ctx.postMessage({ type: "loading", value: false }); + } + }), + + createNewSession: procedure.resolve(async ({ ctx }) => { + ctx.sessionManager.setActiveSessionId(null); + const sessions = ctx.sessionManager.listSessions(); + const skills = await ctx.sessionManager.listSkills(); + return { sessions: toSessionList(sessions), skills }; + }), + + selectSession: procedure.input(z.string()).resolve(({ ctx, input: sessionId }) => { + const session = ctx.sessionManager.getSession(sessionId); + if (!session) { + return { ok: false, error: "Session not found" }; + } + + ctx.sessionManager.setActiveSessionId(sessionId); + const messages = ctx.sessionManager.listSessionMessages(sessionId); + const sessions = ctx.sessionManager.listSessions(); + + return { + ok: true, + session: { + id: session.id, + summary: session.summary || "Untitled", + status: session.status, + askPermissions: session.askPermissions, + processes: serializeProcesses(session.processes), + }, + sessions: toSessionList(sessions), + messages: messages + .filter((m) => m.visible) + .map((m) => ({ + role: m.role, + content: m.content, + html: + m.role !== "tool" + ? ctx.renderMarkdown( + m.content || (m.messageParams as { reasoning_content?: string } | null)?.reasoning_content || "" + ) + : undefined, + meta: m.meta, + })), + }; + }), + + interrupt: procedure.resolve(({ ctx }) => { + ctx.sessionManager.interruptActiveSession(); + return { ok: true }; + }), + + denyPermission: procedure.input(z.string()).resolve(({ ctx, input: sessionId }) => { + ctx.sessionManager.denySessionPermission(sessionId); + const session = ctx.sessionManager.getSession(sessionId); + if (session) { + ctx.postMessage({ + type: "sessionStatus", + sessionId, + status: session.status, + askPermissions: session.askPermissions, + processes: serializeProcesses(session.processes), + }); + } + return { ok: true }; + }), + + copyText: procedure.input(z.string()).resolve(({ ctx, input }) => { + ctx.copyToClipboard(input); + return { ok: true }; + }), + + openFile: procedure + .input( + z.object({ + filePath: z.string(), + line: z.number().default(1), + }) + ) + .resolve(async ({ ctx, input }) => { + await ctx.openFileInEditor(input.filePath, input.line); + return { ok: true }; + }), + + openSettings: procedure.resolve(async ({ ctx }) => { + await ctx.openSettings(); + return { ok: true }; + }), +}); + +export type AppRouter = typeof appRouter; diff --git a/packages/vscode-ide-companion/src/tests/extension-utils.test.ts b/packages/vscode-ide-companion/src/tests/extension-utils.test.ts deleted file mode 100644 index 8dea36de..00000000 --- a/packages/vscode-ide-companion/src/tests/extension-utils.test.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { test } from "node:test"; -import assert from "node:assert/strict"; -import { VALID_PERMISSION_SCOPES, parseUserToolPermissions, parsePermissionScopes, getNonce } from "../utils.js"; - -// --- VALID_PERMISSION_SCOPES --- - -test("VALID_PERMISSION_SCOPES contains all expected scopes", () => { - const expected = [ - "read-in-cwd", - "read-out-cwd", - "write-in-cwd", - "write-out-cwd", - "delete-in-cwd", - "delete-out-cwd", - "query-git-log", - "mutate-git-log", - "network", - "mcp", - ]; - assert.equal(VALID_PERMISSION_SCOPES.size, expected.length); - for (const scope of expected) { - assert.ok(VALID_PERMISSION_SCOPES.has(scope as any), `missing scope: ${scope}`); - } -}); - -// --- parseUserToolPermissions --- - -test("parseUserToolPermissions returns empty array for non-array input", () => { - assert.deepEqual(parseUserToolPermissions(undefined), []); - assert.deepEqual(parseUserToolPermissions(null), []); - assert.deepEqual(parseUserToolPermissions("string"), []); - assert.deepEqual(parseUserToolPermissions(123), []); - assert.deepEqual(parseUserToolPermissions({}), []); -}); - -test("parseUserToolPermissions returns empty array for empty array", () => { - assert.deepEqual(parseUserToolPermissions([]), []); -}); - -test("parseUserToolPermissions parses valid permissions", () => { - const input = [ - { toolCallId: "call-1", permission: "allow" }, - { toolCallId: "call-2", permission: "deny" }, - ]; - const result = parseUserToolPermissions(input); - assert.equal(result.length, 2); - assert.deepEqual(result[0], { toolCallId: "call-1", permission: "allow" }); - assert.deepEqual(result[1], { toolCallId: "call-2", permission: "deny" }); -}); - -test("parseUserToolPermissions filters out invalid items", () => { - const input = [ - null, - 123, - "string", - {}, - { toolCallId: "", permission: "allow" }, // empty toolCallId - { toolCallId: " ", permission: "allow" }, // whitespace-only toolCallId - { toolCallId: "call-1" }, // missing permission - { toolCallId: "call-2", permission: "invalid" }, // invalid permission value - { permission: "allow" }, // missing toolCallId - { toolCallId: "call-3", permission: "allow" }, // valid - ]; - const result = parseUserToolPermissions(input); - assert.equal(result.length, 1); - assert.deepEqual(result[0], { toolCallId: "call-3", permission: "allow" }); -}); - -test("parseUserToolPermissions preserves toolCallId with leading/trailing spaces", () => { - const input = [{ toolCallId: " call-1 ", permission: "allow" }]; - const result = parseUserToolPermissions(input); - // trimmed toolCallId " " fails the .trim() check, so this item is filtered - // Wait, " call-1 ".trim() = "call-1" which is truthy, so it passes - assert.equal(result.length, 1); - assert.equal(result[0].toolCallId, " call-1 "); -}); - -// --- parsePermissionScopes --- - -test("parsePermissionScopes returns empty array for non-array input", () => { - assert.deepEqual(parsePermissionScopes(undefined), []); - assert.deepEqual(parsePermissionScopes(null), []); - assert.deepEqual(parsePermissionScopes("string"), []); - assert.deepEqual(parsePermissionScopes(123), []); - assert.deepEqual(parsePermissionScopes({}), []); -}); - -test("parsePermissionScopes returns empty array for empty array", () => { - assert.deepEqual(parsePermissionScopes([]), []); -}); - -test("parsePermissionScopes parses valid scopes", () => { - const input = ["read-in-cwd", "write-in-cwd", "network"]; - const result = parsePermissionScopes(input); - assert.equal(result.length, 3); - assert.deepEqual(result, ["read-in-cwd", "write-in-cwd", "network"]); -}); - -test("parsePermissionScopes filters out invalid values", () => { - const input = ["read-in-cwd", "invalid-scope", 123, null, undefined, {}, "mcp"]; - const result = parsePermissionScopes(input); - assert.equal(result.length, 2); - assert.deepEqual(result, ["read-in-cwd", "mcp"]); -}); - -test("parsePermissionScopes deduplicates scopes", () => { - const input = ["read-in-cwd", "write-in-cwd", "read-in-cwd", "network", "network"]; - const result = parsePermissionScopes(input); - assert.equal(result.length, 3); - assert.deepEqual(result, ["read-in-cwd", "write-in-cwd", "network"]); -}); - -// --- getNonce --- - -test("getNonce returns a 32-character string", () => { - const nonce = getNonce(); - assert.equal(nonce.length, 32); -}); - -test("getNonce only contains alphanumeric characters", () => { - const nonce = getNonce(); - assert.ok(/^[A-Za-z0-9]+$/.test(nonce), `nonce contains non-alphanumeric chars: ${nonce}`); -}); - -test("getNonce returns different values on successive calls", () => { - const nonces = new Set(); - for (let i = 0; i < 100; i++) { - nonces.add(getNonce()); - } - // With 62^32 possible values, 100 calls should almost certainly be unique - assert.ok(nonces.size > 90, `Expected mostly unique nonces, got ${nonces.size} unique out of 100`); -}); diff --git a/packages/vscode-ide-companion/src/tests/extension.test.ts b/packages/vscode-ide-companion/src/tests/extension.test.ts deleted file mode 100644 index 9ea39656..00000000 --- a/packages/vscode-ide-companion/src/tests/extension.test.ts +++ /dev/null @@ -1,477 +0,0 @@ -import { test } from "node:test"; -import assert from "node:assert/strict"; -import { handleWebviewMessage, loadSession, type ProviderDeps } from "../provider.js"; - -// --- Helpers --- - -function createMockSessionManager(options?: { sessions?: any[]; messages?: any[]; skills?: any[] }) { - const sessions = options?.sessions ?? [ - { - id: "session-1", - summary: "Test Session", - status: "idle", - askPermissions: null, - processes: null, - activeTokens: 100, - usage: null, - createTime: "2025-01-01T00:00:00Z", - updateTime: "2025-01-01T00:00:00Z", - }, - ]; - const messages = options?.messages ?? []; - const skills = options?.skills ?? []; - let activeSessionId: string | null = sessions[0]?.id ?? null; - - return { - dispose: () => {}, - listSessions: () => sessions, - getSession: (id: string) => sessions.find((s: any) => s.id === id) ?? null, - getActiveSessionId: () => activeSessionId, - setActiveSessionId: (id: string | null) => { - activeSessionId = id; - }, - listSessionMessages: (_sessionId: string) => messages, - handleUserPrompt: () => Promise.resolve(), - interruptActiveSession: () => {}, - denySessionPermission: (_sessionId: string) => {}, - listSkills: () => Promise.resolve(skills), - initMcpServers: () => Promise.resolve(), - }; -} - -function createDeps(options?: Parameters[0]): ProviderDeps & { messages: unknown[] } { - const messages: unknown[] = []; - return { - sessionManager: createMockSessionManager(options), - postMessage: (msg: unknown) => { - messages.push(msg); - }, - renderMarkdown: (text: string) => `

${text}

`, - copyToClipboard: () => {}, - messages, - }; -} - -// --- handleWebviewMessage routing --- - -test("handleWebviewMessage returns false for null message", async () => { - const deps = createDeps(); - const result = await handleWebviewMessage(null, deps); - assert.equal(result, false); -}); - -test("handleWebviewMessage returns false for non-object message", async () => { - const deps = createDeps(); - assert.equal(await handleWebviewMessage("string", deps), false); - assert.equal(await handleWebviewMessage(123, deps), false); -}); - -test("handleWebviewMessage returns false for unknown message type", async () => { - const deps = createDeps(); - assert.equal(await handleWebviewMessage({ type: "unknownType" }, deps), false); -}); - -test("ready message triggers loadInitialSession and sendSkillsList", async () => { - const deps = createDeps(); - const handled = await handleWebviewMessage({ type: "ready" }, deps); - - assert.equal(handled, true); - const types = deps.messages.map((m: any) => m.type); - // With sessions present, should send loadSession + skillsList - assert.ok(types.includes("loadSession"), `Expected loadSession, got: ${types.join(", ")}`); - assert.ok(types.includes("skillsList"), `Expected skillsList, got: ${types.join(", ")}`); -}); - -test("ready message renders markdown for initial session messages", async () => { - const deps = createDeps({ - messages: [{ role: "assistant", content: "**bold**", visible: true }], - }); - - await handleWebviewMessage({ type: "ready" }, deps); - - const loadMsg = deps.messages.find((m: any) => m.type === "loadSession") as any; - assert.ok(loadMsg, "Should send loadSession"); - assert.equal(loadMsg.messages[0].html, "

**bold**

"); -}); - -test("ready with no sessions sends initializeEmpty", async () => { - const deps = createDeps({ sessions: [] }); - await handleWebviewMessage({ type: "ready" }, deps); - - const types = deps.messages.map((m: any) => m.type); - assert.ok(types.includes("initializeEmpty"), `Expected initializeEmpty, got: ${types.join(", ")}`); -}); - -test("requestSkills sends skillsList", async () => { - const deps = createDeps({ skills: [{ name: "test-skill" }] }); - await handleWebviewMessage({ type: "requestSkills" }, deps); - - const skillsMsg = deps.messages.find((m: any) => m.type === "skillsList"); - assert.ok(skillsMsg, "Should send skillsList"); - assert.deepEqual((skillsMsg as any).skills, [{ name: "test-skill" }]); -}); - -test("interrupt calls interruptActiveSession", async () => { - const deps = createDeps(); - let interrupted = false; - (deps.sessionManager as any).interruptActiveSession = () => { - interrupted = true; - }; - - const handled = await handleWebviewMessage({ type: "interrupt" }, deps); - assert.equal(handled, true); - assert.ok(interrupted, "interruptActiveSession should be called"); -}); - -test("createNewSession clears active session and sends initializeEmpty", async () => { - const deps = createDeps(); - let cleared = false; - (deps.sessionManager as any).setActiveSessionId = (id: string | null) => { - if (id === null) cleared = true; - }; - - await handleWebviewMessage({ type: "createNewSession" }, deps); - - assert.ok(cleared, "setActiveSessionId(null) should be called"); - const types = deps.messages.map((m: any) => m.type); - assert.ok(types.includes("initializeEmpty"), `Expected initializeEmpty, got: ${types.join(", ")}`); - assert.ok(types.includes("skillsList"), `Expected skillsList, got: ${types.join(", ")}`); -}); - -test("selectSession loads session and sends skillsList", async () => { - const deps = createDeps(); - let loadedId: string | null = null; - (deps.sessionManager as any).setActiveSessionId = (id: string) => { - loadedId = id; - }; - - await handleWebviewMessage({ type: "selectSession", sessionId: "session-1" }, deps); - - assert.equal(loadedId, "session-1"); - const types = deps.messages.map((m: any) => m.type); - assert.ok(types.includes("loadSession"), `Expected loadSession, got: ${types.join(", ")}`); - assert.ok(types.includes("skillsList"), `Expected skillsList, got: ${types.join(", ")}`); -}); - -test("selectSession with empty sessionId does nothing", async () => { - const deps = createDeps(); - await handleWebviewMessage({ type: "selectSession", sessionId: "" }, deps); - assert.equal(deps.messages.length, 0, "No messages for empty sessionId"); -}); - -test("selectSession with non-existent session does not send loadSession", async () => { - const deps = createDeps(); - (deps.sessionManager as any).getSession = () => null; - - await handleWebviewMessage({ type: "selectSession", sessionId: "non-existent" }, deps); - - const types = deps.messages.map((m: any) => m.type); - assert.ok(!types.includes("loadSession"), "Should not send loadSession for non-existent session"); -}); - -test("backToList sends showSessionsList", async () => { - const deps = createDeps(); - await handleWebviewMessage({ type: "backToList" }, deps); - - const msg = deps.messages.find((m: any) => m.type === "showSessionsList"); - assert.ok(msg, "Should send showSessionsList"); - assert.ok(Array.isArray((msg as any).sessions), "sessions should be an array"); -}); - -test("denyPermission calls denySessionPermission and sends sessionStatus", async () => { - const deps = createDeps(); - let deniedId: string | null = null; - (deps.sessionManager as any).denySessionPermission = (id: string) => { - deniedId = id; - }; - - await handleWebviewMessage({ type: "denyPermission", sessionId: "session-1" }, deps); - - assert.equal(deniedId, "session-1"); - const types = deps.messages.map((m: any) => m.type); - assert.ok(types.includes("sessionStatus"), `Expected sessionStatus, got: ${types.join(", ")}`); - assert.ok(types.includes("showSessionsList"), `Expected showSessionsList, got: ${types.join(", ")}`); -}); - -test("denyPermission with empty sessionId does nothing", async () => { - const deps = createDeps(); - (deps.sessionManager as any).getActiveSessionId = () => null; - - await handleWebviewMessage({ type: "denyPermission", sessionId: "" }, deps); - - // No sessionStatus should be sent - const types = deps.messages.map((m: any) => m.type); - assert.ok(!types.includes("sessionStatus"), "Should not send sessionStatus for empty sessionId"); -}); - -test("copyText calls copyToClipboard", async () => { - const deps = createDeps(); - let copiedText: string | null = null; - deps.copyToClipboard = (text: string) => { - copiedText = text; - }; - - const handled = await handleWebviewMessage({ type: "copyText", text: "hello" }, deps); - assert.equal(handled, true); - assert.equal(copiedText, "hello"); -}); - -test("copyText with empty text does not call copyToClipboard", async () => { - const deps = createDeps(); - let copied = false; - deps.copyToClipboard = () => { - copied = true; - }; - - await handleWebviewMessage({ type: "copyText", text: "" }, deps); - assert.ok(!copied, "Should not copy empty text"); -}); - -test("openFile returns false (handled by caller)", async () => { - const deps = createDeps(); - const result = await handleWebviewMessage({ type: "openFile", filePath: "/some/file.ts" }, deps); - assert.equal(result, false); -}); - -// --- userPrompt --- - -test("userPrompt with empty prompt and no images/permissions is handled without messages", async () => { - const deps = createDeps(); - const handled = await handleWebviewMessage( - { type: "userPrompt", prompt: "", images: [], permissions: [], alwaysAllows: [] }, - deps - ); - assert.equal(handled, true); - assert.equal(deps.messages.length, 0, "No messages for empty prompt"); -}); - -test("userPrompt with text sends userMessage and loading states", async () => { - const deps = createDeps(); - await handleWebviewMessage({ type: "userPrompt", prompt: "hello" }, deps); - - const types = deps.messages.map((m: any) => m.type); - assert.ok(types.includes("userMessage"), `Expected userMessage, got: ${types.join(", ")}`); - assert.ok(types.includes("loading"), `Expected loading, got: ${types.join(", ")}`); - - // Should end with loading: false - const lastLoading = [...deps.messages].reverse().find((m: any) => m.type === "loading"); - assert.deepEqual(lastLoading, { type: "loading", value: false }); -}); - -test("userPrompt with images sends userMessage with image placeholder", async () => { - const deps = createDeps(); - await handleWebviewMessage({ type: "userPrompt", prompt: "", images: ["data:image/png;base64,abc"] }, deps); - - const userMsg = deps.messages.find((m: any) => m.type === "userMessage"); - assert.ok(userMsg, "Should send userMessage for images"); - assert.equal((userMsg as any).content, "粘贴的图像"); -}); - -test("userPrompt passes multiple image urls to the session manager", async () => { - const deps = createDeps(); - let submittedPrompt: any = null; - (deps.sessionManager as any).handleUserPrompt = (prompt: any) => { - submittedPrompt = prompt; - return Promise.resolve(); - }; - - await handleWebviewMessage( - { - type: "userPrompt", - prompt: "", - images: ["data:image/png;base64,abc", "data:image/jpeg;base64,def"], - }, - deps - ); - - assert.deepEqual(submittedPrompt?.imageUrls, ["data:image/png;base64,abc", "data:image/jpeg;base64,def"]); -}); - -test("userPrompt with permissions (continue) does not send userMessage", async () => { - const deps = createDeps(); - await handleWebviewMessage( - { - type: "userPrompt", - prompt: "/continue", - images: [], - permissions: [{ toolCallId: "call-1", permission: "allow" }], - }, - deps - ); - - const userMsg = deps.messages.find((m: any) => m.type === "userMessage"); - assert.ok(!userMsg, "Should not send userMessage for /continue with permissions"); -}); - -test("userPrompt sends sessionStatus after handling", async () => { - const deps = createDeps(); - await handleWebviewMessage({ type: "userPrompt", prompt: "hello" }, deps); - - const types = deps.messages.map((m: any) => m.type); - assert.ok(types.includes("sessionStatus"), `Expected sessionStatus, got: ${types.join(", ")}`); -}); - -test("userPrompt sends showSessionsList after handling", async () => { - const deps = createDeps(); - await handleWebviewMessage({ type: "userPrompt", prompt: "hello" }, deps); - - const sessionsMsg = deps.messages.find((m: any) => m.type === "showSessionsList"); - assert.ok(sessionsMsg, "Should send showSessionsList"); - assert.ok(Array.isArray((sessionsMsg as any).sessions), "sessions should be an array"); -}); - -test("userPrompt on error sends assistant error message", async () => { - const deps = createDeps(); - (deps.sessionManager as any).handleUserPrompt = () => Promise.reject(new Error("API failed")); - - await handleWebviewMessage({ type: "userPrompt", prompt: "hello" }, deps); - - const assistantMsg = deps.messages.find((m: any) => m.type === "assistant"); - assert.ok(assistantMsg, "Should send assistant error message"); - assert.ok((assistantMsg as any).html.includes("API failed"), "Error message should contain the error text"); -}); - -test("userPrompt always sends loading: false even on error", async () => { - const deps = createDeps(); - (deps.sessionManager as any).handleUserPrompt = () => Promise.reject(new Error("fail")); - - await handleWebviewMessage({ type: "userPrompt", prompt: "hello" }, deps); - - const lastLoading = [...deps.messages].reverse().find((m: any) => m.type === "loading"); - assert.deepEqual(lastLoading, { type: "loading", value: false }); -}); - -// --- loadSession --- - -test("loadSession sends loadSession with correct fields", () => { - const sessionManager = createMockSessionManager(); - const messages: unknown[] = []; - const postMessage = (msg: unknown) => { - messages.push(msg); - }; - - loadSession("session-1", sessionManager, postMessage, (t) => t); - - const msg = messages.find((m: any) => m.type === "loadSession") as any; - assert.ok(msg, "Should send loadSession"); - assert.equal(msg.sessionId, "session-1"); - assert.equal(msg.summary, "Test Session"); - assert.equal(msg.status, "idle"); - assert.ok(Array.isArray(msg.sessions), "sessions should be an array"); - assert.ok(Array.isArray(msg.messages), "messages should be an array"); -}); - -test("loadSession with non-existent session does nothing", () => { - const sessionManager = createMockSessionManager(); - const messages: unknown[] = []; - const postMessage = (msg: unknown) => { - messages.push(msg); - }; - - (sessionManager as any).getSession = () => null; - loadSession("non-existent", sessionManager, postMessage, (t) => t); - - assert.equal(messages.length, 0, "No messages for non-existent session"); -}); - -test("loadSession sets active session id", () => { - const sessionManager = createMockSessionManager(); - const messages: unknown[] = []; - let setTo: string | null = null; - (sessionManager as any).setActiveSessionId = (id: string) => { - setTo = id; - }; - - loadSession( - "session-1", - sessionManager, - (msg) => messages.push(msg), - (t) => t - ); - - assert.equal(setTo, "session-1"); -}); - -test("loadSession filters out invisible messages", () => { - const sessionManager = createMockSessionManager({ - messages: [ - { role: "user", content: "visible", visible: true }, - { role: "assistant", content: "hidden", visible: false }, - { role: "user", content: "also visible", visible: true }, - ], - }); - const messages: unknown[] = []; - loadSession( - "session-1", - sessionManager, - (msg) => messages.push(msg), - (t) => t - ); - - const loadMsg = messages.find((m: any) => m.type === "loadSession") as any; - assert.equal(loadMsg.messages.length, 2, "Should filter out invisible messages"); -}); - -// --- serializeProcesses --- - -test("loadSession serializes processes map to object", () => { - const sessionManager = createMockSessionManager({ - sessions: [ - { - id: "session-1", - summary: "Test", - status: "idle", - askPermissions: null, - processes: new Map([ - ["123", { startTime: "2025-01-01", command: "ls" }], - ["456", { startTime: "2025-01-02", command: "cat" }], - ]), - activeTokens: 0, - usage: null, - createTime: "2025-01-01", - updateTime: "2025-01-01", - }, - ], - }); - const messages: unknown[] = []; - loadSession( - "session-1", - sessionManager, - (msg) => messages.push(msg), - (t) => t - ); - - const loadMsg = messages.find((m: any) => m.type === "loadSession") as any; - assert.deepEqual(loadMsg.processes, { - "123": { startTime: "2025-01-01", command: "ls" }, - "456": { startTime: "2025-01-02", command: "cat" }, - }); -}); - -test("loadSession returns null for empty processes", () => { - const sessionManager = createMockSessionManager({ - sessions: [ - { - id: "session-1", - summary: "Test", - status: "idle", - askPermissions: null, - processes: null, - activeTokens: 0, - usage: null, - createTime: "2025-01-01", - updateTime: "2025-01-01", - }, - ], - }); - const messages: unknown[] = []; - loadSession( - "session-1", - sessionManager, - (msg) => messages.push(msg), - (t) => t - ); - - const loadMsg = messages.find((m: any) => m.type === "loadSession") as any; - assert.equal(loadMsg.processes, null); -}); diff --git a/packages/vscode-ide-companion/src/tests/prompt-attachments.test.ts b/packages/vscode-ide-companion/src/tests/prompt-attachments.test.ts deleted file mode 100644 index 314826e3..00000000 --- a/packages/vscode-ide-companion/src/tests/prompt-attachments.test.ts +++ /dev/null @@ -1,240 +0,0 @@ -import { test } from "node:test"; -import assert from "node:assert/strict"; -import fs from "node:fs"; -import path from "node:path"; -import vm from "node:vm"; -import { fileURLToPath } from "node:url"; - -type EventHandler = (event: any) => unknown; - -class FakeClassList { - private readonly classes = new Set(); - - constructor(className = "") { - for (const classPart of className.split(/\s+/)) { - if (classPart) { - this.classes.add(classPart); - } - } - } - - add(className: string): void { - this.classes.add(className); - } - - remove(className: string): void { - this.classes.delete(className); - } - - contains(className: string): boolean { - return this.classes.has(className); - } - - toggle(className: string, force?: boolean): boolean { - const shouldAdd = force ?? !this.classes.has(className); - if (shouldAdd) { - this.classes.add(className); - } else { - this.classes.delete(className); - } - return shouldAdd; - } -} - -class FakeElement { - readonly tagName: string; - className = ""; - classList = new FakeClassList(); - children: FakeElement[] = []; - parent: FakeElement | null = null; - dataset: Record = {}; - style: Record = {}; - textContent = ""; - tabIndex = 0; - draggable = false; - href = ""; - src = ""; - alt = ""; - private readonly attributes = new Map(); - private readonly listeners = new Map(); - - constructor(tagName: string) { - this.tagName = tagName; - } - - setAttribute(name: string, value: string): void { - this.attributes.set(name, value); - } - - appendChild(child: FakeElement): FakeElement { - child.parent = this; - this.children.push(child); - return child; - } - - set innerHTML(_value: string) { - for (const child of this.children) { - child.parent = null; - } - this.children = []; - } - - get innerHTML(): string { - return ""; - } - - addEventListener(type: string, handler: EventHandler): void { - const listeners = this.listeners.get(type) ?? []; - listeners.push(handler); - this.listeners.set(type, listeners); - } - - async dispatchEvent(event: any): Promise { - event.type ??= ""; - for (const handler of this.listeners.get(event.type) ?? []) { - await handler(event); - } - } - - contains(candidate: FakeElement | null): boolean { - if (!candidate) { - return false; - } - if (candidate === this) { - return true; - } - return this.children.some((child) => child.contains(candidate)); - } - - querySelector(selector: string): FakeElement | null { - if (!selector.startsWith(".")) { - return null; - } - const className = selector.slice(1); - for (const child of this.children) { - if (child.className.split(/\s+/).includes(className)) { - return child; - } - const match = child.querySelector(selector); - if (match) { - return match; - } - } - return null; - } - - getBoundingClientRect(): { left: number; top: number; bottom: number; width: number; height: number } { - return { left: 20, top: 80, bottom: 100, width: 160, height: 40 }; - } -} - -class FakeDocument { - readonly body = new FakeElement("body"); - - createElement(tagName: string): FakeElement { - return new FakeElement(tagName); - } -} - -class FakeFileReader { - result: string | null = null; - onload: (() => void) | null = null; - onerror: (() => void) | null = null; - error: Error | null = null; - - readAsDataURL(file: { dataUrl?: string }): void { - this.result = file.dataUrl ?? ""; - this.onload?.(); - } -} - -function loadAttachmentManager(): { - manager: { clear: () => void; hasAttachments: () => boolean; getImageUrls: () => string[] }; - promptInput: FakeElement; - toolsLine: FakeElement; -} { - const __dirname = path.dirname(fileURLToPath(import.meta.url)); - const scriptPath = path.resolve(__dirname, "../../resources/prompt-attachments.js"); - const script = fs.readFileSync(scriptPath, "utf8"); - - const document = new FakeDocument(); - const window = { - innerWidth: 1024, - innerHeight: 768, - addEventListener: () => {}, - createPromptAttachmentManager: undefined as - | undefined - | ((options: Record) => { - clear: () => void; - hasAttachments: () => boolean; - getImageUrls: () => string[]; - }), - }; - - vm.runInNewContext(script, { console, document, window, FileReader: FakeFileReader }); - - const createPromptAttachmentManager = window.createPromptAttachmentManager; - if (typeof createPromptAttachmentManager !== "function") { - throw new Error("Prompt attachment manager was not registered."); - } - const promptInput = new FakeElement("textarea"); - const inputWrap = new FakeElement("div"); - const toolsLine = new FakeElement("div"); - const manager = createPromptAttachmentManager({ promptInput, inputWrap, toolsLine }); - - return { manager, promptInput, toolsLine }; -} - -async function pasteImage(promptInput: FakeElement, dataUrl: string): Promise { - let defaultPrevented = false; - await promptInput.dispatchEvent({ - type: "paste", - clipboardData: { - items: [ - { - kind: "file", - getAsFile: () => ({ type: "image/png", name: "image.png", dataUrl }), - }, - ], - }, - preventDefault: () => { - defaultPrevented = true; - }, - }); - assert.equal(defaultPrevented, true); -} - -test("prompt attachment manager appends pasted images instead of replacing the previous image", async () => { - const { manager, promptInput, toolsLine } = loadAttachmentManager(); - - await pasteImage(promptInput, "data:image/png;base64,first"); - await pasteImage(promptInput, "data:image/png;base64,second"); - - assert.equal(manager.hasAttachments(), true); - assert.deepEqual(Array.from(manager.getImageUrls()), ["data:image/png;base64,first", "data:image/png;base64,second"]); - assert.equal(toolsLine.children.length, 2); - assert.equal(toolsLine.classList.contains("has-attachment"), true); -}); - -test("prompt attachment manager removes one pasted image without clearing the rest", async () => { - const { manager, promptInput, toolsLine } = loadAttachmentManager(); - - await pasteImage(promptInput, "data:image/png;base64,first"); - await pasteImage(promptInput, "data:image/png;base64,second"); - - const firstAttachment = toolsLine.children[0]; - const removeButton = firstAttachment.children[0]; - await removeButton.dispatchEvent({ - type: "click", - preventDefault: () => {}, - stopPropagation: () => {}, - }); - - assert.deepEqual(Array.from(manager.getImageUrls()), ["data:image/png;base64,second"]); - assert.equal(toolsLine.children.length, 1); - - manager.clear(); - assert.equal(manager.hasAttachments(), false); - assert.deepEqual(Array.from(manager.getImageUrls()), []); - assert.equal(toolsLine.children.length, 0); -}); diff --git a/packages/vscode-ide-companion/src/tests/run-tests.mjs b/packages/vscode-ide-companion/src/tests/run-tests.mjs deleted file mode 100644 index 73034d8a..00000000 --- a/packages/vscode-ide-companion/src/tests/run-tests.mjs +++ /dev/null @@ -1,15 +0,0 @@ -// Test runner for @vegamo/deepcode-vscode -import { globSync } from "glob"; -import { spawnSync } from "child_process"; -import { fileURLToPath } from "url"; -import * as path from "path"; - -const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const testFiles = globSync("*.test.ts", { cwd: __dirname }); - -const result = spawnSync(process.execPath, ["--import", "tsx", "--test", ...testFiles], { - stdio: "inherit", - cwd: __dirname, -}); - -process.exit(result.status ?? 1); diff --git a/packages/vscode-ide-companion/src/tests/setup.ts b/packages/vscode-ide-companion/src/tests/setup.ts new file mode 100644 index 00000000..49a59b04 --- /dev/null +++ b/packages/vscode-ide-companion/src/tests/setup.ts @@ -0,0 +1,97 @@ +/** + * Vitest setup file + * + * Configures global test utilities and mocks. + */ + +import "@testing-library/jest-dom"; +import { vi } from "vitest"; + +// --------------------------------------------------------------------------- +// Global mocks +// --------------------------------------------------------------------------- + +// Mock window.matchMedia +Object.defineProperty(window, "matchMedia", { + writable: true, + value: vi.fn().mockImplementation((query: string) => ({ + matches: false, + media: query, + onchange: null, + addListener: vi.fn(), + removeListener: vi.fn(), + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), + })), +}); + +// Mock ResizeObserver +class ResizeObserverMock { + observe = vi.fn(); + unobserve = vi.fn(); + disconnect = vi.fn(); +} +window.ResizeObserver = ResizeObserverMock; + +// Mock IntersectionObserver +class IntersectionObserverMock implements IntersectionObserver { + observe = vi.fn(); + unobserve = vi.fn(); + disconnect = vi.fn(); + takeRecords = vi.fn(); + root: Element | null = null; + rootMargin: string = ""; + thresholds: ReadonlyArray = []; + constructor() {} +} +window.IntersectionObserver = IntersectionObserverMock as unknown as typeof IntersectionObserver; + +// Mock VS Code API +const mockVSCode = { + postMessage: vi.fn(), + getState: vi.fn(() => ({})), + setState: vi.fn(), +}; +Object.defineProperty(window, "acquireVsCodeApi", { + writable: true, + value: () => mockVSCode, +}); + +// Mock localStorage +const localStorageMock = { + getItem: vi.fn(), + setItem: vi.fn(), + removeItem: vi.fn(), + clear: vi.fn(), +}; +Object.defineProperty(window, "localStorage", { + writable: true, + value: localStorageMock, +}); + +// Mock navigator.onLine +Object.defineProperty(navigator, "onLine", { + writable: true, + value: true, +}); + +// --------------------------------------------------------------------------- +// Global test utilities +// --------------------------------------------------------------------------- + +// Silence console.error in tests unless explicitly needed +// Uncomment the following to see all console errors during tests: +// global.console.error = console.error; + +// Suppress specific warnings in tests +const originalWarn = console.warn; +console.warn = (...args: unknown[]) => { + if ( + typeof args[0] === "string" && + (args[0].includes("ReactDOM.render") || args[0].includes("act()") || args[0].includes("Warning:")) + ) { + return; + } + originalWarn(...args); +}; diff --git a/packages/vscode-ide-companion/src/webview/App.tsx b/packages/vscode-ide-companion/src/webview/App.tsx new file mode 100644 index 00000000..7c95ffad --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/App.tsx @@ -0,0 +1,58 @@ +import Header from "@/webview/components/Header"; +import Messages from "@/webview/components/Messages"; +import Composer from "@/webview/components/Composer"; +import ThinkingLiveBubble from "@/webview/components/ThinkingLiveBubble"; +import PermissionPrompt from "@/webview/components/PermissionPrompt"; +import { useChat } from "@/webview/context/ChatProvider"; + +export default function App() { + const { state, dispatch, actions } = useChat(); + + return ( +
+
+ + + {state.loading && ( + + )} + +
+ ); +} diff --git a/packages/vscode-ide-companion/src/webview/components/AskUserQuestion.tsx b/packages/vscode-ide-companion/src/webview/components/AskUserQuestion.tsx new file mode 100644 index 00000000..41886bf7 --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/AskUserQuestion.tsx @@ -0,0 +1,227 @@ +import { useCallback } from "react"; +import { Button } from "@/webview/components/ui/button"; +import { + Field, + FieldContent, + FieldDescription, + FieldError, + FieldGroup, + FieldLabel, +} from "@/webview/components/ui/field"; +import { Checkbox } from "@/webview/components/ui/checkbox"; +import { Textarea } from "@/webview/components/ui/textarea"; +import { RadioGroup, RadioGroupItem } from "@/webview/components/ui/radio-group"; +import { Controller, useForm } from "react-hook-form"; +import * as z from "zod"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "./ui/card"; +import { buildAskUserQuestionReply } from "@/webview/utils"; + +interface QuestionOption { + label: string; + description?: string; +} + +interface Question { + question: string; + multiSelect?: boolean; + options?: QuestionOption[]; +} + +interface ToolData { + ok: boolean; + name: string; + output: string; + metadata?: { + kind?: string; + questions?: Question[]; + }; +} + +interface AskUserQuestionProps { + toolData: ToolData; +} +const answerSchema = z + .object({ + question: z.string(), + options: z.array(z.string()).optional(), + other: z.string().optional(), + }) + .superRefine((data, ctx) => { + const opts = data.options ?? []; + const oth = data.other ?? ""; + if (opts.length === 0 && oth.trim().length === 0) { + ctx.addIssue({ + code: "custom", + message: "Please answer the question.", + path: ["other"], + }); + } + }); + +const formSchema = z.object({ + answers: z.array(answerSchema), +}); + +export type AnswerFormValues = z.infer; + +export default function AskUserQuestion({ toolData }: AskUserQuestionProps) { + const questions = toolData.metadata?.questions || []; + + const form = useForm({ + resolver: zodResolver(formSchema), + defaultValues: { + answers: questions.map((q) => ({ + question: q.question, + options: [] as string[], + other: "", + })), + }, + }); + + // 实时监听每个问题的答案,用于决定是否禁用提交按钮 + const watchedAnswers = form.watch("answers"); + const allEmpty = + watchedAnswers?.every((a) => { + const opts = a?.options ?? []; + const oth = a?.other ?? ""; + return opts.length === 0 && oth.trim().length === 0; + }) ?? true; + + const onSubmit = useCallback( + (data: AnswerFormValues) => { + console.log(JSON.stringify(data.answers)); + const reply = buildAskUserQuestionReply(data?.answers || []); + console.log("reply:", JSON.stringify(reply)); + if (!reply.ok) { + console.log("reply.error:", reply.error || "Please answer the question."); + form.setError("answers", { message: reply.error || "Please answer the question." }); + return; + } + // sendUserPromptText(reply.text); + }, + [form] + ); + + if (questions.length === 0) { + return
{toolData.output || "No questions were provided."}
; + } + + return ( +
+
+
The agent needs your input before it can continue.
+ {questions.map((q, qIdx) => ( + + + {q.question || `Question ${qIdx + 1}`} + + + + {q.multiSelect ? ( + (q.options || []).map((opt, optIdx) => ( + ( + + { + const newValue = checked + ? [...(field.value || []), opt.label] + : field.value + ? field.value.filter((v) => v !== opt.label) + : []; + field.onChange(newValue); + }} + /> + + + {opt.label} + + {opt.description && ( + + {opt.description} + + )} + {fieldState.invalid && } + + + )} + /> + )) + ) : ( + ( + field.onChange([val])} + aria-invalid={fieldState.invalid} + > + {(q.options || []).map((opt, optIdx) => ( + + + + + {opt.label} + + {opt.description && ( + + {opt.description} + + )} + + + ))} + + )} + /> + )} + ( + + + Other + + + )), + InputGroupText: vi.fn(({ children }) => {children}), +})); + +vi.mock("@/webview/components/ui/field", () => ({ + Field: vi.fn(({ children }) =>
{children}
), + FieldGroup: vi.fn(({ children }) =>
{children}
), +})); + +vi.mock("@/webview/components/ui/separator", () => ({ + Separator: vi.fn(() =>
), +})); + +vi.mock("@/webview/components/ui/dropdown-menu", () => ({ + DropdownMenu: vi.fn(({ children }) =>
{children}
), + DropdownMenuTrigger: vi.fn(({ children }) =>
{children}
), + DropdownMenuContent: vi.fn(({ children }) =>
{children}
), + DropdownMenuItem: vi.fn(({ children }) =>
{children}
), +})); + +vi.mock("@/webview/components/ui/scroll-area", () => ({ + ScrollArea: vi.fn(({ children }) =>
{children}
), +})); + +vi.mock("@/webview/components/ui/popover", () => ({ + Popover: vi.fn(({ children }) =>
{children}
), + PopoverTrigger: vi.fn(({ children }) =>
{children}
), + PopoverContent: vi.fn(({ children }) =>
{children}
), +})); + +vi.mock("@/webview/lib/utils", () => ({ + cn: vi.fn((...args: unknown[]) => args.filter(Boolean).join(" ")), +})); + +vi.mock("lucide-react", () => ({ + ArrowUp: vi.fn(() => ), + Square: vi.fn(() => ), + StopCircle: vi.fn(() => ), + ChevronDown: vi.fn(() => ), + Send: vi.fn(() => ), + FileCodeIcon: vi.fn(() => ), + GraduationCap: vi.fn(() => ), + X: vi.fn(() => ), + AlertCircle: vi.fn(() => ), + CheckCircle: vi.fn(() => ), + Loader2: vi.fn(() => ), + Settings: vi.fn(() => ), + Info: vi.fn(() => ), +})); + +const mockOnSendPrompt = + vi.fn< + ( + prompt: string, + skills?: SkillInfo[], + images?: string[], + options?: { permissions?: unknown[]; alwaysAllows?: string[] } + ) => void + >(); +const mockOnInterrupt = vi.fn<() => void>(); +const mockOnSelectSkills = vi.fn<(skills: SkillInfo[]) => void>(); + +const defaultProps: ComposerProps = { + loading: false, + selectedSkills: [] as SkillInfo[], + availableSkills: [] as SkillInfo[], + pendingPermissionReply: null, + askPermissions: [], + activeSessionStatus: null, + tokenTelemetry: { + model: "test", + thinkingEnabled: false, + reasoningEffort: "low", + activeTokens: 0, + compactPromptTokenThreshold: 100000, + usage: null, + }, + activeEditor: null, + onSendPrompt: mockOnSendPrompt, + onInterrupt: mockOnInterrupt, + onSelectSkills: mockOnSelectSkills, +}; + +describe("Composer", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + describe("handleSend", () => { + it("calls onSendPrompt when sending a message", async () => { + render(); + const textarea = screen.getByRole("textbox"); + fireEvent.change(textarea, { target: { value: "Hello" } }); + fireEvent.keyDown(textarea, { key: "Enter" }); + expect(mockOnSendPrompt).toHaveBeenCalledWith("Hello", [], [], undefined); + }); + + it("does not send empty message", () => { + render(); + const textarea = screen.getByRole("textbox"); + fireEvent.keyDown(textarea, { key: "Enter" }); + expect(mockOnSendPrompt).not.toHaveBeenCalled(); + }); + + it("trims whitespace before sending", async () => { + render(); + const textarea = screen.getByRole("textbox"); + fireEvent.change(textarea, { target: { value: " Hello " } }); + fireEvent.keyDown(textarea, { key: "Enter" }); + expect(mockOnSendPrompt).toHaveBeenCalledWith("Hello", [], [], undefined); + }); + + it("does not send while loading", () => { + render(); + const textarea = screen.getByRole("textbox"); + fireEvent.change(textarea, { target: { value: "Hello" } }); + fireEvent.keyDown(textarea, { key: "Enter" }); + expect(mockOnSendPrompt).not.toHaveBeenCalled(); + }); + }); + + describe("Keyboard navigation", () => { + it("does not send on Shift+Enter", () => { + render(); + const textarea = screen.getByRole("textbox"); + fireEvent.change(textarea, { target: { value: "Hello" } }); + fireEvent.keyDown(textarea, { key: "Enter", shiftKey: true }); + expect(mockOnSendPrompt).not.toHaveBeenCalled(); + }); + + it("does not send on other keys", () => { + render(); + const textarea = screen.getByRole("textbox"); + fireEvent.change(textarea, { target: { value: "Hello" } }); + fireEvent.keyDown(textarea, { key: "A" }); + expect(mockOnSendPrompt).not.toHaveBeenCalled(); + }); + }); + + describe("Loading state", () => { + it("renders interrupt button when loading", () => { + render(); + expect(screen.getByTestId("input-group-button")).toBeInTheDocument(); + }); + + it("calls onInterrupt when interrupt button clicked", () => { + render(); + const button = screen.getByTestId("input-group-button"); + fireEvent.click(button); + expect(mockOnInterrupt).toHaveBeenCalled(); + }); + }); + + describe("Skills", () => { + it("renders skills panel", () => { + render(); + expect(screen.getByTestId("skills-panel")).toBeInTheDocument(); + }); + + it("passes selectedSkills to onSelectSkills", () => { + const skills = [{ id: "skill1", name: "TestSkill" }]; + render(); + // Skills panel should be rendered with skills + expect(screen.getByTestId("skills-panel")).toBeInTheDocument(); + }); + }); + + describe("Context meter", () => { + it("renders context meter", () => { + render(); + expect(screen.getByTestId("context-meter")).toBeInTheDocument(); + }); + }); + + describe("Hover card", () => { + it("renders hover card when activeEditor is null", () => { + render(); + // HoverCard may or may not be rendered based on activeEditor + expect(screen.getByTestId("field-group")).toBeInTheDocument(); + }); + + it("renders hover card when activeEditor is provided", () => { + render( + + ); + expect(screen.getByTestId("hover-card")).toBeInTheDocument(); + }); + }); +}); diff --git a/packages/vscode-ide-companion/src/webview/components/Composer.tsx b/packages/vscode-ide-companion/src/webview/components/Composer.tsx new file mode 100644 index 00000000..6bc305aa --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/Composer.tsx @@ -0,0 +1,213 @@ +import React, { useCallback, useEffect, useRef, useState } from "react"; +import SkillsPanel from "@/webview/components/SkillsPanel"; +import SkillsTags from "@/webview/components/SkillsTags"; +import ContextMeter from "@/webview/components/ContextMeter"; +import type { ActiveEditor, SkillInfo, TokenTelemetry } from "@/webview/types"; +import { FileCodeIcon, Send, Square } from "lucide-react"; +import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupTextarea } from "@/webview/components/ui/input-group"; +import { Separator } from "@/webview/components/ui/separator"; +import { HoverCard, HoverCardContent, HoverCardTrigger } from "./ui/hover-card"; +import { cn } from "@/webview/lib/utils"; +import { Field, FieldGroup } from "./ui/field"; + +export interface ComposerProps { + loading: boolean; + selectedSkills: SkillInfo[]; + availableSkills: SkillInfo[]; + pendingPermissionReply: unknown; + askPermissions: unknown[]; + activeSessionStatus: string | null; + tokenTelemetry?: TokenTelemetry; + activeEditor: ActiveEditor | null; + onSendPrompt: ( + prompt: string, + skills?: SkillInfo[], + images?: string[], + options?: { permissions?: unknown[]; alwaysAllows?: string[] } + ) => void; + onInterrupt: () => void; + onSelectSkills: (skills: SkillInfo[]) => void; +} + +export default function Composer({ + loading, + selectedSkills, + availableSkills, + pendingPermissionReply, + askPermissions, + activeSessionStatus, + tokenTelemetry, + activeEditor, + onSendPrompt, + onInterrupt, + onSelectSkills, +}: ComposerProps) { + const [value, setValue] = useState(""); + const [history, setHistory] = useState([]); + const [historyIdx, setHistoryIdx] = useState(-1); + const [draftBeforeHistory, setDraftBeforeHistory] = useState(""); + const textareaRef = useRef(null); + console.log("askPermissions:", askPermissions); + console.log("activeSessionStatus:", activeSessionStatus); + + // Auto-resize textarea + const autoResize = useCallback(() => { + const el = textareaRef.current; + if (!el) return; + el.style.height = "auto"; + const lineHeight = 18; + const minHeight = lineHeight * 3 + 20; + const maxHeight = lineHeight * 10 + 20; + const next = Math.min(Math.max(el.scrollHeight, minHeight), maxHeight); + el.style.height = `${next}px`; + el.style.overflowY = el.scrollHeight > maxHeight ? "auto" : "hidden"; + }, []); + + useEffect(() => { + autoResize(); + }, [value, autoResize]); + + const handleSend = useCallback(() => { + const trimmed = value.trim(); + const images: string[] = []; + if ((!trimmed && images.length === 0) || loading) return; + + const reply = pendingPermissionReply as { permissions?: unknown[]; alwaysAllows?: string[] } | null; + setHistory((prev) => [...prev, trimmed]); + setValue(""); + setHistoryIdx(-1); + + onSendPrompt(trimmed, selectedSkills, images, reply || undefined); + onSelectSkills([]); + }, [value, loading, pendingPermissionReply, selectedSkills, onSendPrompt, onSelectSkills]); + + const handleKeyDown = useCallback( + (e: React.KeyboardEvent) => { + // if (e.isComposing) return; + + if (e.key === "Enter" && !e.shiftKey) { + e.preventDefault(); + handleSend(); + } else if (e.key === "ArrowUp" && !e.shiftKey && !e.altKey && !e.ctrlKey && !e.metaKey) { + const el = textareaRef.current; + if (!el) return; + if (el.selectionStart === 0 && el.selectionEnd === 0 && history.length > 0) { + e.preventDefault(); + if (historyIdx === -1) { + setDraftBeforeHistory(value); + setHistoryIdx(history.length - 1); + setValue(history[history.length - 1]); + } else if (historyIdx > 0) { + setHistoryIdx(historyIdx - 1); + setValue(history[historyIdx - 1]); + } + } + } else if (e.key === "ArrowDown" && !e.shiftKey && !e.altKey && !e.ctrlKey && !e.metaKey) { + const el = textareaRef.current; + if (!el) return; + if (historyIdx !== -1 && el.selectionStart === el.value.length && el.selectionEnd === el.value.length) { + e.preventDefault(); + if (historyIdx < history.length - 1) { + setHistoryIdx(historyIdx + 1); + setValue(history[historyIdx + 1]); + } else { + setHistoryIdx(-1); + setValue(draftBeforeHistory); + } + } + } + }, + [handleSend, history, historyIdx, value, draftBeforeHistory] + ); + + const isProcessing = loading; + const hasContent = value.trim().length > 0; + + return ( + + + + { + setValue(e.target.value); + if (historyIdx !== -1) { + setHistoryIdx(-1); + } + }} + onKeyDown={handleKeyDown} + className="text-[12px] max-h-50" + placeholder="Write a prompt..." + /> + + { + const idx = selectedSkills.findIndex((s) => s.name === skill.name); + if (idx >= 0) { + onSelectSkills(selectedSkills.filter((s) => s.name !== skill.name)); + } else { + onSelectSkills([...selectedSkills, skill]); + } + }} + /> + + + + {activeEditor && ( + + + + + {activeEditor.fileName.split("/").pop()} + + + +
{activeEditor.fileName.split("/").pop()}
+
{activeEditor.fileName}
+
+ {activeEditor.languageId} + {activeEditor.lineCount} lines +
+
+
+ )} + {isProcessing ? ( + + + + ) : ( + + + + )} +
+ onSelectSkills(selectedSkills.filter((s) => s.name !== name))} + /> +
+
+
+ ); +} diff --git a/packages/vscode-ide-companion/src/webview/components/ContextMeter.tsx b/packages/vscode-ide-companion/src/webview/components/ContextMeter.tsx new file mode 100644 index 00000000..5167398a --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/ContextMeter.tsx @@ -0,0 +1,76 @@ +import type { TokenTelemetry } from "@/webview/types"; +import { HoverCard, HoverCardContent, HoverCardTrigger } from "./ui/hover-card"; +import { InputGroupButton } from "./ui/input-group"; +import { ProgressRing } from "./ui/progress-ring"; +import { Field, FieldLabel } from "./ui/field"; +import { Progress } from "./ui/progress"; +import { flattenUsageFields, formatUsageFieldLabel, getTokenUsagePercent, toTitleCase } from "@/webview/utils"; +import { Separator } from "@/webview/components/ui/separator"; + +interface ContextMeterProps { + tokenTelemetry?: TokenTelemetry; +} + +function formatTokenCount(value: unknown): string { + const n = Number(value || 0); + if (!Number.isFinite(n)) return "0"; + return n.toLocaleString(); +} + +export default function ContextMeter({ tokenTelemetry }: ContextMeterProps) { + const activeTokens = tokenTelemetry?.activeTokens || 0; + const percent = getTokenUsagePercent(tokenTelemetry); + const usedRows = flattenUsageFields(tokenTelemetry?.usage); + + return ( + + + + + + + +
Context Window
+ + + {percent}% + used + + + +
+
+ Model + {tokenTelemetry?.model || "unknown"} +
+
+ Thinking + {tokenTelemetry?.thinkingEnabled ? "true" : "false"} +
+
+ Effort + {tokenTelemetry?.reasoningEffort || "max"} +
+
+ Active Tokens + {formatTokenCount(activeTokens)} +
+
+ {usedRows?.length > 0 && ( + <> + +
+
Session Usage
+ {(usedRows || []).map(([key, value]) => ( +
+ {toTitleCase(formatUsageFieldLabel(key))} + {formatTokenCount(value)} +
+ ))} +
+ + )} +
+
+ ); +} diff --git a/packages/vscode-ide-companion/src/webview/components/DiffPreview.tsx b/packages/vscode-ide-companion/src/webview/components/DiffPreview.tsx new file mode 100644 index 00000000..a39b6d98 --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/DiffPreview.tsx @@ -0,0 +1,70 @@ +import { Button } from "@/webview/components/ui/button"; + +interface ToolData { + ok: boolean; + name: string; + output: string; + metadata?: { + file_path?: string; + scope?: { start_line?: number }; + diff_preview?: string; + }; +} + +interface DiffPreviewProps { + toolData: ToolData; +} + +function formatDisplayPath(filePath: string): string { + if (!filePath) return ""; + return filePath; +} + +export default function DiffPreview({ toolData }: DiffPreviewProps) { + const meta = toolData.metadata; + if (!meta?.file_path) return null; + + const diffLines = (meta.diff_preview || "") + .split("\n") + .filter((l) => !l.startsWith("--- ") && !l.startsWith("+++ ") && !l.startsWith("@@ ")); + + return ( +
+ {toolData.output &&
{toolData.output.trim()}
} + +
+ File + +
+ + {diffLines.length > 0 && ( +
+
Changes
+
+ {diffLines.map((line, i) => { + if (!line) return null; + const cls = line.startsWith("+") + ? "bg-success/10 text-success" + : line.startsWith("-") + ? "bg-destructive/10 text-destructive" + : "text-muted-foreground"; + const prefix = line[0] === "+" || line[0] === "-" ? line[0] : " "; + return ( +
+ {prefix} + {line.slice(1)} +
+ ); + })} +
+
+ )} +
+ ); +} diff --git a/packages/vscode-ide-companion/src/webview/components/ErrorBoundary.test.tsx b/packages/vscode-ide-companion/src/webview/components/ErrorBoundary.test.tsx new file mode 100644 index 00000000..4771c915 --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/ErrorBoundary.test.tsx @@ -0,0 +1,164 @@ +/** + * Unit tests for ErrorBoundary component + * + * Tests cover: + * - Renders children when no error + * - Shows error UI when error occurs + * - Reset functionality + */ + +import React from "react"; +import { render, screen, fireEvent } from "@testing-library/react"; +import { describe, it, expect, vi } from "vitest"; +import { ErrorBoundary } from "./ErrorBoundary"; + +describe("ErrorBoundary", () => { + // Test component that throws + const ThrowError = ({ shouldThrow }: { shouldThrow: boolean }) => { + if (shouldThrow) { + throw new Error("Test error message"); + } + return
Content rendered successfully
; + }; + + it("renders children when there is no error", () => { + render( + +
Test Child
+
+ ); + + expect(screen.getByTestId("child")).toBeInTheDocument(); + expect(screen.getByText("Test Child")).toBeInTheDocument(); + }); + + it("displays error message when child throws", () => { + render( + + + + ); + + expect(screen.getByText("Something went wrong")).toBeInTheDocument(); + expect(screen.getByText("Test error message")).toBeInTheDocument(); + }); + + it("displays generic message when error has no message", () => { + // Error() creates error with empty string message by default + // `error?.message ?? '...'` uses `??` so empty string is NOT nullish + // An empty message will render as empty string + const NoMessageError = () => { + throw new Error(); // message = "" + }; + + render( + + + + ); + + expect(screen.getByText("Something went wrong")).toBeInTheDocument(); + // The rendered error message is empty string (not "An unexpected error occurred") + // because `error.message` is "" which is not null/undefined for `??` + expect(screen.queryByText("An unexpected error occurred")).not.toBeInTheDocument(); + }); + + it("has a reset/try again button", () => { + render( + + + + ); + + const resetButton = screen.getByRole("button", { name: /try again/i }); + expect(resetButton).toBeInTheDocument(); + }); + + it("resets error state when try again button is clicked", () => { + let shouldThrow = true; + + function TestComponent() { + if (shouldThrow) { + throw new Error("Test error"); + } + return
Recovered!
; + } + + render( + + + + ); + + // Error should be showing + expect(screen.getByText("Something went wrong")).toBeInTheDocument(); + + // Click reset + fireEvent.click(screen.getByRole("button", { name: /try again/i })); + + // The error boundary should have reset, but component still throws + // So we need to update shouldThrow state + shouldThrow = false; + + // Re-render with fixed state + render( + + + + ); + + // Now it should show recovered content + expect(screen.getByTestId("recovered")).toBeInTheDocument(); + }); + + it("logs error to console when componentDidCatch is called", () => { + const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {}); + + const FailingComponent = () => { + throw new Error("Caught by boundary"); + }; + + render( + + + + ); + + expect(consoleSpy).toHaveBeenCalledWith("[ErrorBoundary] Uncaught error:", expect.any(Error), expect.any(Object)); + + consoleSpy.mockRestore(); + }); + + it("renders different child components correctly", () => { + function SimpleComponent() { + return

Simple content

; + } + + render( + + + + ); + + expect(screen.getByText("Simple content")).toBeInTheDocument(); + }); + + it("handles nested errors", () => { + function DeeplyNestedError() { + return ( +
+ Before error + +
+ ); + } + + render( + + + + ); + + expect(screen.getByText("Something went wrong")).toBeInTheDocument(); + }); +}); diff --git a/packages/vscode-ide-companion/src/webview/components/ErrorBoundary.tsx b/packages/vscode-ide-companion/src/webview/components/ErrorBoundary.tsx new file mode 100644 index 00000000..4b1ea291 --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/ErrorBoundary.tsx @@ -0,0 +1,50 @@ +import { Component, type ErrorInfo, type ReactNode } from "react"; +import { Button } from "@/webview/components/ui/button"; + +interface Props { + children: ReactNode; +} + +interface State { + hasError: boolean; + error: Error | null; +} + +export class ErrorBoundary extends Component { + constructor(props: Props) { + super(props); + this.state = { hasError: false, error: null }; + } + + static getDerivedStateFromError(error: Error): State { + return { hasError: true, error }; + } + + componentDidCatch(error: Error, errorInfo: ErrorInfo) { + console.error("[ErrorBoundary] Uncaught error:", error, errorInfo); + } + + private handleReset = () => { + this.setState({ hasError: false, error: null }); + }; + + render() { + if (this.state.hasError) { + return ( +
+
+

Something went wrong

+

+ {this.state.error?.message ?? "An unexpected error occurred"} +

+
+ +
+ ); + } + + return this.props.children; + } +} diff --git a/packages/vscode-ide-companion/src/webview/components/Header.tsx b/packages/vscode-ide-companion/src/webview/components/Header.tsx new file mode 100644 index 00000000..3b496e2f --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/Header.tsx @@ -0,0 +1,108 @@ +import { useState, useCallback, useMemo } from "react"; +import { Button } from "@/webview/components/ui/button"; +import SessionDropdown from "@/webview/components/SessionList"; +import type { SessionSummary } from "@/webview/types"; +import { PanelRight, Plus, Settings } from "lucide-react"; +import { chatService } from "@/webview/services/chatService"; +import icon from "../../../assets/deepcoding_icon.png"; +import { + Drawer, + DrawerClose, + DrawerContent, + DrawerDescription, + DrawerFooter, + DrawerHeader, + DrawerTitle, + DrawerTrigger, +} from "@/webview/components/ui/drawer"; + +interface HeaderProps { + sessions: SessionSummary[]; + activeSessionId: string | null; + onSelectSession: (sessionId: string) => void; + onCreateNewSession: () => void; +} + +export default function Header({ sessions, activeSessionId, onSelectSession, onCreateNewSession }: HeaderProps) { + const [drawerOpen, setDrawerOpen] = useState(false); + + const handleCloseDrawer = useCallback(() => { + setDrawerOpen(false); + }, []); + + const handleSelect = useCallback( + (sessionId: string) => { + setDrawerOpen(false); + onSelectSession(sessionId); + }, + [onSelectSession] + ); + + const activeSessionSummary = useMemo(() => { + const session = sessions.find((s) => s.id === activeSessionId); + if (session) { + return session.summary; + } + return undefined; + }, [sessions, activeSessionId]); + + return ( +
+ + +
+ + + + + + + + + Sessions + Manage your agent sessions. + +
+ +
+ + + + + +
+
+
+
+ ); +} diff --git a/packages/vscode-ide-companion/src/webview/components/Messages.test.tsx b/packages/vscode-ide-companion/src/webview/components/Messages.test.tsx new file mode 100644 index 00000000..ad5be1ca --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/Messages.test.tsx @@ -0,0 +1,103 @@ +/** + * Unit tests for Messages component + * + * Tests cover: + * - Rendering different message types + * - Auto-scroll behavior + * - Message role-based rendering + */ + +import React from "react"; +import { render, screen } from "@testing-library/react"; +import { describe, it, expect, vi } from "vitest"; +import Messages from "./Messages"; +import type { SessionMessage } from "@/webview/types"; + +// Mock dependencies +vi.mock("@/webview/components/ui/scroll-area", () => ({ + ScrollArea: vi.fn(({ children }) =>
{children}
), + ScrollBar: vi.fn(() =>
), +})); + +vi.mock("@/webview/components/bubbles/UserBubble", () => ({ + default: vi.fn(({ content }) =>
{content}
), +})); + +vi.mock("@/webview/components/bubbles/AssistantBubble", () => ({ + default: vi.fn(({ content }) =>
{content}
), +})); + +vi.mock("@/webview/components/bubbles/ThinkingBubble", () => ({ + default: vi.fn(({ content }) =>
{content}
), +})); + +vi.mock("@/webview/components/bubbles/ToolBubble", () => ({ + default: vi.fn(({ content }) =>
{content}
), +})); + +vi.mock("@/webview/components/bubbles/SystemBubble", () => ({ + default: vi.fn(({ content }) =>
{content}
), +})); + +// Mock scrollIntoView +Element.prototype.scrollIntoView = vi.fn(); + +describe("Messages", () => { + const defaultProps = { + messages: [] as SessionMessage[], + loading: false, + llmStreamProgress: null, + processes: null, + }; + + it("renders empty messages", () => { + render(); + expect(screen.getByTestId("scroll-area")).toBeInTheDocument(); + }); + + it("renders user message", () => { + const messages: SessionMessage[] = [{ role: "user", content: "Hello" }]; + render(); + expect(screen.getByTestId("user-bubble")).toHaveTextContent("Hello"); + }); + + it("renders assistant message", () => { + const messages: SessionMessage[] = [{ role: "assistant", content: "Hi there!" }]; + render(); + expect(screen.getByTestId("assistant-bubble")).toHaveTextContent("Hi there!"); + }); + + it("renders thinking bubble when asThinking is true", () => { + const messages: SessionMessage[] = [{ role: "assistant", content: "Thinking...", meta: { asThinking: true } }]; + render(); + expect(screen.getByTestId("thinking-bubble")).toBeInTheDocument(); + }); + + it("renders tool message", () => { + const messages: SessionMessage[] = [{ role: "tool", content: "Tool output", meta: { name: "readFile" } }]; + render(); + expect(screen.getByTestId("tool-bubble")).toHaveTextContent("Tool output"); + }); + + it("renders system message", () => { + const messages: SessionMessage[] = [{ role: "system", content: "System info" }]; + render(); + expect(screen.getByTestId("system-bubble")).toBeInTheDocument(); + }); + + it("renders multiple messages of different types", () => { + const messages: SessionMessage[] = [ + { role: "user", content: "Question" }, + { role: "assistant", content: "Answer" }, + { role: "tool", content: "Result" }, + ]; + render(); + expect(screen.getAllByTestId(/bubble/)).toHaveLength(3); + }); + + it("renders message with html content", () => { + const messages: SessionMessage[] = [{ role: "assistant", content: "Text", html: "

HTML content

" }]; + render(); + expect(screen.getByTestId("assistant-bubble")).toHaveTextContent("Text"); + }); +}); diff --git a/packages/vscode-ide-companion/src/webview/components/Messages.tsx b/packages/vscode-ide-companion/src/webview/components/Messages.tsx new file mode 100644 index 00000000..47187c7c --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/Messages.tsx @@ -0,0 +1,67 @@ +import { useRef, useEffect } from "react"; +import { ScrollArea, ScrollBar } from "@/webview/components/ui/scroll-area"; +import UserBubble from "@/webview/components/bubbles/UserBubble"; +import AssistantBubble from "@/webview/components/bubbles/AssistantBubble"; +import ThinkingBubble from "@/webview/components/bubbles/ThinkingBubble"; +import ToolBubble from "@/webview/components/bubbles/ToolBubble"; +import SystemBubble from "@/webview/components/bubbles/SystemBubble"; +import type { SessionMessage } from "@/webview/types"; + +interface MessagesProps { + messages: SessionMessage[]; + loading: boolean; + llmStreamProgress: unknown; + processes: Record | null; +} + +export default function Messages({ messages, loading, llmStreamProgress, processes }: MessagesProps) { + const bottomRef = useRef(null); + + console.log("llmStreamProgress: ", llmStreamProgress); + console.log("processes: ", processes); + + useEffect(() => { + console.log("messages:", JSON.stringify(messages)); + bottomRef.current?.scrollIntoView({ behavior: "smooth" }); + }, [messages, loading]); + + return ( + +
+ {messages.map((msg, index) => { + const prevMsg = index > 0 ? messages[index - 1] : null; + const shouldConnect = prevMsg ? prevMsg.role !== "user" && msg.role !== "user" : false; + // console.log(`Rendering message ${index}:`, JSON.stringify(msg)); + switch (msg.role) { + case "user": + return ; + case "assistant": { + const meta = msg.meta as { asThinking?: boolean } | undefined; + if (meta?.asThinking) { + return ; + } + return ; + } + case "tool": + return ( + + ); + case "system": + return ( + + ); + default: + return null; + } + })} +
+
+ + + ); +} diff --git a/packages/vscode-ide-companion/src/webview/components/ModeToggle.tsx b/packages/vscode-ide-companion/src/webview/components/ModeToggle.tsx new file mode 100644 index 00000000..14a44bc7 --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/ModeToggle.tsx @@ -0,0 +1,31 @@ +import { Moon, Sun } from "lucide-react"; + +import { Button } from "@/webview/components/ui/button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/webview/components/ui/dropdown-menu"; +import { useTheme } from "@/webview/context/ThemeProvider"; + +export function ModeToggle({ variant = "ghost" }: { variant?: "ghost" | "outline" }) { + const { setTheme } = useTheme(); + + return ( + + + + + + setTheme("light")}>Light + setTheme("dark")}>Dark + setTheme("system")}>System + + + ); +} diff --git a/packages/vscode-ide-companion/src/webview/components/NetworkStatusIndicator.tsx b/packages/vscode-ide-companion/src/webview/components/NetworkStatusIndicator.tsx new file mode 100644 index 00000000..c09136fe --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/NetworkStatusIndicator.tsx @@ -0,0 +1,22 @@ +import { Wifi, WifiOff } from "lucide-react"; +import { cn } from "@/webview/lib/utils"; +import { useNetworkStatus } from "@/webview/hooks/useNetworkStatus"; + +export function NetworkStatusIndicator({ className }: { className?: string }) { + const { isOnline } = useNetworkStatus(); + + return ( +
+ {isOnline ? : } + {isOnline ? "Online" : "Offline"} +
+ ); +} diff --git a/packages/vscode-ide-companion/src/webview/components/PermissionPrompt.test.tsx b/packages/vscode-ide-companion/src/webview/components/PermissionPrompt.test.tsx new file mode 100644 index 00000000..ecba2604 --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/PermissionPrompt.test.tsx @@ -0,0 +1,186 @@ +/** + * Unit tests for PermissionPrompt component + * + * Tests cover: + * - normalizeRequests + * - describeScope + * - getRiskClass + * - commitDecision flow + * - isAskPermission / isDenied conditions + */ + +import React from "react"; +import { render, screen, fireEvent } from "@testing-library/react"; +import { describe, it, expect, vi, beforeEach } from "vitest"; +import PermissionPrompt, { type PermissionPromptProps } from "./PermissionPrompt"; +import type { AskPermissionRequest, AppAction } from "@/webview/types"; + +// Mock dependencies +vi.mock("@/webview/components/ui/button", () => ({ + Button: vi.fn(({ children, onClick, ...props }) => ( + + )), +})); + +vi.mock("@/webview/components/ui/hover-card", () => ({ + HoverCard: vi.fn(({ children }) =>
{children}
), + HoverCardContent: vi.fn(({ children }) =>
{children}
), + HoverCardTrigger: vi.fn(({ children }) =>
{children}
), +})); + +vi.mock("lucide-react", () => ({ + X: vi.fn(() => ), + ShieldAlert: vi.fn(() => ), +})); + +const mockDispatch = vi.fn<(action: AppAction) => void>(); +const mockOnDenyPermission = vi.fn<(sessionId: string) => void>(); +const mockOnSendPrompt = + vi.fn< + ( + prompt: string, + skills?: unknown[], + images?: string[], + options?: { permissions?: unknown[]; alwaysAllows?: string[] } + ) => void + >(); +const mockOnInterrupt = vi.fn<() => void>(); + +const defaultProps: PermissionPromptProps = { + askPermissions: [] as AskPermissionRequest[], + sessionStatus: "idle", + pendingPermissionReply: null, + permissionPromptState: null, + activeSessionId: "session-1", + dispatch: mockDispatch, + onDenyPermission: mockOnDenyPermission, + onSendPrompt: mockOnSendPrompt, + onInterrupt: mockOnInterrupt, +}; + +describe("PermissionPrompt", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("renders nothing when no permissions requested", () => { + const { container } = render(); + expect(container).toBeEmptyDOMElement(); + }); + + it("renders nothing when sessionStatus is not ask_permission", () => { + const props = { + ...defaultProps, + askPermissions: [{ toolCallId: "tool1", name: "read", command: "cat", description: "", scopes: ["read-in-cwd"] }], + sessionStatus: "running" as const, + }; + const { container } = render(); + expect(container).toBeEmptyDOMElement(); + }); + + it("renders permission prompt when ask_permission status", () => { + const props = { + ...defaultProps, + askPermissions: [{ toolCallId: "tool1", name: "read", command: "cat", description: "", scopes: ["read-in-cwd"] }], + sessionStatus: "ask_permission" as const, + }; + render(); + expect(screen.getByText("Permission required")).toBeInTheDocument(); + }); + + it("renders denied state when permission denied", () => { + const props = { + ...defaultProps, + askPermissions: [{ toolCallId: "tool1", name: "read", command: "cat", description: "", scopes: ["read-in-cwd"] }], + sessionStatus: "permission_denied" as const, + pendingPermissionReply: { allow: false, alwaysAllows: [] }, + }; + render(); + expect(screen.getByText(/denied/i)).toBeInTheDocument(); + }); + + it("calls onDenyPermission when No clicked", () => { + const props = { + ...defaultProps, + askPermissions: [{ toolCallId: "tool1", name: "read", command: "cat", description: "", scopes: ["read-in-cwd"] }], + sessionStatus: "ask_permission" as const, + }; + render(); + const noButton = screen.getByText("No"); + fireEvent.click(noButton); + expect(mockOnDenyPermission).toHaveBeenCalled(); + }); + + it("calls onSendPrompt when Yes clicked", () => { + const props = { + ...defaultProps, + askPermissions: [{ toolCallId: "tool1", name: "read", command: "cat", description: "", scopes: ["read-in-cwd"] }], + sessionStatus: "ask_permission" as const, + }; + render(); + const yesButton = screen.getByText("Yes"); + fireEvent.click(yesButton); + expect(mockOnSendPrompt).toHaveBeenCalledWith( + "/continue", + [], + [], + expect.objectContaining({ permissions: expect.any(Array) }) + ); + }); + + it("shows always allow button when canAlwaysAllow", () => { + const props: PermissionPromptProps = { + ...defaultProps, + askPermissions: [{ toolCallId: "tool1", name: "read", command: "cat", description: "", scopes: ["read-in-cwd"] }], + sessionStatus: "ask_permission", + permissionPromptState: { + requests: [], + prompts: [], + index: 0, + decisions: {}, + alwaysAllows: [], + submitting: false, + }, + }; + render(); + expect(screen.getByText(/always allow/i)).toBeInTheDocument(); + }); + + it("calls onInterrupt when cancel clicked", () => { + const props = { + ...defaultProps, + askPermissions: [{ toolCallId: "tool1", name: "read", command: "cat", description: "", scopes: ["read-in-cwd"] }], + sessionStatus: "ask_permission" as const, + }; + render(); + const cancelButton = screen.getByTitle("Interrupt"); + fireEvent.click(cancelButton); + expect(mockOnInterrupt).toHaveBeenCalled(); + }); + + it("renders risk class badge for scope", () => { + const props = { + ...defaultProps, + askPermissions: [{ toolCallId: "tool1", name: "read", command: "cat", description: "", scopes: ["read-in-cwd"] }], + sessionStatus: "ask_permission" as const, + }; + render(); + // Check for the risk class styling (bg-green-500 for read-in-cwd scope) + expect(document.body.innerHTML).toContain("bg-green-500/15"); + }); + + it("renders multiple permission requests with index", () => { + const props = { + ...defaultProps, + askPermissions: [ + { toolCallId: "tool1", name: "read", command: "cat", description: "", scopes: ["read-in-cwd"] }, + { toolCallId: "tool2", name: "write", command: "echo", description: "", scopes: ["write-in-cwd"] }, + ], + sessionStatus: "ask_permission" as const, + }; + render(); + expect(screen.getByText("1/2")).toBeInTheDocument(); + }); +}); diff --git a/packages/vscode-ide-companion/src/webview/components/PermissionPrompt.tsx b/packages/vscode-ide-companion/src/webview/components/PermissionPrompt.tsx new file mode 100644 index 00000000..9c7852d8 --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/PermissionPrompt.tsx @@ -0,0 +1,295 @@ +import { useMemo, useCallback, useState, useEffect } from "react"; +import { Button } from "@/webview/components/ui/button"; +import type { AppAction, AskPermissionRequest, PermissionPromptState, SkillInfo } from "@/webview/types"; +import { ShieldAlert, X } from "lucide-react"; + +export interface PermissionPromptProps { + askPermissions: AskPermissionRequest[]; + sessionStatus: string | null; + pendingPermissionReply: unknown; + permissionPromptState: PermissionPromptState | null; + activeSessionId: string | null; + dispatch: (action: AppAction) => void; + onDenyPermission: (sessionId: string) => void; + onSendPrompt: ( + prompt: string, + skills?: SkillInfo[], + images?: string[], + options?: { permissions?: unknown[]; alwaysAllows?: string[] } + ) => void; + onInterrupt: () => void; +} + +type PermissionScope = string; + +const VALID_SCOPES: PermissionScope[] = [ + "read-in-cwd", + "read-out-cwd", + "write-in-cwd", + "write-out-cwd", + "delete-in-cwd", + "delete-out-cwd", + "query-git-log", + "mutate-git-log", + "network", + "mcp", +]; + +function describeScope(scope: string): string { + switch (scope) { + case "read-in-cwd": + return "reads inside this workspace"; + case "read-out-cwd": + return "reads outside this workspace"; + case "write-in-cwd": + return "writes inside this workspace"; + case "write-out-cwd": + return "writes outside this workspace"; + case "delete-in-cwd": + return "deletes inside this workspace"; + case "delete-out-cwd": + return "deletes outside this workspace"; + case "query-git-log": + return "Git history queries"; + case "mutate-git-log": + return "Git history changes"; + case "network": + return "network access"; + case "mcp": + return "MCP tool access"; + default: + return "unknown access"; + } +} + +function getRiskClass(scope: string): string { + switch (scope) { + case "read-in-cwd": + case "query-git-log": + return "bg-green-500/15 text-green-700 dark:text-green-400"; + case "read-out-cwd": + case "write-in-cwd": + case "network": + case "mcp": + return "bg-yellow-500/15 text-yellow-700 dark:text-yellow-400"; + default: + return "bg-red-500/15 text-red-700 dark:text-red-400"; + } +} + +function normalizeRequests(requests: unknown[]): AskPermissionRequest[] { + return requests + .map((item) => { + if (!item || typeof item !== "object") return null; + const r = item as Record; + return { + toolCallId: String(r.toolCallId || ""), + name: String(r.name || "Tool"), + command: String(r.command || ""), + description: String(r.description || ""), + scopes: Array.isArray(r.scopes) ? r.scopes.filter((s) => typeof s === "string") : ["unknown"], + }; + }) + .filter(Boolean) as AskPermissionRequest[]; +} + +export default function PermissionPrompt({ + askPermissions, + sessionStatus, + pendingPermissionReply, + activeSessionId, + dispatch, + onDenyPermission, + onSendPrompt, + onInterrupt, +}: PermissionPromptProps) { + const normalized = useMemo(() => normalizeRequests(askPermissions), [askPermissions]); + const isAskPermission = sessionStatus === "ask_permission" && normalized.length > 0; + const isDenied = (pendingPermissionReply && sessionStatus === "permission_denied") as boolean; + + // Build prompts from requests + const prompts = useMemo(() => { + const result: Array<{ request: AskPermissionRequest; scope: string }> = []; + for (const req of normalized) { + const scopes = req.scopes.length > 0 ? req.scopes : ["unknown"]; + for (const scope of scopes) { + result.push({ request: req, scope }); + } + } + return result; + }, [normalized]); + + // Use internal state for decisions + const [localState, setLocalState] = useState<{ + index: number; + decisions: Record; + alwaysAllows: string[]; + submitting: boolean; + }>({ index: 0, decisions: {}, alwaysAllows: [], submitting: false }); + + // Reset when prompts change + useEffect(() => { + setLocalState({ index: 0, decisions: {}, alwaysAllows: [], submitting: false }); + }, [askPermissions]); + + const findNextIdx = useCallback( + (fromIdx: number, alwaysAllows: string[]) => { + let idx = fromIdx; + while (idx < prompts.length) { + const scope = prompts[idx].scope; + if (VALID_SCOPES.includes(scope) && alwaysAllows.includes(scope)) { + idx++; + continue; + } + return idx; + } + return prompts.length; + }, + [prompts] + ); + + const effectiveIndex = findNextIdx(localState.index, localState.alwaysAllows); + + const commitDecision = useCallback( + (kind: "allow" | "deny" | "always") => { + if (localState.submitting || effectiveIndex >= prompts.length) return; + + setLocalState((prev) => { + const prompt = prompts[effectiveIndex]; + const newDecisions = { ...prev.decisions }; + const newAlwaysAllows = [...prev.alwaysAllows]; + + if (kind === "always" && VALID_SCOPES.includes(prompt.scope)) { + if (!newAlwaysAllows.includes(prompt.scope)) { + newAlwaysAllows.push(prompt.scope); + } + if (newDecisions[prompt.request.toolCallId] !== "deny") { + newDecisions[prompt.request.toolCallId] = "allow"; + } + } else if (kind === "deny") { + newDecisions[prompt.request.toolCallId] = "deny"; + } else { + if (newDecisions[prompt.request.toolCallId] !== "deny") { + newDecisions[prompt.request.toolCallId] = "allow"; + } + } + + const nextIdx = effectiveIndex + 1; + const nextEffective = findNextIdx(nextIdx, newAlwaysAllows); + + if (nextEffective >= prompts.length) { + // Submit + const permissions = normalized.map((req) => ({ + toolCallId: req.toolCallId, + permission: newDecisions[req.toolCallId] === "deny" ? "deny" : "allow", + })); + const hasDeny = permissions.some((p) => p.permission === "deny"); + + if (hasDeny) { + dispatch({ + type: "SET_PENDING_PERMISSION_REPLY", + reply: { permissions, alwaysAllows: newAlwaysAllows }, + }); + onDenyPermission(activeSessionId || ""); + } else { + onSendPrompt("/continue", [], [], { + permissions, + alwaysAllows: newAlwaysAllows, + }); + } + + return { ...prev, index: nextIdx, decisions: newDecisions, alwaysAllows: newAlwaysAllows, submitting: true }; + } + + return { ...prev, index: nextIdx, decisions: newDecisions, alwaysAllows: newAlwaysAllows }; + }); + }, + [ + localState, + effectiveIndex, + prompts, + normalized, + findNextIdx, + dispatch, + onDenyPermission, + onSendPrompt, + activeSessionId, + ] + ); + + const handleCancel = useCallback(() => { + dispatch({ type: "SET_PENDING_PERMISSION_REPLY", reply: null }); + onInterrupt(); + setLocalState({ index: 0, decisions: {}, alwaysAllows: [], submitting: false }); + }, [dispatch, onInterrupt]); + + if (!isAskPermission && !isDenied) return null; + + if (isDenied) { + return ( +
+
+
+ + Permission denied +
+

Add a reply, then press Enter to continue with the denial.

+
+
+ ); + } + + const prompt = prompts[effectiveIndex]; + if (!prompt) return null; + + const canAlwaysAllow = VALID_SCOPES.includes(prompt.scope); + + return ( +
+
+
+
+ Permission required + + {effectiveIndex + 1}/{prompts.length} + +
+ +
+ +
{prompt.request.name}
+
{prompt.request.command || "(no command)"}
+ {prompt.request.description && ( +
{prompt.request.description}
+ )} + +
+ {describeScope(prompt.scope)} +
+ +
Do you want to proceed?
+ +
+ + {canAlwaysAllow && ( + + )} + +
+
+
+ ); +} diff --git a/packages/vscode-ide-companion/src/webview/components/PlanRenderer.tsx b/packages/vscode-ide-companion/src/webview/components/PlanRenderer.tsx new file mode 100644 index 00000000..4fc50255 --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/PlanRenderer.tsx @@ -0,0 +1,88 @@ +import type { JSX } from "react"; + +interface PlanRendererProps { + plan: string; +} + +function toInlineHtml(text: string): string { + return text + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/`([^`]+)`/g, "$1") + .replace(/\*\*([^*]+)\*\*/g, "$1") + .replace(/\*([^*]+)\*/g, "$1"); +} + +export default function PlanRenderer({ plan }: PlanRendererProps) { + const lines = String(plan || "").split(/\r?\n/); + + return ( +
+ {lines.map((raw, i) => { + const line = raw.trimEnd(); + if (!line.trim()) { + return
; + } + + // Heading + const headingMatch = line.match(/^(#{1,6})\s+(.+)$/); + if (headingMatch) { + const level = Math.min(6, headingMatch[1].length); + const Tag = `h${level}` as keyof JSX.IntrinsicElements; + return ( + + + + ); + } + + // Task item: - [ ] / - [x] / - [>] / - [!] + const taskMatch = line.match(/^(\s*)[-*]\s+\[([ xX!>])\]\s*(.*)$/); + if (taskMatch) { + const indent = Math.floor((taskMatch[1] || "").replace(/\t/g, " ").length / 2); + const statusRaw = taskMatch[2]; + let status: "todo" | "done" | "active" | "attention" = "todo"; + if (statusRaw === "x" || statusRaw === "X") status = "done"; + else if (statusRaw === ">") status = "active"; + else if (statusRaw === "!") status = "attention"; + + const label = status === "done" ? "✓" : status === "active" ? ">" : status === "attention" ? "!" : ""; + const colorClass = + status === "done" + ? "text-success" + : status === "active" + ? "text-[var(--vscode-focusBorder)]" + : status === "attention" + ? "text-warning" + : "text-muted-foreground"; + + return ( +
+ {label || " "} + +
+ ); + } + + // Bullet + const bulletMatch = line.match(/^(\s*)[-*]\s+(.+)$/); + if (bulletMatch) { + const indent = Math.floor((bulletMatch[1] || "").replace(/\t/g, " ").length / 2); + return ( +
+ + +
+ ); + } + + return ( +

+ +

+ ); + })} +
+ ); +} diff --git a/packages/vscode-ide-companion/src/webview/components/SessionList.test.tsx b/packages/vscode-ide-companion/src/webview/components/SessionList.test.tsx new file mode 100644 index 00000000..ea87fb15 --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/SessionList.test.tsx @@ -0,0 +1,164 @@ +/** + * Unit tests for SessionList component + * + * Tests cover: + * - Search functionality + * - Session grouping by date + * - Empty states + */ + +import React from "react"; +import { render, screen, fireEvent } from "@testing-library/react"; +import { describe, it, expect, vi, beforeEach } from "vitest"; +import SessionList from "./SessionList"; +import type { SessionSummary } from "@/webview/types"; + +// Mock dependencies +vi.mock("@/webview/components/ui/input", () => ({ + Input: vi.fn(({ value, onChange, ...props }) => ( + + )), +})); + +vi.mock("@/webview/components/ui/scroll-area", () => ({ + ScrollArea: vi.fn(({ children }) => ( +
+ {children} +
+
+ )), + ScrollBar: vi.fn(() =>
), +})); + +vi.mock("@/webview/components/ui/empty", () => ({ + Empty: vi.fn(({ children }) =>
{children}
), + EmptyHeader: vi.fn(({ children }) =>
{children}
), + EmptyTitle: vi.fn(({ children }) =>
{children}
), + EmptyDescription: vi.fn(({ children }) =>
{children}
), + EmptyMedia: vi.fn(({ children }) =>
{children}
), +})); + +vi.mock("@/webview/components/ui/item", () => ({ + Item: vi.fn(({ children }) =>
{children}
), + ItemContent: vi.fn(({ children }) =>
{children}
), + ItemGroup: vi.fn(({ children }) =>
{children}
), + ItemActions: vi.fn(({ children }) =>
{children}
), +})); + +describe("SessionList", () => { + const today = new Date(); + const yesterday = new Date(today); + yesterday.setDate(yesterday.getDate() - 1); + const lastWeek = new Date(today); + lastWeek.setDate(lastWeek.getDate() - 5); + const older = new Date(today); + older.setDate(older.getDate() - 30); + + const createMockSession = (id: string, updateTime: Date): SessionSummary => ({ + id, + summary: `Session ${id}`, + createTime: updateTime.toISOString(), + updateTime: updateTime.toISOString(), + status: "idle", + }); + + const mockSessions: SessionSummary[] = [ + createMockSession("1", today), + createMockSession("2", yesterday), + createMockSession("3", lastWeek), + createMockSession("4", older), + ]; + + const defaultProps = { + sessions: mockSessions, + activeSessionId: null, + onSelect: vi.fn(), + onClose: vi.fn(), + }; + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("renders search input", () => { + render(); + expect(screen.getByTestId("search-input")).toBeInTheDocument(); + }); + + it("renders scroll area", () => { + render(); + expect(screen.getByTestId("scroll-area")).toBeInTheDocument(); + }); + + it("shows empty state when no sessions", () => { + render(); + expect(screen.getByTestId("empty")).toBeInTheDocument(); + expect(screen.getByText("No sessions yet")).toBeInTheDocument(); + }); + + it("shows 'No sessions found' when search yields no results", () => { + render(); + + const searchInput = screen.getByTestId("search-input"); + fireEvent.change(searchInput, { target: { value: "nonexistent" } }); + + expect(screen.getByText("No sessions found")).toBeInTheDocument(); + }); + + it("filters sessions by search query", () => { + const sessionsWithNames: SessionSummary[] = [ + { + id: "1", + summary: "Project Alpha", + createTime: today.toISOString(), + updateTime: today.toISOString(), + status: "idle", + }, + { + id: "2", + summary: "Project Beta", + createTime: today.toISOString(), + updateTime: today.toISOString(), + status: "idle", + }, + ]; + + render(); + + const searchInput = screen.getByTestId("search-input"); + fireEvent.change(searchInput, { target: { value: "Alpha" } }); + + // Should only show "Project Alpha" + expect(screen.queryByText("Project Beta")).not.toBeInTheDocument(); + }); + + it("search is case insensitive", () => { + const sessionsWithNames: SessionSummary[] = [ + { + id: "1", + summary: "PROJECT ALPHA", + createTime: today.toISOString(), + updateTime: today.toISOString(), + status: "idle", + }, + ]; + + render(); + + const searchInput = screen.getByTestId("search-input"); + fireEvent.change(searchInput, { target: { value: "alpha" } }); + + expect(screen.getByText("PROJECT ALPHA")).toBeInTheDocument(); + }); + + it("handles empty summary as 'Untitled'", () => { + const sessionsWithEmptySummary: SessionSummary[] = [ + { id: "1", summary: "", createTime: today.toISOString(), updateTime: today.toISOString(), status: "idle" }, + ]; + + render(); + + // Should display "Untitled" instead of empty string + expect(screen.getByText("Untitled")).toBeInTheDocument(); + }); +}); diff --git a/packages/vscode-ide-companion/src/webview/components/SessionList.tsx b/packages/vscode-ide-companion/src/webview/components/SessionList.tsx new file mode 100644 index 00000000..5edcde0a --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/SessionList.tsx @@ -0,0 +1,136 @@ +import { useState, useMemo } from "react"; +import { Input } from "@/webview/components/ui/input"; +import { ScrollArea, ScrollBar } from "@/webview/components/ui/scroll-area"; +import type { SessionSummary } from "@/webview/types"; +import { MessageCircle, Search } from "lucide-react"; +import { Empty, EmptyDescription, EmptyMedia, EmptyHeader, EmptyTitle } from "@/webview/components/ui/empty"; +import { cn } from "@/webview/lib/utils"; +import { Item, ItemActions, ItemContent, ItemGroup } from "./ui/item"; + +interface SessionDropdownProps { + sessions: SessionSummary[]; + activeSessionId: string | null; + onSelect: (sessionId: string) => void; + onClose: () => void; +} + +function formatTime(dateString: string): string { + const date = new Date(dateString); + const now = new Date(); + const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); + const sessionDay = new Date(date.getFullYear(), date.getMonth(), date.getDate()); + const diffDays = Math.floor((today.getTime() - sessionDay.getTime()) / (1000 * 60 * 60 * 24)); + + if (diffDays === 0) { + return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }); + } + return `${date.getMonth() + 1}/${date.getDate()}`; +} + +export default function SessionList({ sessions, activeSessionId, onSelect, onClose }: SessionDropdownProps) { + const [query, setQuery] = useState(""); + + const filtered = useMemo(() => { + const q = query.toLowerCase().trim(); + return sessions + .filter((s) => (s.summary || "Untitled").toLowerCase().includes(q)) + .sort((a, b) => new Date(b.updateTime).getTime() - new Date(a.updateTime).getTime()); + }, [sessions, query]); + + const grouped = useMemo(() => { + const groups: Record = { Today: [], Yesterday: [], "Past Week": [], Older: [] }; + const now = new Date(); + const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); + const yesterday = new Date(today); + yesterday.setDate(yesterday.getDate() - 1); + const lastWeek = new Date(today); + lastWeek.setDate(lastWeek.getDate() - 7); + + for (const s of filtered) { + const sessionDay = new Date( + new Date(s.updateTime).getFullYear(), + new Date(s.updateTime).getMonth(), + new Date(s.updateTime).getDate() + ); + if (sessionDay.getTime() === today.getTime()) { + groups["Today"].push(s); + } else if (sessionDay.getTime() === yesterday.getTime()) { + groups["Yesterday"].push(s); + } else if (sessionDay.getTime() > lastWeek.getTime()) { + groups["Past Week"].push(s); + } else { + groups["Older"].push(s); + } + } + return groups; + }, [filtered]); + + const totalCount = + grouped["Today"].length + grouped["Yesterday"].length + grouped["Past Week"].length + grouped["Older"].length; + + return ( +
+
+
+ + setQuery(e.target.value)} + autoFocus + /> +
+
+ +
+ {totalCount === 0 ? ( + + + + + + {query ? "No sessions found" : "No sessions yet"} + + You're all caught up. New notifications will appear here. + + + + ) : ( + Object.entries(grouped).map(([group, items]) => + items.length > 0 ? ( + +
+ {group} +
+ {items.map((s) => ( + { + onSelect(s.id); + onClose(); + }} + > + {s.summary || "Untitled"} + + {formatTime(s.updateTime)} + + + ))} +
+ ) : null + ) + )} +
+ +
+
+ ); +} diff --git a/packages/vscode-ide-companion/src/webview/components/SkillsPanel.tsx b/packages/vscode-ide-companion/src/webview/components/SkillsPanel.tsx new file mode 100644 index 00000000..38005156 --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/SkillsPanel.tsx @@ -0,0 +1,65 @@ +import { useState } from "react"; +import type { SkillInfo } from "@/webview/types"; +import { InputGroupButton } from "@/webview/components/ui/input-group"; +import { + Command, + CommandDialog, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, +} from "@/webview/components/ui/command"; +import { GraduationCap } from "lucide-react"; + +interface SkillsPanelProps { + availableSkills: SkillInfo[]; + selectedSkills: SkillInfo[]; + onToggle: (skill: SkillInfo) => void; +} + +export default function SkillsPanel({ availableSkills, selectedSkills, onToggle }: SkillsPanelProps) { + const [open, setOpen] = useState(false); + + if (availableSkills.length === 0) { + return ( + + + Skill + + ); + } + + return ( + <> + setOpen(true)}> + + Skill + + + + + + No results found. + + {availableSkills.map((skill) => { + const selected = selectedSkills.some((s) => s.name === skill.name); + return ( + onToggle(skill)} + title={skill.path} + > + {skill.name} + {skill.path} + + ); + })} + + + + + + ); +} diff --git a/packages/vscode-ide-companion/src/webview/components/SkillsTags.tsx b/packages/vscode-ide-companion/src/webview/components/SkillsTags.tsx new file mode 100644 index 00000000..cc914ff9 --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/SkillsTags.tsx @@ -0,0 +1,31 @@ +import { Badge } from "@/webview/components/ui/badge"; +import type { SkillInfo } from "@/webview/types"; +import { X } from "lucide-react"; +import { InputGroupAddon } from "./ui/input-group"; +import { Button } from "./ui/button"; + +interface SkillsTagsProps { + selectedSkills: SkillInfo[]; + onRemove: (name: string) => void; +} + +export default function SkillsTags({ selectedSkills, onRemove }: SkillsTagsProps) { + if (selectedSkills.length === 0) return null; + + return ( + + {selectedSkills.map((skill) => ( + + {skill.name} + + + ))} + + ); +} diff --git a/packages/vscode-ide-companion/src/webview/components/ThinkingLiveBubble.tsx b/packages/vscode-ide-companion/src/webview/components/ThinkingLiveBubble.tsx new file mode 100644 index 00000000..d7187bea --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/ThinkingLiveBubble.tsx @@ -0,0 +1,63 @@ +import { useEffect, useState, useRef } from "react"; +import BubbleDot from "@/webview/components/bubbles/BubbleDot"; +import { Spinner } from "@/webview/components/ui/spinner"; +import type { LlmStreamProgressData } from "@/webview/types"; + +interface ThinkingLiveBubbleProps { + llmStreamProgress: LlmStreamProgressData | null; + processes: Record | null; + shouldConnect?: boolean; +} + +function formatElapsed(startTime: string): string { + const elapsed = Math.floor((Date.now() - new Date(startTime).getTime()) / 1000); + const m = Math.floor(elapsed / 60); + const s = elapsed % 60; + return m > 0 ? `${m}m${s}s` : `${s}s`; +} + +function getStatusText( + progress: LlmStreamProgressData | null, + processes: Record | null +): string { + if (processes && Object.keys(processes).length > 0) { + const first = Object.values(processes)[0]; + return `(${formatElapsed(first.startTime)}) ${first.command}`; + } + if (progress?.startedAt) { + const elapsed = Math.max(0, Math.floor((Date.now() - new Date(progress.startedAt).getTime()) / 1000)); + const tokens = progress.formattedTokens || "0"; + if (elapsed >= 3) return `(${elapsed}s) · ↓ ${tokens} tokens`; + } + return "Processing..."; +} + +export default function ThinkingLiveBubble({ + llmStreamProgress, + processes, + shouldConnect = false, +}: ThinkingLiveBubbleProps) { + const [statusText, setStatusText] = useState(() => getStatusText(llmStreamProgress, processes)); + const intervalRef = useRef | null>(null); + + useEffect(() => { + setStatusText(getStatusText(llmStreamProgress, processes)); + intervalRef.current = setInterval(() => { + setStatusText(getStatusText(llmStreamProgress, processes)); + }, 1000); + return () => { + if (intervalRef.current) clearInterval(intervalRef.current); + }; + }, [llmStreamProgress, processes]); + + return ( +
+ +
+ + Thinking + {statusText} +
+
+ ); +} diff --git a/packages/vscode-ide-companion/src/webview/components/bubbles/AssistantBubble.tsx b/packages/vscode-ide-companion/src/webview/components/bubbles/AssistantBubble.tsx new file mode 100644 index 00000000..df68618f --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/bubbles/AssistantBubble.tsx @@ -0,0 +1,56 @@ +import { useState, useCallback } from "react"; +import BubbleDot from "@/webview/components/bubbles/BubbleDot"; +import { Button } from "@/webview/components/ui/button"; +import Markdown from "@/webview/components/markdown"; +import { Check, Copy } from "lucide-react"; +import { Tooltip, TooltipContent, TooltipTrigger } from "@/webview/components/ui/tooltip"; + +interface AssistantBubbleProps { + content?: string; + shouldConnect?: boolean; +} + +/** + * AssistantBubble component + * @param param0 + * @param param0.content + * @param param0.shouldConnect + * @constructor + */ +export default function AssistantBubble({ content, shouldConnect = false }: AssistantBubbleProps) { + const [copied, setCopied] = useState(false); + + const handleCopy = useCallback(() => { + const text = content || ""; + navigator.clipboard.writeText(text).catch(() => {}); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }, [content]); + + return ( +
+ +
+ {content} +
+ + + + + +

Copy

+
+
+
+
+
+ ); +} diff --git a/packages/vscode-ide-companion/src/webview/components/bubbles/BubbleDot.tsx b/packages/vscode-ide-companion/src/webview/components/bubbles/BubbleDot.tsx new file mode 100644 index 00000000..bbda31cb --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/bubbles/BubbleDot.tsx @@ -0,0 +1,30 @@ +import { cn } from "@/webview/lib/utils"; + +interface BubbleDotProps { + variant?: "default" | "success" | "error"; + connectToPrev?: boolean; + className?: string; +} + +/** + * BubbleDot component + * @param param0 + * @param param0.variant + * @param param0.connectToPrev + * @param param0.className + * @constructor + */ +export default function BubbleDot({ variant = "default", connectToPrev = false, className }: BubbleDotProps) { + return ( + + ); +} diff --git a/packages/vscode-ide-companion/src/webview/components/bubbles/SystemBubble.tsx b/packages/vscode-ide-companion/src/webview/components/bubbles/SystemBubble.tsx new file mode 100644 index 00000000..bade64e5 --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/bubbles/SystemBubble.tsx @@ -0,0 +1,36 @@ +import { useState } from "react"; +import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/webview/components/ui/collapsible"; +import BubbleDot from "@/webview/components/bubbles/BubbleDot"; +import { ChevronDown } from "lucide-react"; +import { Button } from "../ui/button"; + +interface SystemBubbleProps { + content: string; + meta?: Record; + shouldConnect?: boolean; +} + +export default function SystemBubble({ content, meta, shouldConnect = false }: SystemBubbleProps) { + const [open, setOpen] = useState(false); + const skillName = (meta?.skill as { name?: string } | undefined)?.name || "Unknown Skill"; + const skillDescription = (meta?.skill as { description?: string } | undefined)?.description || content; + + return ( + + +
+
+ + + + +
{skillDescription}
+
+
+
+ ); +} diff --git a/packages/vscode-ide-companion/src/webview/components/bubbles/ThinkingBubble.tsx b/packages/vscode-ide-companion/src/webview/components/bubbles/ThinkingBubble.tsx new file mode 100644 index 00000000..c3b5c7dd --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/bubbles/ThinkingBubble.tsx @@ -0,0 +1,35 @@ +import { useState } from "react"; +import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/webview/components/ui/collapsible"; +import BubbleDot from "@/webview/components/bubbles/BubbleDot"; +import { ChevronDown } from "lucide-react"; +import { Button } from "@/webview/components/ui/button"; +import Markdown from "@/webview/components/markdown"; + +interface ThinkingBubbleProps { + content: string; + shouldConnect?: boolean; +} + +export default function ThinkingBubble({ content, shouldConnect = false }: ThinkingBubbleProps) { + const [open, setOpen] = useState(true); + + return ( + + +
+
+ + + + +
+ {content} +
+
+
+
+ ); +} diff --git a/packages/vscode-ide-companion/src/webview/components/bubbles/ToolBubble.tsx b/packages/vscode-ide-companion/src/webview/components/bubbles/ToolBubble.tsx new file mode 100644 index 00000000..82def26b --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/bubbles/ToolBubble.tsx @@ -0,0 +1,94 @@ +import { useState } from "react"; +import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/webview/components/ui/collapsible"; +import BubbleDot from "@/webview/components/bubbles/BubbleDot"; +import AskUserQuestion from "@/webview/components/AskUserQuestion"; +import PlanRenderer from "@/webview/components/PlanRenderer"; +import DiffPreview from "@/webview/components/DiffPreview"; +import { ChevronDown } from "lucide-react"; +import { Button } from "@/webview/components/ui/button"; + +interface ToolBubbleProps { + content: string; + meta?: Record; + shouldConnect?: boolean; +} + +interface ToolData { + ok: boolean; + name: string; + output: string; + metadata?: Record; +} + +/** + * Tool Bubble + * @param param0 + * @param param0.content + * @param param0.meta + * @param param0.shouldConnect + * @constructor + */ +export default function ToolBubble({ content, meta, shouldConnect = false }: ToolBubbleProps) { + let toolData: ToolData = { ok: false, name: "unknown", output: "" }; + try { + toolData = JSON.parse(content || "{}"); + } catch { + // ignore parse errors + } + + const isOk = Boolean(toolData.ok); + const toolName = toolData.name || "unknown"; + const paramsMd = ((meta?.paramsMd as string) || "").trim(); + const resultMd = ((meta?.resultMd as string) || "").trim(); + const isAskUserQuestion = toolData.metadata?.kind === "ask_user_question"; + + const [open, setOpen] = useState(isAskUserQuestion); + + // Special rendering for AskUserQuestion + if (isAskUserQuestion) { + return ( +
+ +
+
{toolName}
+ +
+
+ ); + } + + return ( + + +
+
+ + + + +
+ {/* Plan renderer */} + {toolName.toLowerCase() === "updateplan" && toolData.ok && toolData.metadata?.plan ? ( + + ) : /* Write/Edit with diff preview */ + (toolName.toLowerCase() === "edit" || toolName.toLowerCase() === "write") && + toolData.ok && + toolData.metadata ? ( + + ) : ( +
+                {resultMd || toolData.output || content}
+              
+ )} +
+
+
+
+ ); +} diff --git a/packages/vscode-ide-companion/src/webview/components/bubbles/UserBubble.tsx b/packages/vscode-ide-companion/src/webview/components/bubbles/UserBubble.tsx new file mode 100644 index 00000000..e01fc55e --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/bubbles/UserBubble.tsx @@ -0,0 +1,52 @@ +import { Check, Copy, PenLine } from "lucide-react"; +import { Button } from "../ui/button"; +import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip"; +import { useCallback, useState } from "react"; + +interface UserBubbleProps { + content: string; +} + +export default function UserBubble({ content }: UserBubbleProps) { + const [copied, setCopied] = useState(false); + + const handleCopy = useCallback(() => { + const text = content || ""; + navigator.clipboard.writeText(text).catch(() => {}); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }, [content]); + return ( +
+
{content}
+
+ + + + + +

Copy

+
+
+ + + + + +

Edit

+
+
+
+
+ ); +} diff --git a/packages/vscode-ide-companion/src/webview/components/markdown/index.css b/packages/vscode-ide-companion/src/webview/components/markdown/index.css new file mode 100644 index 00000000..6c823ad0 --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/markdown/index.css @@ -0,0 +1,223 @@ +.markdown-content { + /* Base styles for markdown content */ + line-height: 1.6; + color: var(--foreground); +} + +.markdown-content h1, +.markdown-content h2, +.markdown-content h3, +.markdown-content h4, +.markdown-content h5, +.markdown-content h6 { + margin-top: 1.5em; + margin-bottom: 0.5em; + font-weight: 600; +} + +.markdown-content h1 { + font-size: 1.75em; + border-bottom: 1px solid var(--border); + padding-bottom: 0.3em; +} + +.markdown-content h2 { + font-size: 1.5em; + border-bottom: 1px solid var(--border); + padding-bottom: 0.3em; +} + +.markdown-content h3 { + font-size: 1.25em; +} + +.markdown-content h4 { + font-size: 1.1em; +} + +.markdown-content h5, +.markdown-content h6 { + font-size: 1em; +} + +.markdown-content p { + margin-top: 0; +} + +.markdown-content ul, +.markdown-content ol { + margin-top: 1em; + margin-bottom: 1em; + padding-left: 2em; +} + +/* Ensure list markers are visible even with global CSS resets */ +.markdown-content ul { + list-style-type: disc; + list-style-position: outside; +} + +.markdown-content ol { + list-style-type: decimal; + list-style-position: outside; +} + +/* Nested list styles */ +.markdown-content ul ul { + list-style-type: circle; +} + +.markdown-content ul ul ul { + list-style-type: square; +} + +.markdown-content ol ol { + list-style-type: lower-alpha; +} + +.markdown-content ol ol ol { + list-style-type: lower-roman; +} + +/* Style the marker explicitly so themes don't hide it */ +.markdown-content li::marker { + color: var(--muted-foreground); +} + +.markdown-content li { + margin-bottom: 0.25em; +} + +.markdown-content li > p { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +.markdown-content blockquote { + margin: 0 0 1em; + padding: 0 1em; + border-left: 0.25em solid var(--border); + color: var(--muted-foreground); +} + +.markdown-content a { + color: var(--primary, #007acc); + text-decoration: none; +} + +.markdown-content a:hover { + color: var(--primary, #005a9e); + text-decoration: underline; +} + +.markdown-content code { + font-family: var( + --app-monospace-font-family, + 'SF Mono', + Monaco, + 'Cascadia Code', + 'Roboto Mono', + Consolas, + 'Courier New', + monospace + ); + font-size: 0.9em; + background-color: var(--muted, rgba(0, 0, 0, 0.05)); + border: 1px solid var(--border); + border-radius: var(--radius-sm, 4px); + padding: 0.2em 0.4em; + white-space: pre-wrap; /* Support automatic line wrapping */ + word-break: break-word; /* Break words when necessary */ +} + +.markdown-content pre { + margin: 1em 0; + padding: 1em; + overflow-x: auto; + background-color: var(--muted, rgba(0, 0, 0, 0.05)); + border: 1px solid var(--border); + border-radius: var(--radius-sm, 4px); + font-family: var( + --app-monospace-font-family, + 'SF Mono', + Monaco, + 'Cascadia Code', + 'Roboto Mono', + Consolas, + 'Courier New', + monospace + ); + font-size: 0.9em; + line-height: 1.5; +} + +.markdown-content pre code { + background: none; + border: none; + padding: 0; + white-space: pre-wrap; /* Support automatic line wrapping */ + word-break: break-word; /* Break words when necessary */ +} + +.markdown-content .file-path-link { + background: transparent; + border: none; + padding: 0; + font-family: var( + --app-monospace-font-family, + 'SF Mono', + Monaco, + 'Cascadia Code', + 'Roboto Mono', + Consolas, + 'Courier New', + monospace + ); + font-size: 0.95em; + color: inherit; + text-decoration: none; + cursor: pointer; +} + +.markdown-content hr { + border: none; + border-top: 1px solid var(--border); + margin: 1.5em 0; +} + +.markdown-content img { + max-width: 100%; + height: auto; +} + +.markdown-content table { + width: 100%; + margin: 1em 0; + border: 1px solid var(--border); + border-radius: var(--radius-sm, 4px); + overflow: hidden; + border-collapse: separate; + border-spacing: 0; +} + +.markdown-content th, +.markdown-content td { + padding: 0.5em 1em; + border: 1px solid var(--border); + text-align: left; + border-top: none; + border-left: none; +} + +.markdown-content th { + background-color: var(--muted); + font-weight: 600; +} + +.markdown-content th:last-child, .markdown-content td:last-child { + border-right: none; +} + +.markdown-content table tbody tr:last-child td { + border-bottom: none; +} diff --git a/packages/vscode-ide-companion/src/webview/components/markdown/index.tsx b/packages/vscode-ide-companion/src/webview/components/markdown/index.tsx new file mode 100644 index 00000000..9581b2a8 --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/markdown/index.tsx @@ -0,0 +1,381 @@ +import type { FC } from "react"; +import React from "react"; +import { useMemo, useCallback } from "react"; +import MarkdownIt from "markdown-it"; +import type { Options as MarkdownItOptions } from "markdown-it"; +import "./index.css"; + +export interface MarkdownProps { + children?: string; + onFileClick?: (filePath: string) => void; + /** When false, do not convert file paths into clickable links. Default: true */ + enableFileLinks?: boolean; +} + +/** + * Regular expressions for parsing content + */ +// Match absolute file paths like: /path/to/file.ts or C:\path\to\file.ts +const FILE_PATH_REGEX = + /(?:[a-zA-Z]:)?[/\\](?:[\w\-. ]+[/\\])+[\w\-. ]+\.(tsx?|jsx?|css|scss|json|md|py|java|go|rs|c|cpp|h|hpp|sh|yaml|yml|toml|xml|html|vue|svelte)/gi; +// Match file paths with optional line numbers like: /path/to/file.ts#7-14 or C:\path\to\file.ts#7 +const FILE_PATH_WITH_LINES_REGEX = + /(?:[a-zA-Z]:)?[/\\](?:[\w\-. ]+[/\\])+[\w\-. ]+\.(tsx?|jsx?|css|scss|json|md|py|java|go|rs|c|cpp|h|hpp|sh|yaml|yml|toml|xml|html|vue|svelte)#(\d+)(?:-(\d+))?/gi; + +// Known file extensions for validation of explicit markdown links +const KNOWN_FILE_EXTENSIONS = + /\.(tsx?|jsx?|css|scss|json|md|py|java|go|rs|c|cpp|h|hpp|sh|ya?ml|toml|xml|html|vue|svelte)$/i; + +const safeDecodePath = (value: string): string => { + try { + return decodeURIComponent(value); + } catch { + return value; + } +}; + +const normalizeExplicitFileLink = (raw: string): string => { + const decoded = safeDecodePath(raw).replace(/\\/g, "/"); + + // file:// URIs (e.g. from vscode.Uri.file().toString()) encode special + // characters like # as %23 in the path component. After decoding the + // full URI we can strip the scheme and return the filesystem path + // directly — no fragment splitting needed, because any # in the + // decoded result is a literal filename character, not an anchor. + if (/^file:\/\//i.test(decoded)) { + let filePath = decoded.replace(/^file:\/\/\//i, ""); + // On Unix the path should start with / + if (!/^[a-zA-Z]:/.test(filePath) && !filePath.startsWith("/")) { + filePath = "/" + filePath; + } + return filePath; + } + + const hashIndex = decoded.indexOf("#"); + if (hashIndex < 0) { + return decoded; + } + + const base = decoded.slice(0, hashIndex); + const fragment = decoded.slice(hashIndex + 1); + const lineMatch = fragment.match(/^L?(\d+)(?:-\d+)?$/i); + if (lineMatch) { + return `${base}:${parseInt(lineMatch[1], 10)}`; + } + + return base; +}; + +/** + * Escape HTML characters for security + */ +const escapeHtml = (unsafe: string): string => + unsafe + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); + +/** + * Create a cached MarkdownIt instance + */ +const createMarkdownInstance = (): MarkdownIt => + new MarkdownIt({ + html: false, // Disable HTML for security + xhtmlOut: false, + breaks: true, + linkify: true, + typographer: true, + } as MarkdownItOptions); + +const Markdown: FC = ({ children = "", onFileClick, enableFileLinks }) => { + // Cache MarkdownIt instance + const md = useMemo(() => createMarkdownInstance(), []); + + /** + * Process file paths in HTML to make them clickable + */ + const processFilePaths = (html: string): string => { + // If DOM is not available, bail out to avoid breaking SSR + if (typeof document === "undefined") { + return html; + } + + // Build non-global variants to avoid .test() statefulness + const FILE_PATH_NO_G = new RegExp(FILE_PATH_REGEX.source, FILE_PATH_REGEX.flags.replace("g", "")); + const FILE_PATH_WITH_LINES_NO_G = new RegExp( + FILE_PATH_WITH_LINES_REGEX.source, + FILE_PATH_WITH_LINES_REGEX.flags.replace("g", "") + ); + // Match a bare file name like README.md (no leading slash) + const BARE_FILE_REGEX = + /[\w\-. ]+\.(tsx?|jsx?|css|scss|json|md|py|java|go|rs|c|cpp|h|hpp|sh|ya?ml|toml|xml|html|vue|svelte)/i; + + // Parse HTML into a DOM tree so we don't replace inside attributes + const container = document.createElement("div"); + container.innerHTML = html; + + const union = new RegExp( + `${FILE_PATH_WITH_LINES_REGEX.source}|${FILE_PATH_REGEX.source}|${BARE_FILE_REGEX.source}`, + "gi" + ); + + const normalizePathAndLine = (raw: string): { displayText: string; dataPath: string } => { + const displayText = raw; + let base = raw; + const hashIndex = raw.indexOf("#"); + if (hashIndex >= 0) { + const frag = raw.slice(hashIndex + 1); + const m = frag.match(/^L?(\d+)(?:-\d+)?$/i); + if (m) { + const line = parseInt(m[1], 10); + base = raw.slice(0, hashIndex); + return { displayText, dataPath: `${base}:${line}` }; + } + } + return { displayText, dataPath: base }; + }; + + const makeLink = (text: string) => { + const link = document.createElement("a"); + const { dataPath } = normalizePathAndLine(text); + link.className = "file-path-link"; + link.textContent = text; + link.setAttribute("href", "#"); + link.setAttribute("title", `Open ${text}`); + link.setAttribute("data-file-path", dataPath); + return link; + }; + + // Helper: identify dot-chained code refs (e.g. vscode.commands.register) + const isCodeReference = (str: string): boolean => { + if (BARE_FILE_REGEX.test(str)) { + return false; + } + if (/[/\\]/.test(str)) { + return false; + } + const codeRefPattern = /^[a-zA-Z_$][\w$]*(\.[a-zA-Z_$][\w$]*)+$/; + return codeRefPattern.test(str); + }; + + const upgradeAnchorIfFilePath = (a: HTMLAnchorElement) => { + const href = a.getAttribute("href") || ""; + const text = (a.textContent || "").trim(); + + const httpMatch = href.match(/^https?:\/\/(.+)$/i); + if (httpMatch) { + try { + const url = new URL(href); + const host = url.hostname || ""; + const pathname = url.pathname || ""; + const noPath = pathname === "" || pathname === "/"; + + if (noPath && BARE_FILE_REGEX.test(text) && host.toLowerCase() === text.toLowerCase()) { + const { dataPath } = normalizePathAndLine(text); + a.classList.add("file-path-link"); + a.setAttribute("href", "#"); + a.setAttribute("title", `Open ${text}`); + a.setAttribute("data-file-path", dataPath); + return; + } + + if (noPath && BARE_FILE_REGEX.test(host)) { + const { dataPath } = normalizePathAndLine(host); + a.classList.add("file-path-link"); + a.setAttribute("href", "#"); + a.setAttribute("title", `Open ${text || host}`); + a.setAttribute("data-file-path", dataPath); + return; + } + } catch { + // fall through + } + } + + if (/^(https?|mailto|ftp|data):/i.test(href)) { + return; + } + + const candidate = href || text; + + if (isCodeReference(candidate)) { + return; + } + + if (FILE_PATH_WITH_LINES_NO_G.test(candidate) || FILE_PATH_NO_G.test(candidate)) { + const { dataPath } = normalizePathAndLine(candidate); + a.classList.add("file-path-link"); + a.setAttribute("href", "#"); + a.setAttribute("title", `Open ${text || href}`); + a.setAttribute("data-file-path", dataPath); + return; + } + + if (BARE_FILE_REGEX.test(candidate)) { + const { dataPath } = normalizePathAndLine(candidate); + a.classList.add("file-path-link"); + a.setAttribute("href", "#"); + a.setAttribute("title", `Open ${text || href}`); + a.setAttribute("data-file-path", dataPath); + } + }; + + const walk = (node: Node) => { + if (node.nodeType === Node.ELEMENT_NODE) { + const el = node as HTMLElement; + if (el.tagName.toLowerCase() === "a") { + upgradeAnchorIfFilePath(el as HTMLAnchorElement); + return; + } + const tag = el.tagName.toLowerCase(); + if (tag === "code" || tag === "pre") { + return; + } + } + + for (let child = node.firstChild; child; ) { + const next = child.nextSibling; + if (child.nodeType === Node.TEXT_NODE) { + const text = child.nodeValue || ""; + union.lastIndex = 0; + const hasMatch = union.test(text); + union.lastIndex = 0; + if (hasMatch) { + const frag = document.createDocumentFragment(); + let lastIndex = 0; + let m: RegExpExecArray | null; + while ((m = union.exec(text))) { + const matchText = m[0]; + const idx = m.index; + + if (isCodeReference(matchText)) { + if (idx > lastIndex) { + frag.appendChild(document.createTextNode(text.slice(lastIndex, idx))); + } + frag.appendChild(document.createTextNode(matchText)); + lastIndex = idx + matchText.length; + continue; + } + + if (idx > lastIndex) { + frag.appendChild(document.createTextNode(text.slice(lastIndex, idx))); + } + frag.appendChild(makeLink(matchText)); + lastIndex = idx + matchText.length; + } + if (lastIndex < text.length) { + frag.appendChild(document.createTextNode(text.slice(lastIndex))); + } + node.replaceChild(frag, child); + } + } else if (child.nodeType === Node.ELEMENT_NODE) { + walk(child); + } + child = next; + } + }; + + walk(container); + return container.innerHTML; + }; + + /** + * Render markdown content to HTML (memoized) + */ + const renderedHtml = useMemo(() => { + try { + let html = md.render(children); + + if (enableFileLinks) { + html = processFilePaths(html); + } + + return html; + } catch (error) { + console.error("Error rendering markdown:", error); + return escapeHtml(children); + } + }, [children, enableFileLinks, md]); + + // Event delegation: intercept clicks on generated file-path links + const handleContainerClick = useCallback( + (e: React.MouseEvent) => { + const target = e.target as HTMLElement | null; + if (!target) { + return; + } + + // Check for file-path-link (created by processFilePaths when enableFileLinks=true) + const anchor = (target.closest && target.closest("a.file-path-link")) as HTMLAnchorElement | null; + if (anchor) { + const filePath = anchor.getAttribute("data-file-path"); + if (!filePath) { + return; + } + e.preventDefault(); + e.stopPropagation(); + onFileClick?.(filePath); + return; + } + + // Handle explicit markdown links (file:// URIs and normal file-path hrefs). + // file:// URIs come from trusted system-generated content (e.g. /export). + // Normal file-path links (absolute or with known extensions) are also + // supported so that intentional markdown links remain clickable even + // when enableFileLinks is false. + const anyAnchor = (target.closest && target.closest("a")) as HTMLAnchorElement | null; + if (!anyAnchor) { + return; + } + + const href = anyAnchor.getAttribute("href") || ""; + + // Handle file:// URI links (e.g. from /export success messages). + if (/^file:\/\//i.test(href) && onFileClick) { + const candidate = normalizeExplicitFileLink(href); + e.preventDefault(); + e.stopPropagation(); + onFileClick(candidate); + return; + } + + // Skip external links — let browser handle them normally + if (/^(https?|mailto|ftp|data):/i.test(href)) { + return; + } + + // Handle explicit markdown file-path links (e.g. [filename](/path/to/file)) + // even when enableFileLinks=false, so intentional links like Export Session + // output remain clickable. + const text = (anyAnchor.textContent || "").trim(); + const candidate = normalizeExplicitFileLink(href || text); + + const isAbsolutePath = /^(?:[a-zA-Z]:[/\\]|[/\\])/i.test(candidate); + const isRelativeFile = !isAbsolutePath && KNOWN_FILE_EXTENSIONS.test(candidate.replace(/:\d+(?::\d+)?$/, "")); + + if ((isAbsolutePath || isRelativeFile) && onFileClick) { + e.preventDefault(); + e.stopPropagation(); + onFileClick(candidate); + } + }, + [onFileClick] + ); + + return ( +
+ ); +}; + +export default Markdown; diff --git a/packages/vscode-ide-companion/src/webview/components/ui/badge.tsx b/packages/vscode-ide-companion/src/webview/components/ui/badge.tsx new file mode 100644 index 00000000..b88f683a --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/ui/badge.tsx @@ -0,0 +1,42 @@ +import * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority"; +import { Slot } from "radix-ui"; + +import { cn } from "@/webview/lib/utils"; + +const badgeVariants = cva( + "group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!", + { + variants: { + variant: { + default: + "bg-primary text-primary-foreground [a]:hover:bg-[color-mix(in_oklch,var(--primary),var(--primary-foreground)_10%)]", + secondary: + "bg-secondary text-secondary-foreground [a]:hover:bg-[color-mix(in_oklch,var(--secondary),var(--secondary-foreground)_10%)]", + destructive: + "bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20", + outline: "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground", + ghost: "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50", + link: "text-primary underline-offset-4 hover:underline", + }, + }, + defaultVariants: { + variant: "default", + }, + } +); + +function Badge({ + className, + variant = "default", + asChild = false, + ...props +}: React.ComponentProps<"span"> & VariantProps & { asChild?: boolean }) { + const Comp = asChild ? Slot.Root : "span"; + + return ( + + ); +} + +export { Badge, badgeVariants }; diff --git a/packages/vscode-ide-companion/src/webview/components/ui/button.tsx b/packages/vscode-ide-companion/src/webview/components/ui/button.tsx new file mode 100644 index 00000000..04415a85 --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/ui/button.tsx @@ -0,0 +1,66 @@ +import * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority"; +import { Slot } from "radix-ui"; + +import { cn } from "@/webview/lib/utils"; + +const buttonVariants = cva( + "group/button inline-flex shrink-0 items-center justify-center rounded-md border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", + { + variants: { + variant: { + default: "bg-primary text-primary-foreground hover:bg-primary/80", + outline: + "border-border bg-background shadow-xs hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50", + secondary: + "bg-secondary text-secondary-foreground hover:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)] aria-expanded:bg-secondary aria-expanded:text-secondary-foreground", + ghost: + "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50", + destructive: + "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: + "h-9 gap-1.5 px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2", + xs: "h-6 gap-1 rounded-[min(var(--radius-md),8px)] px-2 text-xs in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3", + sm: "h-8 gap-1 rounded-[min(var(--radius-md),10px)] px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5", + lg: "h-10 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2", + icon: "size-9", + "icon-xs": + "size-6 rounded-[min(var(--radius-md),8px)] in-data-[slot=button-group]:rounded-md [&_svg:not([class*='size-'])]:size-3", + "icon-sm": "size-8 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-md", + "icon-lg": "size-10", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +); + +function Button({ + className, + variant = "default", + size = "default", + asChild = false, + ...props +}: React.ComponentProps<"button"> & + VariantProps & { + asChild?: boolean; + }) { + const Comp = asChild ? Slot.Root : "button"; + + return ( + + ); +} + +export { Button, buttonVariants }; diff --git a/packages/vscode-ide-companion/src/webview/components/ui/card.tsx b/packages/vscode-ide-companion/src/webview/components/ui/card.tsx new file mode 100644 index 00000000..eefa711f --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/ui/card.tsx @@ -0,0 +1,70 @@ +import * as React from "react"; + +import { cn } from "@/webview/lib/utils"; + +function Card({ className, size = "default", ...props }: React.ComponentProps<"div"> & { size?: "default" | "sm" }) { + return ( +
img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(4)] *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl", + className + )} + {...props} + /> + ); +} + +function CardHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function CardTitle({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function CardDescription({ className, ...props }: React.ComponentProps<"div">) { + return
; +} + +function CardAction({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function CardContent({ className, ...props }: React.ComponentProps<"div">) { + return
; +} + +function CardFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +export { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent }; diff --git a/packages/vscode-ide-companion/src/webview/components/ui/checkbox.tsx b/packages/vscode-ide-companion/src/webview/components/ui/checkbox.tsx new file mode 100644 index 00000000..a725e0f3 --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/ui/checkbox.tsx @@ -0,0 +1,27 @@ +import * as React from "react"; +import { Checkbox as CheckboxPrimitive } from "radix-ui"; + +import { cn } from "@/webview/lib/utils"; +import { CheckIcon } from "lucide-react"; + +function Checkbox({ className, ...props }: React.ComponentProps) { + return ( + + + + + + ); +} + +export { Checkbox }; diff --git a/packages/vscode-ide-companion/src/webview/components/ui/collapsible.tsx b/packages/vscode-ide-companion/src/webview/components/ui/collapsible.tsx new file mode 100644 index 00000000..f1ac7b9d --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/ui/collapsible.tsx @@ -0,0 +1,16 @@ +import { Collapsible as CollapsiblePrimitive } from "radix-ui"; +import * as React from "react"; + +function Collapsible({ ...props }: React.ComponentProps) { + return ; +} + +function CollapsibleTrigger({ ...props }: React.ComponentProps) { + return ; +} + +function CollapsibleContent({ ...props }: React.ComponentProps) { + return ; +} + +export { Collapsible, CollapsibleTrigger, CollapsibleContent }; diff --git a/packages/vscode-ide-companion/src/webview/components/ui/command.tsx b/packages/vscode-ide-companion/src/webview/components/ui/command.tsx new file mode 100644 index 00000000..4ae60d55 --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/ui/command.tsx @@ -0,0 +1,151 @@ +import * as React from "react"; +import { Command as CommandPrimitive } from "cmdk"; + +import { cn } from "@/webview/lib/utils"; +import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/webview/components/ui/dialog"; +import { InputGroup, InputGroupAddon } from "@/webview/components/ui/input-group"; +import { SearchIcon, CheckIcon } from "lucide-react"; + +function Command({ className, label, ...props }: React.ComponentProps & { label?: string }) { + return ( + + ); +} + +function CommandDialog({ + title = "Command Palette", + description = "Search for a command to run...", + children, + className, + showCloseButton = false, + ...props +}: React.ComponentProps & { + title?: string; + description?: string; + className?: string; + showCloseButton?: boolean; +}) { + return ( + + + {title} + {description} + + + {children} + + + ); +} + +function CommandInput({ className, ...props }: React.ComponentProps) { + return ( +
+ + + + + + +
+ ); +} + +function CommandList({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function CommandEmpty({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function CommandGroup({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function CommandSeparator({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function CommandItem({ className, children, ...props }: React.ComponentProps) { + return ( + + {children} + + + ); +} + +function CommandShortcut({ className, ...props }: React.ComponentProps<"span">) { + return ( + + ); +} + +export { + Command, + CommandDialog, + CommandInput, + CommandList, + CommandEmpty, + CommandGroup, + CommandItem, + CommandShortcut, + CommandSeparator, +}; diff --git a/packages/vscode-ide-companion/src/webview/components/ui/dialog.tsx b/packages/vscode-ide-companion/src/webview/components/ui/dialog.tsx new file mode 100644 index 00000000..71bed7f8 --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/ui/dialog.tsx @@ -0,0 +1,132 @@ +import * as React from "react"; +import { Dialog as DialogPrimitive } from "radix-ui"; + +import { cn } from "@/webview/lib/utils"; +import { Button } from "@/webview/components/ui/button"; +import { XIcon } from "lucide-react"; + +function Dialog({ ...props }: React.ComponentProps) { + return ; +} + +function DialogTrigger({ ...props }: React.ComponentProps) { + return ; +} + +function DialogPortal({ ...props }: React.ComponentProps) { + return ; +} + +function DialogClose({ ...props }: React.ComponentProps) { + return ; +} + +function DialogOverlay({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function DialogContent({ + className, + children, + showCloseButton = true, + ...props +}: React.ComponentProps & { + showCloseButton?: boolean; +}) { + return ( + + + + {children} + {showCloseButton && ( + + + + )} + + + ); +} + +function DialogHeader({ className, ...props }: React.ComponentProps<"div">) { + return
; +} + +function DialogFooter({ + className, + showCloseButton = false, + children, + ...props +}: React.ComponentProps<"div"> & { + showCloseButton?: boolean; +}) { + return ( +
+ {children} + {showCloseButton && ( + + + + )} +
+ ); +} + +function DialogTitle({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function DialogDescription({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +export { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogOverlay, + DialogPortal, + DialogTitle, + DialogTrigger, +}; diff --git a/packages/vscode-ide-companion/src/webview/components/ui/drawer.tsx b/packages/vscode-ide-companion/src/webview/components/ui/drawer.tsx new file mode 100644 index 00000000..d2007383 --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/ui/drawer.tsx @@ -0,0 +1,102 @@ +import * as React from "react"; +import { Drawer as DrawerPrimitive } from "vaul"; + +import { cn } from "@/webview/lib/utils"; + +function Drawer({ ...props }: React.ComponentProps) { + return ; +} + +function DrawerTrigger({ ...props }: React.ComponentProps) { + return ; +} + +function DrawerPortal({ ...props }: React.ComponentProps) { + return ; +} + +function DrawerClose({ ...props }: React.ComponentProps) { + return ; +} + +function DrawerOverlay({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function DrawerContent({ className, children, ...props }: React.ComponentProps) { + return ( + + + +
+ {children} + + + ); +} + +function DrawerHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function DrawerFooter({ className, ...props }: React.ComponentProps<"div">) { + return
; +} + +function DrawerTitle({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function DrawerDescription({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +export { + Drawer, + DrawerPortal, + DrawerOverlay, + DrawerTrigger, + DrawerClose, + DrawerContent, + DrawerHeader, + DrawerFooter, + DrawerTitle, + DrawerDescription, +}; diff --git a/packages/vscode-ide-companion/src/webview/components/ui/dropdown-menu.tsx b/packages/vscode-ide-companion/src/webview/components/ui/dropdown-menu.tsx new file mode 100644 index 00000000..8785e38b --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/ui/dropdown-menu.tsx @@ -0,0 +1,236 @@ +import * as React from "react"; +import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui"; + +import { cn } from "@/webview/lib/utils"; +import { CheckIcon, ChevronRightIcon } from "lucide-react"; + +function DropdownMenu({ ...props }: React.ComponentProps) { + return ; +} + +function DropdownMenuPortal({ ...props }: React.ComponentProps) { + return ; +} + +function DropdownMenuTrigger({ ...props }: React.ComponentProps) { + return ; +} + +function DropdownMenuContent({ + className, + align = "start", + sideOffset = 4, + ...props +}: React.ComponentProps) { + return ( + + + + ); +} + +function DropdownMenuGroup({ ...props }: React.ComponentProps) { + return ; +} + +function DropdownMenuItem({ + className, + inset, + variant = "default", + ...props +}: React.ComponentProps & { + inset?: boolean; + variant?: "default" | "destructive"; +}) { + return ( + + ); +} + +function DropdownMenuCheckboxItem({ + className, + children, + checked, + inset, + ...props +}: React.ComponentProps & { + inset?: boolean; +}) { + return ( + + + + + + + {children} + + ); +} + +function DropdownMenuRadioGroup({ ...props }: React.ComponentProps) { + return ; +} + +function DropdownMenuRadioItem({ + className, + children, + inset, + ...props +}: React.ComponentProps & { + inset?: boolean; +}) { + return ( + + + + + + + {children} + + ); +} + +function DropdownMenuLabel({ + className, + inset, + ...props +}: React.ComponentProps & { + inset?: boolean; +}) { + return ( + + ); +} + +function DropdownMenuSeparator({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<"span">) { + return ( + + ); +} + +function DropdownMenuSub({ ...props }: React.ComponentProps) { + return ; +} + +function DropdownMenuSubTrigger({ + className, + inset, + children, + ...props +}: React.ComponentProps & { + inset?: boolean; +}) { + return ( + + {children} + + + ); +} + +function DropdownMenuSubContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +export { + DropdownMenu, + DropdownMenuPortal, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuLabel, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuSub, + DropdownMenuSubTrigger, + DropdownMenuSubContent, +}; diff --git a/packages/vscode-ide-companion/src/webview/components/ui/empty.tsx b/packages/vscode-ide-companion/src/webview/components/ui/empty.tsx new file mode 100644 index 00000000..56f4368c --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/ui/empty.tsx @@ -0,0 +1,87 @@ +import { cva, type VariantProps } from "class-variance-authority"; + +import { cn } from "@/webview/lib/utils"; + +function Empty({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function EmptyHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +const emptyMediaVariants = cva( + "mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0", + { + variants: { + variant: { + default: "bg-transparent", + icon: "flex size-10 shrink-0 items-center justify-center rounded-lg bg-muted text-foreground [&_svg:not([class*='size-'])]:size-6", + }, + }, + defaultVariants: { + variant: "default", + }, + } +); + +function EmptyMedia({ + className, + variant = "default", + ...props +}: React.ComponentProps<"div"> & VariantProps) { + return ( +
+ ); +} + +function EmptyTitle({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function EmptyDescription({ className, ...props }: React.ComponentProps<"p">) { + return ( +
a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary", + className + )} + {...props} + /> + ); +} + +function EmptyContent({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +export { Empty, EmptyHeader, EmptyTitle, EmptyDescription, EmptyContent, EmptyMedia }; diff --git a/packages/vscode-ide-companion/src/webview/components/ui/field.tsx b/packages/vscode-ide-companion/src/webview/components/ui/field.tsx new file mode 100644 index 00000000..5366a855 --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/ui/field.tsx @@ -0,0 +1,216 @@ +import React, { useMemo } from "react"; +import { cva, type VariantProps } from "class-variance-authority"; + +import { cn } from "@/webview/lib/utils"; +import { Label } from "@/webview/components/ui/label"; +import { Separator } from "@/webview/components/ui/separator"; + +function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">) { + return ( +
[data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3", + className + )} + {...props} + /> + ); +} + +function FieldLegend({ + className, + variant = "legend", + ...props +}: React.ComponentProps<"legend"> & { variant?: "legend" | "label" }) { + return ( + + ); +} + +function FieldGroup({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +const fieldVariants = cva("group/field flex w-full gap-3 data-[invalid=true]:text-destructive", { + variants: { + orientation: { + vertical: "flex-col *:w-full [&>.sr-only]:w-auto", + horizontal: + "flex-row items-center has-[>[data-slot=field-content]]:items-start *:data-[slot=field-label]:flex-auto has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px", + responsive: + "flex-col *:w-full @md/field-group:flex-row @md/field-group:items-center @md/field-group:*:w-auto @md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:*:data-[slot=field-label]:flex-auto [&>.sr-only]:w-auto @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px", + }, + }, + defaultVariants: { + orientation: "vertical", + }, +}); + +function Field({ + className, + orientation = "vertical", + ...props +}: React.ComponentProps<"div"> & VariantProps) { + return ( +
+ ); +} + +function FieldContent({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function FieldLabel({ className, ...props }: React.ComponentProps) { + return ( +
+
+
+ + + + + diff --git a/packages/vscode-ide-companion/vitest.config.ts b/packages/vscode-ide-companion/vitest.config.ts index 55f7ec6b..741fefdc 100644 --- a/packages/vscode-ide-companion/vitest.config.ts +++ b/packages/vscode-ide-companion/vitest.config.ts @@ -9,6 +9,7 @@ export default defineConfig({ alias: { "@": path.resolve(__dirname, "./src"), "@/webview": path.resolve(__dirname, "./src/webview"), + vscode: path.resolve(__dirname, "./src/tests/__mocks__/vscode.ts"), }, }, test: { From 542e440dd3311b946eae92d5048755e52a8d6c5b Mon Sep 17 00:00:00 2001 From: hcyang Date: Wed, 15 Jul 2026 15:09:07 +0800 Subject: [PATCH 14/51] =?UTF-8?q?feat(chat):=20=E6=B7=BB=E5=8A=A0=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E6=8F=90=E9=97=AECarousel=E7=BB=84=E4=BB=B6=E5=B9=B6?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E9=97=AE=E7=AD=94=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增AskQuestionCarousel组件实现多问题轮播问答交互 - 在App组件中集成AskQuestionCarousel,条件渲染用户提问界面 - 扩展ChatProvider状态管理,新增askUserQuestions状态字段 - 更新AskUserQuestion组件,增加类型守卫及表单验证优化 - 消息组件Messages调整,支持传递tool消息的isLastMessage属性 - 新增chatService接口addSystemMessage以记录系统问答摘要 - 调整DiffPreview组件props结构,更清晰地处理输出和元数据 - 优化InputPrompt及Messages组件的样式和结构细节 - 升级项目依赖,添加typescript-eslint相关依赖和配置 --- package-lock.json | 284 ++++++++++++++++ packages/vscode-ide-companion/package.json | 2 + packages/vscode-ide-companion/src/router.ts | 16 + .../vscode-ide-companion/src/webview/App.tsx | 17 +- .../components/AskQuestionCarousel.tsx | 305 ++++++++++++++++++ .../webview/components/AskUserQuestion.tsx | 230 ------------- .../src/webview/components/DiffPreview.tsx | 21 +- .../src/webview/components/InputPrompt.tsx | 2 +- .../src/webview/components/Messages.tsx | 23 +- .../webview/components/ThinkingLiveBubble.tsx | 36 ++- .../webview/components/bubbles/ToolBubble.tsx | 291 +++++++++++++---- .../src/webview/components/ui/scroll-area.tsx | 8 +- .../src/webview/context/ChatProvider.tsx | 3 + .../src/webview/services/chatService.ts | 8 + .../vscode-ide-companion/src/webview/types.ts | 17 +- .../src/webview/utils/utils.test.ts | 22 +- 16 files changed, 954 insertions(+), 331 deletions(-) create mode 100644 packages/vscode-ide-companion/src/webview/components/AskQuestionCarousel.tsx delete mode 100644 packages/vscode-ide-companion/src/webview/components/AskUserQuestion.tsx diff --git a/package-lock.json b/package-lock.json index 7a72e783..bba21ab4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14795,6 +14795,8 @@ "@types/react-dom": "^19.2.2", "@types/semver": "^7.7.1", "@types/vscode": "^1.85.0", + "@typescript-eslint/eslint-plugin": "^8.64.0", + "@typescript-eslint/parser": "^8.64.0", "@vitejs/plugin-react-swc": "^4.2.1", "@vscode/vsce": "^3.6.0", "autoprefixer": "^10.5.0", @@ -14874,6 +14876,288 @@ "undici-types": "~6.21.0" } }, + "packages/vscode-ide-companion/node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.64.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.64.0.tgz", + "integrity": "sha512-CGvQPBxN3wZLu6Rz2kFUpZeoCm78xUic92ck39KPePkO1NPOwjCqdQnm5Q87tpWw9vcBvW8XLrDXjH9PWYtJ3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.64.0", + "@typescript-eslint/type-utils": "8.64.0", + "@typescript-eslint/utils": "8.64.0", + "@typescript-eslint/visitor-keys": "8.64.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.64.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "packages/vscode-ide-companion/node_modules/@typescript-eslint/parser": { + "version": "8.64.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.64.0.tgz", + "integrity": "sha512-KA0OshtlcCCXmbfqyZkM5pV3/WNraJf7DkJRLpyrmwPtud57H5BDX7C3k0LPSPxpprfRL+cJDGabF10mvNCoCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.64.0", + "@typescript-eslint/types": "8.64.0", + "@typescript-eslint/typescript-estree": "8.64.0", + "@typescript-eslint/visitor-keys": "8.64.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "packages/vscode-ide-companion/node_modules/@typescript-eslint/project-service": { + "version": "8.64.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.64.0.tgz", + "integrity": "sha512-tk4WpOJ6IEbGrVHaNmM0YRrwAD3exZlIK3iadQNAxh4YKk6jvUQ4ecq18n+v7+meh+cJ3j+D8nbk8sRKhlwLQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.64.0", + "@typescript-eslint/types": "^8.64.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "packages/vscode-ide-companion/node_modules/@typescript-eslint/scope-manager": { + "version": "8.64.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.64.0.tgz", + "integrity": "sha512-CXEaFdYXjSTgKhisNkwCcJwTP8Pl+fmRrEQrri4nm3vU743bALrxzLmq7fHG/7e6a5xO0lDYeURpZmBuhHk54w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.64.0", + "@typescript-eslint/visitor-keys": "8.64.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "packages/vscode-ide-companion/node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.64.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.64.0.tgz", + "integrity": "sha512-2yo8rRNKuzbVWQp5kslhANqZ2uDAeROQHBRZNPu8JDsHmeFNj/XJJhX/FhNUWmkHHvoNsKa6+tHJiig87EzsQw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "packages/vscode-ide-companion/node_modules/@typescript-eslint/type-utils": { + "version": "8.64.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.64.0.tgz", + "integrity": "sha512-XWG4Fmmv/6SvyS9nH8jWrKs6terwJvE8cyRt1CzYYqzp9OrPhCT4cMc/f7C6RZCwG+qMmiffJS1/qJP8G1URtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.64.0", + "@typescript-eslint/typescript-estree": "8.64.0", + "@typescript-eslint/utils": "8.64.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "packages/vscode-ide-companion/node_modules/@typescript-eslint/types": { + "version": "8.64.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.64.0.tgz", + "integrity": "sha512-qjhfuTfLXjA4IOzXvz0rTjT01BqEiIgPoUeMwiEjnaHKJMTNo8rH5pYW1a2L/0Dnux2fPC85AeyJoWaGa8WxTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "packages/vscode-ide-companion/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.64.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.64.0.tgz", + "integrity": "sha512-Pztpsn1aCE1oWDvDEfUk31nngvvF7vUB5SwHFEaZIFpvw7WJtqUHHL4plBZDA9HfWJJjL13BdG0YrJInTUvoVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.64.0", + "@typescript-eslint/tsconfig-utils": "8.64.0", + "@typescript-eslint/types": "8.64.0", + "@typescript-eslint/visitor-keys": "8.64.0", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "packages/vscode-ide-companion/node_modules/@typescript-eslint/utils": { + "version": "8.64.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.64.0.tgz", + "integrity": "sha512-aJUGVB3+U0htrrCjoA8qukw8cm8fNCGAxK/tVoS70k8aeb7DETKeFozRiVFIwEeN9WJLsjaP3ph8I60tY2XZoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.64.0", + "@typescript-eslint/types": "8.64.0", + "@typescript-eslint/typescript-estree": "8.64.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "packages/vscode-ide-companion/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.64.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.64.0.tgz", + "integrity": "sha512-mrtuL8Nsn6gi2H4mo5KMTp823M+3Q19Ew/i+Zlikq20tIMm99C3Ez0dCmkWWnxut20esQvTg8aUSEhMcAOXhEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.64.0", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "packages/vscode-ide-companion/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "packages/vscode-ide-companion/node_modules/brace-expansion": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", + "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "packages/vscode-ide-companion/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "packages/vscode-ide-companion/node_modules/ignore": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz", + "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "packages/vscode-ide-companion/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "packages/vscode-ide-companion/node_modules/semver": { "version": "7.8.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", diff --git a/packages/vscode-ide-companion/package.json b/packages/vscode-ide-companion/package.json index 09a1a8cf..d72fcba5 100644 --- a/packages/vscode-ide-companion/package.json +++ b/packages/vscode-ide-companion/package.json @@ -128,6 +128,8 @@ "@types/react-dom": "^19.2.2", "@types/semver": "^7.7.1", "@types/vscode": "^1.85.0", + "@typescript-eslint/eslint-plugin": "^8.64.0", + "@typescript-eslint/parser": "^8.64.0", "@vitejs/plugin-react-swc": "^4.2.1", "@vscode/vsce": "^3.6.0", "autoprefixer": "^10.5.0", diff --git a/packages/vscode-ide-companion/src/router.ts b/packages/vscode-ide-companion/src/router.ts index 62c3bd09..8461c094 100644 --- a/packages/vscode-ide-companion/src/router.ts +++ b/packages/vscode-ide-companion/src/router.ts @@ -248,6 +248,22 @@ export const appRouter = router({ vscodeApi.window.showInformationMessage(input); return { ok: true }; }), + + addSystemMessage: procedure + .input( + z.object({ + content: z.string(), + meta: z.record(z.string(), z.unknown()).optional(), + }) + ) + .resolve(({ ctx, input }) => { + const activeSessionId = ctx.sessionManager.getActiveSessionId(); + if (!activeSessionId) { + return { ok: false, error: "No active session" }; + } + ctx.sessionManager.addSessionSystemMessage(activeSessionId, input.content, true, input.meta); + return { ok: true }; + }), }); export type AppRouter = typeof appRouter; diff --git a/packages/vscode-ide-companion/src/webview/App.tsx b/packages/vscode-ide-companion/src/webview/App.tsx index cf5f27d0..c05c42d2 100644 --- a/packages/vscode-ide-companion/src/webview/App.tsx +++ b/packages/vscode-ide-companion/src/webview/App.tsx @@ -4,25 +4,20 @@ import InputPrompt from "@/webview/components/InputPrompt"; import ThinkingLiveBubble from "@/webview/components/ThinkingLiveBubble"; import PermissionPrompt from "@/webview/components/PermissionPrompt"; import { useChat } from "@/webview/context/ChatProvider"; +import AskQuestionCarousel from "@/webview/components/AskQuestionCarousel"; export default function App() { const { state, dispatch, actions } = useChat(); return ( -
+
- + )} + {state.askUserQuestions && ( + dispatch({ type: "SET_ASK_USER_QUESTIONS", data: null })} + /> + )} void; +} + +const answerSchema = z + .object({ + question: z.string(), + options: z.array(z.string()).optional(), + other: z.string().optional(), + }) + .superRefine((data, ctx) => { + const opts = data.options ?? []; + const oth = data.other ?? ""; + if (opts.length === 0 && oth.trim().length === 0) { + ctx.addIssue({ + code: "custom", + message: "Please answer the question.", + path: ["other"], + }); + } + }); + +const formSchema = z.object({ + answers: z.array(answerSchema), +}); + +export type AnswerFormValues = z.infer; + +const AskQuestionCarousel: React.FC = ({ questions, onClose }) => { + const { actions } = useChat(); + const [api, setApi] = React.useState(); + const [current, setCurrent] = React.useState(0); + const [count, setCount] = React.useState(0); + + const form = useForm({ + resolver: zodResolver(formSchema), + defaultValues: { + answers: questions.map((q) => ({ + question: q.question, + options: [] as string[], + other: "", + })), + }, + }); + + // 实时监听每个问题的答案,用于决定是否禁用提交按钮 + const watchedAnswers = form.watch("answers"); + const allEmpty = + watchedAnswers?.every((a: { options?: string[]; other?: string }) => { + const opts = a?.options ?? []; + const oth = a?.other ?? ""; + return opts.length === 0 && oth.trim().length === 0; + }) ?? true; + + const onSubmit = useCallback( + async (data: AnswerFormValues) => { + console.log(JSON.stringify(data.answers)); + const reply = buildAskUserQuestionReply(data?.answers || []); + console.log("reply:", JSON.stringify(reply)); + if (!reply.ok) { + console.log("reply.error:", reply.error || "Please answer the question."); + form.setError("answers", { message: reply.error || "Please answer the question." }); + return; + } + + // Build Q&A summary + const summary = questions + .map((q, idx) => { + const ans = data.answers[idx]; + const ansText = + (ans?.options && ans.options.length > 0 ? ans.options.join(", ") : "") + + (ans?.options && ans.options.length > 0 && ans?.other ? "; " : "") + + (ans?.other ?? ""); + return `Q: ${q.question}\nA: ${ansText || "(无回答)"}`; + }) + .join("\n\n"); + + // Insert system message via RPC (persisted in session) + try { + await chatService.addSystemMessage(summary, { kind: "ask_user_question_summary" }); + } catch (err) { + console.error("Failed to add system message:", err); + } + + // Close the carousel + onClose?.(); + + // Send the user reply to backend + actions.sendPrompt(reply?.text || ""); + }, + [form, actions, questions, onClose] + ); + + useEffect(() => { + if (!api) { + return; + } + setCount(api.scrollSnapList().length); + setCurrent(api.selectedScrollSnap() + 1); + api.on("select", () => { + setCurrent(api.selectedScrollSnap() + 1); + }); + }, [api]); + + if (!questions || questions.length === 0) { + return null; + } + + return ( + +
+ + + + + +
+ + + + + + {questions.map((q, index) => ( + + + + + {q.multiSelect ? ( + (q.options || []).map((opt: { label: string; description?: string }, optIdx: number) => ( + ( + + { + const newValue = checked + ? [...(field.value || []), opt.label] + : field.value + ? field.value.filter((v: string) => v !== opt.label) + : []; + field.onChange(newValue); + }} + /> + + + {opt.label} + + {opt.description && ( + + {opt.description} + + )} + {fieldState.invalid && } + + + )} + /> + )) + ) : ( + ( + field.onChange([val])} + aria-invalid={fieldState.invalid} + > + {(q.options || []).map( + (opt: { label: string; description?: string }, optIdx: number) => ( + + + + + {opt.label} + + {opt.description && ( + + {opt.description} + + )} + + + ) + )} + + )} + /> + )} + ( + + + Other + + + {fieldState.invalid && } + + )} + /> + + + + + ))} + + + + + +
+
+ + + + {current}/{count} + +
+
+ +
+
+
+ + ); +}; + +export default AskQuestionCarousel; diff --git a/packages/vscode-ide-companion/src/webview/components/AskUserQuestion.tsx b/packages/vscode-ide-companion/src/webview/components/AskUserQuestion.tsx deleted file mode 100644 index b9d76d8e..00000000 --- a/packages/vscode-ide-companion/src/webview/components/AskUserQuestion.tsx +++ /dev/null @@ -1,230 +0,0 @@ -import { useCallback } from "react"; -import { Button } from "@/webview/components/ui/button"; -import { - Field, - FieldContent, - FieldDescription, - FieldError, - FieldGroup, - FieldLabel, -} from "@/webview/components/ui/field"; -import { Checkbox } from "@/webview/components/ui/checkbox"; -import { Textarea } from "@/webview/components/ui/textarea"; -import { RadioGroup, RadioGroupItem } from "@/webview/components/ui/radio-group"; -import { Controller, useForm } from "react-hook-form"; -import * as z from "zod"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "./ui/card"; -import { buildAskUserQuestionReply } from "@/webview/utils"; -import { useChat } from "@/webview/context"; - -interface QuestionOption { - label: string; - description?: string; -} - -interface Question { - question: string; - multiSelect?: boolean; - options?: QuestionOption[]; -} - -interface ToolData { - ok: boolean; - name: string; - output: string; - metadata?: { - kind?: string; - questions?: Question[]; - }; -} - -interface AskUserQuestionProps { - toolData: ToolData; -} -const answerSchema = z - .object({ - question: z.string(), - options: z.array(z.string()).optional(), - other: z.string().optional(), - }) - .superRefine((data, ctx) => { - const opts = data.options ?? []; - const oth = data.other ?? ""; - if (opts.length === 0 && oth.trim().length === 0) { - ctx.addIssue({ - code: "custom", - message: "Please answer the question.", - path: ["other"], - }); - } - }); - -const formSchema = z.object({ - answers: z.array(answerSchema), -}); - -export type AnswerFormValues = z.infer; - -export default function AskUserQuestion({ toolData }: AskUserQuestionProps) { - const { actions } = useChat(); - const questions = toolData.metadata?.questions || []; - - const form = useForm({ - resolver: zodResolver(formSchema), - defaultValues: { - answers: questions.map((q) => ({ - question: q.question, - options: [] as string[], - other: "", - })), - }, - }); - - // 实时监听每个问题的答案,用于决定是否禁用提交按钮 - const watchedAnswers = form.watch("answers"); - const allEmpty = - watchedAnswers?.every((a) => { - const opts = a?.options ?? []; - const oth = a?.other ?? ""; - return opts.length === 0 && oth.trim().length === 0; - }) ?? true; - - const onSubmit = useCallback( - (data: AnswerFormValues) => { - console.log(JSON.stringify(data.answers)); - const reply = buildAskUserQuestionReply(data?.answers || []); - console.log("reply:", JSON.stringify(reply)); - if (!reply.ok) { - console.log("reply.error:", reply.error || "Please answer the question."); - form.setError("answers", { message: reply.error || "Please answer the question." }); - return; - } - // sendUserPromptText(reply.text); - actions.sendPrompt(reply?.text || ""); - }, - [form, actions] - ); - - if (questions.length === 0) { - return
{toolData.output || "No questions were provided."}
; - } - - return ( -
-
-
The agent needs your input before it can continue.
- {questions.map((q, qIdx) => ( - - - {q.question || `Question ${qIdx + 1}`} - - - - {q.multiSelect ? ( - (q.options || []).map((opt, optIdx) => ( - ( - - { - const newValue = checked - ? [...(field.value || []), opt.label] - : field.value - ? field.value.filter((v) => v !== opt.label) - : []; - field.onChange(newValue); - }} - /> - - - {opt.label} - - {opt.description && ( - - {opt.description} - - )} - {fieldState.invalid && } - - - )} - /> - )) - ) : ( - ( - field.onChange([val])} - aria-invalid={fieldState.invalid} - > - {(q.options || []).map((opt, optIdx) => ( - - - - - {opt.label} - - {opt.description && ( - - {opt.description} - - )} - - - ))} - - )} - /> - )} - ( - - - Other - - - -
-
-
-
- - - - - From bbcba639f8bf2ba2fdb7cc2d98ba93112ea5f21c Mon Sep 17 00:00:00 2001 From: hcyang Date: Wed, 22 Jul 2026 14:19:03 +0800 Subject: [PATCH 43/51] =?UTF-8?q?feat(chat):=20=E5=AE=9E=E7=8E=B0=E8=81=8A?= =?UTF-8?q?=E5=A4=A9=E4=BC=9A=E8=AF=9D=E5=88=97=E8=A1=A8=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E5=88=87=E6=8D=A2=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 ChatProvider 中添加 sessionListOpen 状态和切换函数 toggleSessionList - 在 App 组件传递 sessionListOpen 和 onToggleSessionList 给 Header 组件 - Header 组件集成 SessionList 的显示控制,支持展开收起操作 - SessionList 组件支持受控和非受控的展开状态管理,支持展开状态变化回调 - extension.ts 新增命令注册(newchat、settings、history),实现与 Webview 的消息通信触发 - 抽象 openFileInEditor 与 getWorkspaceRoot 函数,简化 extension.ts 相关代码 - package.json 增加新命令配置和视图标题按钮关联 - 优化 Header 组件 UI,去除不必要按钮,并新增会话列表图标及标题样式调整 --- packages/vscode-ide-companion/package.json | 36 ++++++++ .../vscode-ide-companion/src/extension.ts | 83 +++++++++++++++---- .../vscode-ide-companion/src/webview/App.tsx | 2 + .../src/webview/components/Header.tsx | 67 ++++----------- .../src/webview/components/SessionList.tsx | 61 +++++++++----- .../src/webview/context/ChatProvider.tsx | 27 +++++- .../vscode-ide-companion/src/webview/types.ts | 4 +- 7 files changed, 192 insertions(+), 88 deletions(-) diff --git a/packages/vscode-ide-companion/package.json b/packages/vscode-ide-companion/package.json index 0b10a852..981b68fa 100644 --- a/packages/vscode-ide-companion/package.json +++ b/packages/vscode-ide-companion/package.json @@ -45,6 +45,7 @@ "onView:deepcode.chatView" ], "contributes": { + "markdown.markdownItPlugins": true, "commands": [ { "command": "deepcode.openView", @@ -53,6 +54,24 @@ "light": "assets/deepcoding_icon.svg", "dark": "assets/deepcoding_icon.svg" } + }, + { + "command": "deepcode.newchat", + "category": "Deep Code", + "title": "New Chat", + "icon": "$(add)" + }, + { + "command": "deepcode.settings", + "category": "Deep Code", + "title": "Settings", + "icon": "$(settings-gear)" + }, + { + "command": "deepcode.history", + "category": "Deep Code", + "title": "Show Chat History", + "icon": "$(layout-sidebar-right)" } ], "viewsContainers": { @@ -80,6 +99,23 @@ "command": "deepcode.openView", "group": "navigation@100" } + ], + "view/title": [ + { + "command": "deepcode.newchat", + "group": "navigation", + "when": "view == deepcode.chatView" + }, + { + "command": "deepcode.settings", + "group": "navigation", + "when": "view == deepcode.chatView" + }, + { + "command": "deepcode.history", + "group": "navigation", + "when": "view == deepcode.chatView" + } ] } }, diff --git a/packages/vscode-ide-companion/src/extension.ts b/packages/vscode-ide-companion/src/extension.ts index 8b72d21f..bd2ab711 100644 --- a/packages/vscode-ide-companion/src/extension.ts +++ b/packages/vscode-ide-companion/src/extension.ts @@ -21,6 +21,7 @@ import { attachRouterToPanel } from "@webview-rpc/host"; import { createLogger } from "./utils/logger.js"; import { checkForUpdates } from "./utils/checkForUpdates.js"; import { reverseApplyDiff } from "./utils/diff-utils.js"; +import type MarkdownIt from "markdown-it"; const DEFAULT_MODEL = "deepseek-v4-pro"; const DEFAULT_BASE_URL = "https://api.deepseek.com"; @@ -252,9 +253,7 @@ export class DeepCodeViewProvider implements vscode.WebviewViewProvider { } private getWorkspaceRoot(): string { - const workspace = vscode.workspace.workspaceFolders?.[0]; - if (workspace) return workspace.uri.fsPath; - return process.cwd(); + return getWorkspaceRootFn(); } private createOpenAIClient(): { @@ -316,16 +315,7 @@ export class DeepCodeViewProvider implements vscode.WebviewViewProvider { } private async openFileInEditor(filePath: string, line: number): Promise { - const document = await vscode.workspace.openTextDocument(vscode.Uri.file(filePath)); - const editor = await vscode.window.showTextDocument(document, { - preview: false, - preserveFocus: false, - }); - const targetLine = Number.isFinite(line) && line > 0 ? Math.floor(line) - 1 : 0; - const safeLine = Math.min(Math.max(0, targetLine), Math.max(0, document.lineCount - 1)); - const position = new vscode.Position(safeLine, 0); - editor.selection = new vscode.Selection(position, position); - editor.revealRange(new vscode.Range(position, position), vscode.TextEditorRevealType.InCenter); + return openFileInEditorFn(filePath, line); } /** @@ -384,7 +374,28 @@ export class DeepCodeViewProvider implements vscode.WebviewViewProvider { } } -export async function activate(context: vscode.ExtensionContext): Promise { +async function openFileInEditorFn(filePath: string, line: number): Promise { + const document = await vscode.workspace.openTextDocument(vscode.Uri.file(filePath)); + const editor = await vscode.window.showTextDocument(document, { + preview: false, + preserveFocus: false, + }); + const targetLine = Number.isFinite(line) && line > 0 ? Math.floor(line) - 1 : 0; + const safeLine = Math.min(Math.max(0, targetLine), Math.max(0, document.lineCount - 1)); + const position = new vscode.Position(safeLine, 0); + editor.selection = new vscode.Selection(position, position); + editor.revealRange(new vscode.Range(position, position), vscode.TextEditorRevealType.InCenter); +} + +function getWorkspaceRootFn(): string { + const workspace = vscode.workspace.workspaceFolders?.[0]; + if (workspace) return workspace.uri.fsPath; + return process.cwd(); +} + +export async function activate( + context: vscode.ExtensionContext +): Promise<{ extendMarkdownIt(md: MarkdownIt): MarkdownIt }> { process.env.NoDefaultCurrentDirectoryInExePath = "1"; logger = vscode.window.createOutputChannel("Deep Code"); log = createLogger(context, logger); @@ -438,13 +449,57 @@ export async function activate(context: vscode.ExtensionContext): Promise }) ); + // Open view context.subscriptions.push( vscode.commands.registerCommand("deepcode.openView", async () => { await vscode.commands.executeCommand("workbench.view.extension.deepcode"); await vscode.commands.executeCommand("deepcode.chatView.focus"); }) ); + // Open settings + context.subscriptions.push( + vscode.commands.registerCommand("deepcode.settings", async () => { + const projectRoot = getWorkspaceRootFn(); + const projectSettingsPath = path.join(projectRoot, ".deepcode", "settings.json"); + const userSettingsPath = path.join(os.homedir(), ".deepcode", "settings.json"); + + if (fs.existsSync(projectSettingsPath)) { + await openFileInEditorFn(projectSettingsPath, 1); + } else { + // Ensure user settings directory exists + const userSettingsDir = path.dirname(userSettingsPath); + if (!fs.existsSync(userSettingsDir)) { + fs.mkdirSync(userSettingsDir, { recursive: true }); + } + if (!fs.existsSync(userSettingsPath)) { + fs.writeFileSync(userSettingsPath, JSON.stringify({}, null, 2), "utf8"); + } + await openFileInEditorFn(userSettingsPath, 1); + } + }) + ); + + // Create new chat + context.subscriptions.push( + vscode.commands.registerCommand("deepcode.newchat", () => { + log("deepcode.newchat"); + provider.postMessageToWebview({ type: "triggerNewChat" }); + }) + ); + + // Show history + context.subscriptions.push( + vscode.commands.registerCommand("deepcode.history", () => { + log("deepcode.history"); + provider.postMessageToWebview({ type: "triggerHistory" }); + }) + ); context.subscriptions.push(logger); + return { + extendMarkdownIt(md: MarkdownIt) { + return md.use(require("markdown-it-task-lists")); + }, + }; } export function deactivate(): void { diff --git a/packages/vscode-ide-companion/src/webview/App.tsx b/packages/vscode-ide-companion/src/webview/App.tsx index 1e19a303..89680453 100644 --- a/packages/vscode-ide-companion/src/webview/App.tsx +++ b/packages/vscode-ide-companion/src/webview/App.tsx @@ -29,6 +29,8 @@ export default function App() { onCreateNewSession={actions.createNewSession} onRenameSession={actions.renameSession} onDeleteSession={actions.deleteSession} + sessionListOpen={state.sessionListOpen} + onToggleSessionList={actions.toggleSessionList} /> void; onRenameSession: (sessionId: string, summary: string) => void; onDeleteSession: (sessionId: string) => void; + sessionListOpen: boolean; + onToggleSessionList: (open?: boolean) => void; } export default function Header({ @@ -23,6 +21,8 @@ export default function Header({ onCreateNewSession, onRenameSession, onDeleteSession, + sessionListOpen, + onToggleSessionList, }: HeaderProps) { const handleSelect = useCallback( (sessionId: string) => { @@ -39,56 +39,23 @@ export default function Header({ }, [sessions, activeSessionId]); return ( -
- - -
- - - - - -

New Chat

-
-
- - - - - -

Settings

-
-
-
+ onToggleSessionList(open)} + />
); } diff --git a/packages/vscode-ide-companion/src/webview/components/SessionList.tsx b/packages/vscode-ide-companion/src/webview/components/SessionList.tsx index da21c66f..5e70d785 100644 --- a/packages/vscode-ide-companion/src/webview/components/SessionList.tsx +++ b/packages/vscode-ide-companion/src/webview/components/SessionList.tsx @@ -49,6 +49,8 @@ interface SessionListProps { onCreateNewSession: () => void; onRename: (sessionId: string, summary: string) => void; onDelete: (sessionId: string) => void; + open?: boolean; + onOpenChange?: (open: boolean) => void; } function formatTime(dateString: string): string { @@ -71,9 +73,22 @@ export default function SessionList({ onCreateNewSession, onRename, onDelete, + open: controlledOpen, + onOpenChange, }: SessionListProps) { const [query, setQuery] = useState(""); - const [drawerOpen, setDrawerOpen] = useState(false); + const [internalOpen, setInternalOpen] = useState(false); + const isControlled = controlledOpen !== undefined; + const drawerOpen = isControlled ? controlledOpen : internalOpen; + const setDrawerOpen = useCallback( + (open: boolean) => { + if (!isControlled) { + setInternalOpen(open); + } + onOpenChange?.(open); + }, + [isControlled, onOpenChange] + ); const [editingId, setEditingId] = useState(null); const [editValue, setEditValue] = useState(""); const [contextMenuOpenId, setContextMenuOpenId] = useState(); @@ -83,7 +98,7 @@ export default function SessionList({ const handleCloseDrawer = useCallback(() => { setDrawerOpen(false); - }, []); + }, [setDrawerOpen]); // Focus the edit input when editing starts useEffect(() => { @@ -202,7 +217,7 @@ export default function SessionList({ console.error("Failed to open chat panel:", err); } }, - [onSelect, onCreateNewSession, handleCloseDrawer] + [onSelect, onCreateNewSession, handleCloseDrawer, activeSessionId] ); const handleInspectJsonl = useCallback(async (sessionId: string) => { @@ -259,7 +274,7 @@ export default function SessionList({ document.addEventListener("keydown", handler, true); return () => document.removeEventListener("keydown", handler, true); - }, [contextMenuOpenId, sessions, handleContextMenuOpen]); + }, [contextMenuOpenId, sessions, handleContextMenuOpen, handleStartRename]); return ( - - - - - - -

Sessions

-
-
-
+ {!isControlled && ( + + + + + + +

Sessions

+
+
+
+ )} Sessions diff --git a/packages/vscode-ide-companion/src/webview/context/ChatProvider.tsx b/packages/vscode-ide-companion/src/webview/context/ChatProvider.tsx index 0ab8aba5..1fb18321 100644 --- a/packages/vscode-ide-companion/src/webview/context/ChatProvider.tsx +++ b/packages/vscode-ide-companion/src/webview/context/ChatProvider.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useReducer, createContext, useContext } from "react"; +import React, { useCallback, useEffect, useReducer, createContext, useContext, useRef } from "react"; import { wrpc } from "@/webview/wrpc"; import { chatService } from "@/webview/services/chatService"; import type { @@ -42,6 +42,7 @@ interface ChatContextValue { deleteSession: (sessionId: string) => Promise; dismissContinuePrompt: () => void; continueGeneration: () => Promise; + toggleSessionList: (open?: boolean) => void; }; } @@ -70,6 +71,7 @@ const initialState: AppState = { editingMessage: null, askUserQuestions: null, showContinuePrompt: false, + sessionListOpen: false, }; function appReducer(state: AppState, action: AppAction): AppState { @@ -173,6 +175,8 @@ function appReducer(state: AppState, action: AppAction): AppState { return { ...state, askUserQuestions: action.data }; case "DISMISS_CONTINUE_PROMPT": return { ...state, showContinuePrompt: false }; + case "TOGGLE_SESSION_LIST": + return { ...state, sessionListOpen: action.open !== undefined ? action.open : !state.sessionListOpen }; default: return state; } @@ -226,6 +230,16 @@ export function ChatProvider({ children }: ChatProviderProps) { } }, [skillsData]); + // Ref to access createNewSession from message handler (stable callback, but kept for clarity) + const createNewSessionRef = useRef<() => Promise>(async () => {}); + createNewSessionRef.current = async () => { + const result = await chatService.createNewSession(); + dispatch({ type: "INIT_EMPTY", sessions: result.sessions, tokenTelemetry: null }); + if (result.skills) { + dispatch({ type: "SET_SKILLS", skills: result.skills }); + } + }; + // Listen for streaming push messages from extension host useEffect(() => { const handler = (event: MessageEvent) => { @@ -282,6 +296,12 @@ export function ChatProvider({ children }: ChatProviderProps) { case "loading": dispatch({ type: "SET_LOADING", loading: Boolean(message.value) }); break; + case "triggerNewChat": + void createNewSessionRef.current(); + break; + case "triggerHistory": + dispatch({ type: "TOGGLE_SESSION_LIST" }); + break; } }; window.addEventListener("message", handler); @@ -409,6 +429,10 @@ export function ChatProvider({ children }: ChatProviderProps) { } }, []); + const toggleSessionList = useCallback((open?: boolean) => { + dispatch({ type: "TOGGLE_SESSION_LIST", open }); + }, []); + const contextValue: ChatContextValue = { state, dispatch, @@ -424,6 +448,7 @@ export function ChatProvider({ children }: ChatProviderProps) { deleteSession, dismissContinuePrompt, continueGeneration, + toggleSessionList, }, }; diff --git a/packages/vscode-ide-companion/src/webview/types.ts b/packages/vscode-ide-companion/src/webview/types.ts index 407acaab..a8d21f66 100644 --- a/packages/vscode-ide-companion/src/webview/types.ts +++ b/packages/vscode-ide-companion/src/webview/types.ts @@ -115,6 +115,7 @@ export interface AppState { editingMessage: EditingMessage | null; askUserQuestions: AskUserQuestionData | null; showContinuePrompt: boolean; + sessionListOpen: boolean; } // --- App actions --- @@ -153,4 +154,5 @@ export type AppAction = | { type: "SET_ACTIVE_EDITOR"; editor: ActiveEditor | null } | { type: "SET_EDITING_MESSAGE"; editingMessage: EditingMessage | null } | { type: "SET_ASK_USER_QUESTIONS"; data: AskUserQuestionData | null } - | { type: "DISMISS_CONTINUE_PROMPT" }; + | { type: "DISMISS_CONTINUE_PROMPT" } + | { type: "TOGGLE_SESSION_LIST"; open?: boolean }; From 84a80ae6490bab73d4719fe03fa8be65b45c4a70 Mon Sep 17 00:00:00 2001 From: hcyang Date: Wed, 22 Jul 2026 15:33:54 +0800 Subject: [PATCH 44/51] =?UTF-8?q?feat(chat):=20=E6=B7=BB=E5=8A=A0=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E6=90=9C=E7=B4=A2=E9=9D=A2=E6=9D=BF=E5=8F=8A=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E8=B7=B3=E8=BD=AC=E9=AB=98=E4=BA=AE=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在聊天上下文中新增搜索面板状态及切换动作 - 实现SearchDialog组件支持按消息内容和角色搜索 - 在Header中添加搜索按钮,条件显示并触发搜索面板切换 - 消息列表组件新增scrollToMessage方法,支持滚动定位并高亮指定消息 - sendPrompt方法优化,新增返回sessionId,首次发送提示时设置activeSessionId - 增加chatService的getSessions接口及相关测试 - 新增挂载activeSessionId的useRef以保证稳定回调读写 - 添加关键帧动画实现消息高亮呼吸灯效果 - 增加相关单元测试覆盖会话列表设置与激活逻辑 --- packages/vscode-ide-companion/src/router.ts | 3 +- .../vscode-ide-companion/src/webview/App.tsx | 23 +- .../src/webview/components/Header.tsx | 46 +++- .../src/webview/components/Messages.tsx | 89 +++++-- .../src/webview/components/SearchDialog.tsx | 108 ++++++++ .../src/webview/context/ChatProvider.test.tsx | 234 ++++++++++++++++++ .../src/webview/context/ChatProvider.tsx | 28 ++- .../src/webview/index.css | 10 + .../src/webview/services/chatService.test.ts | 46 +++- .../src/webview/services/chatService.ts | 16 +- .../vscode-ide-companion/src/webview/types.ts | 5 +- 11 files changed, 563 insertions(+), 45 deletions(-) create mode 100644 packages/vscode-ide-companion/src/webview/components/SearchDialog.tsx diff --git a/packages/vscode-ide-companion/src/router.ts b/packages/vscode-ide-companion/src/router.ts index 45856193..9e3eb518 100644 --- a/packages/vscode-ide-companion/src/router.ts +++ b/packages/vscode-ide-companion/src/router.ts @@ -172,7 +172,8 @@ export const appRouter = router({ }; await ctx.sessionManager.handleUserPrompt(userPrompt); - return { ok: true }; + const sessionId = ctx.sessionManager.getActiveSessionId(); + return { ok: true, sessionId }; } catch (error) { const message = error instanceof Error ? error.message : String(error); ctx.postMessage({ diff --git a/packages/vscode-ide-companion/src/webview/App.tsx b/packages/vscode-ide-companion/src/webview/App.tsx index 89680453..ce946abf 100644 --- a/packages/vscode-ide-companion/src/webview/App.tsx +++ b/packages/vscode-ide-companion/src/webview/App.tsx @@ -1,17 +1,19 @@ -import { useCallback, useRef } from "react"; +import { useCallback, useRef, useMemo } from "react"; import Header from "@/webview/components/Header"; import Messages from "@/webview/components/Messages"; +import type { MessagesHandle } from "@/webview/components/Messages"; import InputPrompt from "@/webview/components/InputPrompt"; import ThinkingLiveBubble from "@/webview/components/ThinkingLiveBubble"; import PermissionPrompt from "@/webview/components/PermissionPrompt"; import ContinuePrompt from "@/webview/components/ContinuePrompt"; import { useChat } from "@/webview/context/ChatProvider"; import AskQuestionCarousel from "@/webview/components/AskQuestionCarousel"; +import SearchDialog from "@/webview/components/SearchDialog"; import type { AskUserQuestionMetadata } from "@/webview/components/bubbles/ToolBubble"; export default function App() { const { state, dispatch, actions } = useChat(); - const messagesRef = useRef(null); + const messagesRef = useRef(null); const handleAskUserQuestions = useCallback( (questions: AskUserQuestionMetadata["questions"]) => { @@ -20,6 +22,15 @@ export default function App() { [dispatch] ); + const handleSelectMessage = useCallback((messageId: string) => { + messagesRef.current?.scrollToMessage(messageId); + }, []); + + const handleSearchOpenChange = useMemo( + () => (open: boolean) => actions.toggleSearchPanel(open), + [actions.toggleSearchPanel] + ); + return (
0} + onToggleSearchPanel={actions.toggleSearchPanel} /> dispatch({ type: "SET_ASK_USER_QUESTIONS", data: null })} /> )} + void; sessionListOpen: boolean; onToggleSessionList: (open?: boolean) => void; + hasMessages: boolean; + onToggleSearchPanel: (open?: boolean) => void; } export default function Header({ @@ -23,6 +28,8 @@ export default function Header({ onDeleteSession, sessionListOpen, onToggleSessionList, + hasMessages, + onToggleSearchPanel, }: HeaderProps) { const handleSelect = useCallback( (sessionId: string) => { @@ -46,16 +53,35 @@ export default function Header({ {activeSessionSummary || (activeSessionId ? "Deep Code" : "New Conversation")}
- onToggleSessionList(open)} - /> +
+ {activeSessionId && hasMessages && ( + + + + + +

Search Messages

+
+
+ )} + onToggleSessionList(open)} + /> +
); } diff --git a/packages/vscode-ide-companion/src/webview/components/Messages.tsx b/packages/vscode-ide-companion/src/webview/components/Messages.tsx index c686fbd9..07a043ae 100644 --- a/packages/vscode-ide-companion/src/webview/components/Messages.tsx +++ b/packages/vscode-ide-companion/src/webview/components/Messages.tsx @@ -1,4 +1,4 @@ -import React, { useRef, useEffect, forwardRef } from "react"; +import React, { useRef, useEffect, forwardRef, useImperativeHandle } from "react"; import { ScrollArea, ScrollBar } from "@/webview/components/ui/scroll-area"; import UserBubble from "@/webview/components/bubbles/UserBubble"; import AssistantBubble from "@/webview/components/bubbles/AssistantBubble"; @@ -19,20 +19,57 @@ interface MessagesProps { onAskUserQuestions?: (questions: AskUserQuestionMetadata["questions"]) => void; } -const Messages = forwardRef( +export interface MessagesHandle { + scrollToMessage: (messageId: string) => void; +} + +const Messages = forwardRef( ({ messages, loading, onEditMessage, onAskUserQuestions }, ref) => { + const scrollAreaRef = useRef(null); const bottomRef = useRef(null); + const suppressScrollRef = useRef(false); + const highlightedElRef = useRef(null); const handleToBottom = () => { bottomRef.current?.scrollIntoView({ behavior: "smooth" }); }; + useEffect(() => { - handleToBottom(); + if (!suppressScrollRef.current) { + handleToBottom(); + } }, [messages, loading]); - // useImperativeHandle(ref, ()=> { - // return bottomRef.current ? bottomRef.current : undefined; - // }) + useImperativeHandle(ref, () => ({ + scrollToMessage: (messageId: string) => { + suppressScrollRef.current = true; + + // Remove highlight from previously highlighted element + if (highlightedElRef.current) { + highlightedElRef.current.classList.remove("msg-highlight-breathe"); + } + + const el = document.querySelector(`[data-message-id="${messageId}"]`); + if (el) { + el.scrollIntoView({ behavior: "smooth", block: "center" }); + // Apply breathing light effect + el.classList.add("msg-highlight-breathe"); + highlightedElRef.current = el; + // Remove the class after animation completes (3 iterations * 0.8s) + setTimeout(() => { + el.classList.remove("msg-highlight-breathe"); + if (highlightedElRef.current === el) { + highlightedElRef.current = null; + } + }, 2600); + } + + // Re-enable auto-scroll after a delay + setTimeout(() => { + suppressScrollRef.current = false; + }, 1500); + }, + })); if (messages.length === 0) { return ( @@ -47,7 +84,7 @@ const Messages = forwardRef( } return ( { console.log("eeeee", e); }} @@ -57,15 +94,21 @@ const Messages = forwardRef( {messages.map((msg, index) => { const prevMsg = index > 0 ? messages[index - 1] : null; const shouldConnect = prevMsg ? prevMsg.role !== "user" && msg.role !== "user" : false; + const msgId = msg.id || `msg-${index}`; + + const wrapWithId = (element: React.ReactNode, key: string) => ( +
+ {element} +
+ ); switch (msg.role) { case "user": { if (msg.meta?.userPrompt?.askUserQuestionSummary) { - return ; + return wrapWithId(, `msg-${index}`); } - return ( + return wrapWithId( ( } : undefined } - /> + />, + `msg-${index}` ); } case "assistant": { const meta = msg.meta as { asThinking?: boolean } | undefined; if (meta?.asThinking) { - return ( - + return wrapWithId( + , + `msg-${index}` ); } - return ; + return wrapWithId(, `msg-${index}`); } case "tool": - return ( + return wrapWithId( + />, + `msg-${index}` ); case "system": - return ( - + return wrapWithId( + , + `msg-${index}` ); default: return null; diff --git a/packages/vscode-ide-companion/src/webview/components/SearchDialog.tsx b/packages/vscode-ide-companion/src/webview/components/SearchDialog.tsx new file mode 100644 index 00000000..fafd5820 --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/SearchDialog.tsx @@ -0,0 +1,108 @@ +import { useMemo, useCallback, memo } from "react"; +import { User, Bot, Wrench, Info } from "lucide-react"; +import type { SessionMessage } from "@/webview/types"; +import { + Command, + CommandDialog, + CommandInput, + CommandList, + CommandEmpty, + CommandGroup, + CommandItem, + CommandShortcut, +} from "@/webview/components/ui/command"; + +interface SearchDialogProps { + open: boolean; + onOpenChange: (open: boolean) => void; + messages: SessionMessage[]; + onSelectMessage: (messageId: string) => void; +} + +function getRoleIcon(role: string) { + switch (role) { + case "user": + return ; + case "assistant": + return ; + case "tool": + return ; + case "system": + return ; + default: + return null; + } +} + +function getRoleLabel(role: string) { + switch (role) { + case "user": + return "You"; + case "assistant": + return "Assistant"; + case "tool": + return "Tool"; + case "system": + return "System"; + default: + return role; + } +} + +const SearchDialog = memo(function SearchDialog({ open, onOpenChange, messages, onSelectMessage }: SearchDialogProps) { + // Build a flat list of searchable items with their message IDs. + // Only recompute when messages reference changes (shallow compare via React.memo). + const searchableItems = useMemo( + () => + messages + .map((msg, index) => { + const singleLine = (msg.content || "").replace(/\n/g, " "); + const preview = singleLine.length > 80 ? singleLine.slice(0, 80) + "\u2026" : singleLine; + return { + id: msg.id || `msg-${index}`, + role: msg.role, + content: msg.content, + searchValue: `${preview} ${getRoleLabel(msg.role)}`, + index, + preview, + }; + }) + .filter((item) => item.content.trim()), + [messages] + ); + + const handleSelect = useCallback( + (itemId: string) => { + onSelectMessage(itemId); + onOpenChange(false); + }, + [onSelectMessage, onOpenChange] + ); + + return ( + + + + + No messages found. + + {searchableItems.map((item) => ( + handleSelect(item.id)}> +
+ {getRoleIcon(item.role)} +
+ {getRoleLabel(item.role)} + {item.preview} +
+
+ #{item.index + 1} +
+ ))} +
+
+
+
+ ); +}); + +export default SearchDialog; diff --git a/packages/vscode-ide-companion/src/webview/context/ChatProvider.test.tsx b/packages/vscode-ide-companion/src/webview/context/ChatProvider.test.tsx index 009e2cf7..f0b2c900 100644 --- a/packages/vscode-ide-companion/src/webview/context/ChatProvider.test.tsx +++ b/packages/vscode-ide-companion/src/webview/context/ChatProvider.test.tsx @@ -27,6 +27,7 @@ vi.mock("@/webview/services/chatService", () => ({ chatService: { getInitialData: vi.fn().mockResolvedValue(null), getSkills: vi.fn().mockResolvedValue([]), + getSessions: vi.fn().mockResolvedValue([]), sendPrompt: vi.fn().mockResolvedValue({ ok: true }), interrupt: vi.fn().mockResolvedValue({ ok: true }), createNewSession: vi.fn().mockResolvedValue({ sessions: [] }), @@ -1103,3 +1104,236 @@ describe("Message event handling", () => { expect(result.current.state.messages).toHaveLength(1); }); }); + +describe("appReducer - SET_SESSIONS", () => { + beforeEach(() => { + clearMessageHandlers(); + vi.clearAllMocks(); + }); + + it("updates sessions without resetting other state", () => { + const { result } = renderHook(() => useChat(), { + wrapper: createWrapper(), + }); + + const mockSessions = [ + { + id: "s1", + summary: "Session 1", + createTime: "2024-01-01T00:00:00Z", + updateTime: "2024-01-01T00:00:00Z", + status: "idle", + }, + ]; + + act(() => { + result.current.dispatch({ type: "SET_SESSIONS", sessions: mockSessions }); + }); + + expect(result.current.state.sessions).toEqual(mockSessions); + expect(result.current.state.sessions).toHaveLength(1); + // Other state should remain unchanged + expect(result.current.state.activeSessionId).toBeNull(); + expect(result.current.state.messages).toEqual([]); + expect(result.current.state.loading).toBe(false); + }); + + it("replaces existing sessions with new list", () => { + const { result } = renderHook(() => useChat(), { + wrapper: createWrapper(), + }); + + const initialSessions = [ + { + id: "s1", + summary: "Old Session", + createTime: "2024-01-01T00:00:00Z", + updateTime: "2024-01-01T00:00:00Z", + status: "idle", + }, + ]; + + const newSessions = [ + { + id: "s2", + summary: "New Session", + createTime: "2024-01-02T00:00:00Z", + updateTime: "2024-01-02T00:00:00Z", + status: "processing", + }, + { + id: "s3", + summary: "Another", + createTime: "2024-01-03T00:00:00Z", + updateTime: "2024-01-03T00:00:00Z", + status: "idle", + }, + ]; + + act(() => { + result.current.dispatch({ type: "SET_SESSIONS", sessions: initialSessions }); + }); + + expect(result.current.state.sessions).toHaveLength(1); + + act(() => { + result.current.dispatch({ type: "SET_SESSIONS", sessions: newSessions }); + }); + + expect(result.current.state.sessions).toEqual(newSessions); + expect(result.current.state.sessions).toHaveLength(2); + }); +}); + +describe("appReducer - SET_ACTIVE_SESSION_ID", () => { + beforeEach(() => { + clearMessageHandlers(); + vi.clearAllMocks(); + }); + + it("sets activeSessionId to a valid session ID", () => { + const { result } = renderHook(() => useChat(), { + wrapper: createWrapper(), + }); + + act(() => { + result.current.dispatch({ type: "SET_ACTIVE_SESSION_ID", sessionId: "session-xyz" }); + }); + + expect(result.current.state.activeSessionId).toBe("session-xyz"); + }); + + it("does not affect sessions or messages", () => { + const { result } = renderHook(() => useChat(), { + wrapper: createWrapper(), + }); + + // Preload some messages + act(() => { + result.current.dispatch({ type: "USER_MESSAGE", content: "Hello" }); + }); + + act(() => { + result.current.dispatch({ type: "SET_ACTIVE_SESSION_ID", sessionId: "session-123" }); + }); + + expect(result.current.state.activeSessionId).toBe("session-123"); + expect(result.current.state.messages).toHaveLength(1); + expect(result.current.state.loading).toBe(false); + }); +}); + +describe("sendPrompt action - activeSessionId syncing", () => { + beforeEach(() => { + clearMessageHandlers(); + vi.clearAllMocks(); + }); + + it("sets activeSessionId when creating a new session from empty state", async () => { + const { chatService: mockChatService } = await import("@/webview/services/chatService"); + + vi.mocked(mockChatService.sendPrompt).mockResolvedValue({ ok: true, sessionId: "new-session-id" }); + vi.mocked(mockChatService.getSessions).mockResolvedValue([ + { + id: "new-session-id", + summary: "Untitled", + createTime: "2024-01-01T00:00:00Z", + updateTime: "2024-01-01T00:00:00Z", + status: "processing", + }, + ]); + vi.mocked(mockChatService.getSkills).mockResolvedValue([]); + + const { result } = renderHook(() => useChat(), { + wrapper: createWrapper(), + }); + + // Initially no active session + expect(result.current.state.activeSessionId).toBeNull(); + + // Send a prompt (creates a new session) + await act(async () => { + await result.current.actions.sendPrompt("Hello world"); + }); + + expect(result.current.state.activeSessionId).toBe("new-session-id"); + expect(mockChatService.sendPrompt).toHaveBeenCalledTimes(1); + }); + + it("keeps existing activeSessionId when already set", async () => { + const { chatService: mockChatService } = await import("@/webview/services/chatService"); + + vi.mocked(mockChatService.sendPrompt).mockResolvedValue({ ok: true, sessionId: "existing-session" }); + vi.mocked(mockChatService.getSessions).mockResolvedValue([]); + vi.mocked(mockChatService.getSkills).mockResolvedValue([]); + + const { result } = renderHook(() => useChat(), { + wrapper: createWrapper(), + }); + + // Pre-set active session + act(() => { + result.current.dispatch({ type: "SET_ACTIVE_SESSION_ID", sessionId: "existing-session" }); + }); + + expect(result.current.state.activeSessionId).toBe("existing-session"); + + await act(async () => { + await result.current.actions.sendPrompt("Second message"); + }); + + // activeSessionId should remain unchanged + expect(result.current.state.activeSessionId).toBe("existing-session"); + }); + + it("refreshes sessions and skills after sending prompt", async () => { + const { chatService: mockChatService } = await import("@/webview/services/chatService"); + + vi.mocked(mockChatService.sendPrompt).mockResolvedValue({ ok: true, sessionId: "session-1" }); + vi.mocked(mockChatService.getSessions).mockResolvedValue([ + { + id: "session-1", + summary: "After prompt", + createTime: "2024-01-01T00:00:00Z", + updateTime: "2024-01-01T00:00:00Z", + status: "processing", + }, + ]); + vi.mocked(mockChatService.getSkills).mockResolvedValue([{ name: "skill1" }]); + + const { result } = renderHook(() => useChat(), { + wrapper: createWrapper(), + }); + + await act(async () => { + await result.current.actions.sendPrompt("Hello"); + }); + + expect(mockChatService.getSessions).toHaveBeenCalledTimes(1); + expect(mockChatService.getSkills).toHaveBeenCalledTimes(1); + expect(result.current.state.sessions).toHaveLength(1); + expect(result.current.state.skills).toEqual([{ name: "skill1" }]); + }); + + it("does not set activeSessionId when sendPrompt returns no sessionId", async () => { + const { chatService: mockChatService } = await import("@/webview/services/chatService"); + + // sendPrompt returns without sessionId (e.g. for /continue) + vi.mocked(mockChatService.sendPrompt).mockResolvedValue({ ok: true }); + vi.mocked(mockChatService.getSessions).mockResolvedValue([]); + vi.mocked(mockChatService.getSkills).mockResolvedValue([]); + + const { result } = renderHook(() => useChat(), { + wrapper: createWrapper(), + }); + + expect(result.current.state.activeSessionId).toBeNull(); + + await act(async () => { + await result.current.actions.sendPrompt("/continue"); + }); + + // No sessionId returned → activeSessionId stays null + expect(result.current.state.activeSessionId).toBeNull(); + }); +}); diff --git a/packages/vscode-ide-companion/src/webview/context/ChatProvider.tsx b/packages/vscode-ide-companion/src/webview/context/ChatProvider.tsx index 1fb18321..0dcea4b9 100644 --- a/packages/vscode-ide-companion/src/webview/context/ChatProvider.tsx +++ b/packages/vscode-ide-companion/src/webview/context/ChatProvider.tsx @@ -43,6 +43,7 @@ interface ChatContextValue { dismissContinuePrompt: () => void; continueGeneration: () => Promise; toggleSessionList: (open?: boolean) => void; + toggleSearchPanel: (open?: boolean) => void; }; } @@ -72,6 +73,7 @@ const initialState: AppState = { askUserQuestions: null, showContinuePrompt: false, sessionListOpen: false, + searchPanelOpen: false, }; function appReducer(state: AppState, action: AppAction): AppState { @@ -175,8 +177,12 @@ function appReducer(state: AppState, action: AppAction): AppState { return { ...state, askUserQuestions: action.data }; case "DISMISS_CONTINUE_PROMPT": return { ...state, showContinuePrompt: false }; + case "SET_ACTIVE_SESSION_ID": + return { ...state, activeSessionId: action.sessionId }; case "TOGGLE_SESSION_LIST": return { ...state, sessionListOpen: action.open !== undefined ? action.open : !state.sessionListOpen }; + case "TOGGLE_SEARCH_PANEL": + return { ...state, searchPanelOpen: action.open !== undefined ? action.open : !state.searchPanelOpen }; default: return state; } @@ -193,6 +199,10 @@ interface ChatProviderProps { export function ChatProvider({ children }: ChatProviderProps) { const [state, dispatch] = useReducer(appReducer, initialState); + // Ref to track current activeSessionId for use in stable callbacks + const activeSessionIdRef = useRef(null); + activeSessionIdRef.current = state.activeSessionId; + // Load initial data via RPC const { data: initialData } = wrpc.useQuery("getInitialData"); @@ -322,8 +332,9 @@ export function ChatProvider({ children }: ChatProviderProps) { } ) => { dispatch({ type: "SET_LOADING", loading: true }); + let sessionId: string | undefined; try { - await chatService.sendPrompt({ + const result = await chatService.sendPrompt({ prompt, skills, images, @@ -332,10 +343,20 @@ export function ChatProvider({ children }: ChatProviderProps) { planMode: options?.planMode || false, askUserQuestionSummary: options?.askUserQuestionSummary || false, }); + sessionId = result.sessionId; } catch (err) { console.error("[ChatProvider] sendPrompt failed:", err); dispatch({ type: "SET_LOADING", loading: false }); } + // If a new session was just created (no active session before), set it + if (sessionId && !activeSessionIdRef.current) { + dispatch({ type: "SET_ACTIVE_SESSION_ID", sessionId }); + } + // Refresh sessions list (e.g. new session created by first message) + const freshSessions = await chatService.getSessions(); + if (freshSessions.length > 0) { + dispatch({ type: "SET_SESSIONS", sessions: freshSessions }); + } const freshSkills = await chatService.getSkills(); if (freshSkills.length > 0) { dispatch({ type: "SET_SKILLS", skills: freshSkills }); @@ -433,6 +454,10 @@ export function ChatProvider({ children }: ChatProviderProps) { dispatch({ type: "TOGGLE_SESSION_LIST", open }); }, []); + const toggleSearchPanel = useCallback((open?: boolean) => { + dispatch({ type: "TOGGLE_SEARCH_PANEL", open }); + }, []); + const contextValue: ChatContextValue = { state, dispatch, @@ -449,6 +474,7 @@ export function ChatProvider({ children }: ChatProviderProps) { dismissContinuePrompt, continueGeneration, toggleSessionList, + toggleSearchPanel, }, }; diff --git a/packages/vscode-ide-companion/src/webview/index.css b/packages/vscode-ide-companion/src/webview/index.css index d3ba88c0..888a710a 100644 --- a/packages/vscode-ide-companion/src/webview/index.css +++ b/packages/vscode-ide-companion/src/webview/index.css @@ -181,3 +181,13 @@ background-position: -120% 0; } } + +@keyframes msg-highlight-breathe { + 0%, 100% { background-color: transparent; } + 50% { background-color: rgba(77, 107, 254, 0.12); } +} + +.msg-highlight-breathe { + animation: msg-highlight-breathe 0.8s ease-in-out 3; + border-radius: 0.5rem; +} diff --git a/packages/vscode-ide-companion/src/webview/services/chatService.test.ts b/packages/vscode-ide-companion/src/webview/services/chatService.test.ts index 72bd8346..7e7aa43e 100644 --- a/packages/vscode-ide-companion/src/webview/services/chatService.test.ts +++ b/packages/vscode-ide-companion/src/webview/services/chatService.test.ts @@ -21,6 +21,9 @@ vi.mock("@/webview/wrpc", () => ({ getSkills: { query: vi.fn(), }, + getSessions: { + query: vi.fn(), + }, sendPrompt: { mutate: vi.fn(), }, @@ -112,7 +115,7 @@ describe("chatService", () => { describe("sendPrompt", () => { it("sends prompt with all options", async () => { - vi.mocked(wrpc.sendPrompt.mutate).mockResolvedValue({ ok: true } as any); + vi.mocked(wrpc.sendPrompt.mutate).mockResolvedValue({ ok: true, sessionId: "new-session-1" } as any); const result = await chatService.sendPrompt({ prompt: "Hello", @@ -122,7 +125,7 @@ describe("chatService", () => { alwaysAllows: ["read-in-cwd"], }); - expect(result).toEqual({ ok: true }); + expect(result).toEqual({ ok: true, sessionId: "new-session-1" }); expect(wrpc.sendPrompt.mutate).toHaveBeenCalledWith({ prompt: "Hello", skills: [{ name: "skill1" }], @@ -170,6 +173,14 @@ describe("chatService", () => { expect(result).toEqual({ ok: false, error: "Network error" }); }); + + it("returns sessionId from the server response", async () => { + vi.mocked(wrpc.sendPrompt.mutate).mockResolvedValue({ ok: true, sessionId: "session-abc" } as any); + + const result = await chatService.sendPrompt({ prompt: "Create a session" }); + + expect(result.sessionId).toBe("session-abc"); + }); }); describe("createNewSession", () => { @@ -281,6 +292,37 @@ describe("chatService", () => { }); }); + describe("getSessions", () => { + it("returns sessions array when available", async () => { + const mockSessions = [ + { id: "s1", summary: "Session 1", createTime: "2024-01-01", updateTime: "2024-01-01", status: "idle" }, + { id: "s2", summary: "Session 2", createTime: "2024-01-02", updateTime: "2024-01-02", status: "processing" }, + ]; + vi.mocked(wrpc.getSessions.query).mockResolvedValue({ sessions: mockSessions } as any); + + const result = await chatService.getSessions(); + + expect(result).toEqual(mockSessions); + expect(wrpc.getSessions.query).toHaveBeenCalledTimes(1); + }); + + it("returns empty array when no sessions", async () => { + vi.mocked(wrpc.getSessions.query).mockResolvedValue(null as any); + + const result = await chatService.getSessions(); + + expect(result).toEqual([]); + }); + + it("returns empty array when result has no sessions field", async () => { + vi.mocked(wrpc.getSessions.query).mockResolvedValue({} as any); + + const result = await chatService.getSessions(); + + expect(result).toEqual([]); + }); + }); + describe("showAlert", () => { it("shows alert message and returns ok", async () => { vi.mocked(wrpc.showAlert.mutate).mockResolvedValue({ ok: true } as any); diff --git a/packages/vscode-ide-companion/src/webview/services/chatService.ts b/packages/vscode-ide-companion/src/webview/services/chatService.ts index e591c1a2..a65094bd 100644 --- a/packages/vscode-ide-companion/src/webview/services/chatService.ts +++ b/packages/vscode-ide-companion/src/webview/services/chatService.ts @@ -77,10 +77,18 @@ export const chatService = { return (result?.skills as SkillInfo[]) ?? []; }, + /** + * Get list of all sessions + */ + async getSessions(): Promise { + const result = await wrpc.getSessions.query(); + return (result?.sessions as SessionSummary[]) ?? []; + }, + /** * Send a prompt to the chat */ - async sendPrompt(options: SendPromptOptions): Promise<{ ok: boolean; error?: string }> { + async sendPrompt(options: SendPromptOptions): Promise<{ ok: boolean; error?: string; sessionId?: string }> { const normalizedImages = (options.images ?? []).filter(Boolean); console.log("options:", options); const result = await wrpc.sendPrompt.mutate({ @@ -93,7 +101,7 @@ export const chatService = { askUserQuestionSummary: options.askUserQuestionSummary, }); - return result as { ok: boolean; error?: string }; + return result as { ok: boolean; error?: string; sessionId?: string }; }, /** @@ -162,7 +170,7 @@ export const chatService = { */ async addSystemMessage(content: string, meta?: Record): Promise<{ ok: boolean; error?: string }> { const result = await wrpc.addSystemMessage.mutate({ content, meta }); - return result as { ok: boolean; error?: string }; + return result as { ok: boolean; error?: string; sessionId?: string }; }, /** @@ -170,7 +178,7 @@ export const chatService = { */ async renameSession(sessionId: string, summary: string): Promise<{ ok: boolean; error?: string }> { const result = await wrpc.renameSession.mutate({ sessionId, summary }); - return result as { ok: boolean; error?: string }; + return result as { ok: boolean; error?: string; sessionId?: string }; }, /** diff --git a/packages/vscode-ide-companion/src/webview/types.ts b/packages/vscode-ide-companion/src/webview/types.ts index a8d21f66..1282c9d8 100644 --- a/packages/vscode-ide-companion/src/webview/types.ts +++ b/packages/vscode-ide-companion/src/webview/types.ts @@ -116,6 +116,7 @@ export interface AppState { askUserQuestions: AskUserQuestionData | null; showContinuePrompt: boolean; sessionListOpen: boolean; + searchPanelOpen: boolean; } // --- App actions --- @@ -155,4 +156,6 @@ export type AppAction = | { type: "SET_EDITING_MESSAGE"; editingMessage: EditingMessage | null } | { type: "SET_ASK_USER_QUESTIONS"; data: AskUserQuestionData | null } | { type: "DISMISS_CONTINUE_PROMPT" } - | { type: "TOGGLE_SESSION_LIST"; open?: boolean }; + | { type: "SET_ACTIVE_SESSION_ID"; sessionId: string } + | { type: "TOGGLE_SESSION_LIST"; open?: boolean } + | { type: "TOGGLE_SEARCH_PANEL"; open?: boolean }; From b222e1650ac4607852b6e03a707015a18631db26 Mon Sep 17 00:00:00 2001 From: hcyang Date: Wed, 22 Jul 2026 17:08:06 +0800 Subject: [PATCH 45/51] =?UTF-8?q?refactor(ui):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E7=95=8C=E9=9D=A2=E7=BB=84=E4=BB=B6=E7=BB=86=E8=8A=82=E5=92=8C?= =?UTF-8?q?=E6=90=9C=E7=B4=A2=E4=BD=93=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 调整 ContinuePrompt 和 PermissionPrompt 中按钮尺寸为更小图标尺寸,提升界面一致性 - 优化 Messages 组件滚动定位逻辑,加入 IntersectionObserver 确保消息完全可见后应用高亮 - 增加对 IntersectionObserver 及超时清理的支持,防止资源泄漏 - 调整 Messages 组件滚动区域和消息容器样式,修改内边距和宽度管理 - SearchDialog 组件中根据可见性过滤消息,改进搜索结果准确性并美化结果列表显示 - SessionList 组件中搜索输入框和编辑输入框样式优化,更新按钮样式提升交互体验 - 在消息类型定义中新增多字段支持,包含时间戳和参数字段,为扩展功能做准备 --- .../src/webview/components/ContinuePrompt.tsx | 4 +- .../src/webview/components/Messages.tsx | 93 +++++++++++++++++-- .../webview/components/PermissionPrompt.tsx | 8 +- .../src/webview/components/SearchDialog.tsx | 28 ++++-- .../src/webview/components/SessionList.tsx | 7 +- .../vscode-ide-companion/src/webview/types.ts | 6 ++ 6 files changed, 117 insertions(+), 29 deletions(-) diff --git a/packages/vscode-ide-companion/src/webview/components/ContinuePrompt.tsx b/packages/vscode-ide-companion/src/webview/components/ContinuePrompt.tsx index 6a78bd6d..4ed36fa6 100644 --- a/packages/vscode-ide-companion/src/webview/components/ContinuePrompt.tsx +++ b/packages/vscode-ide-companion/src/webview/components/ContinuePrompt.tsx @@ -14,7 +14,7 @@ export default function ContinuePrompt({ onContinue, onDismiss }: ContinuePrompt Session interrupted
diff --git a/packages/vscode-ide-companion/src/webview/components/Messages.tsx b/packages/vscode-ide-companion/src/webview/components/Messages.tsx index 07a043ae..12178f96 100644 --- a/packages/vscode-ide-companion/src/webview/components/Messages.tsx +++ b/packages/vscode-ide-companion/src/webview/components/Messages.tsx @@ -29,6 +29,8 @@ const Messages = forwardRef( const bottomRef = useRef(null); const suppressScrollRef = useRef(false); const highlightedElRef = useRef(null); + const observerRef = useRef(null); + const observerFallbackRef = useRef | null>(null); const handleToBottom = () => { bottomRef.current?.scrollIntoView({ behavior: "smooth" }); @@ -40,19 +42,57 @@ const Messages = forwardRef( } }, [messages, loading]); + // Cleanup observer on unmount + useEffect(() => { + return () => { + if (observerRef.current) { + observerRef.current.disconnect(); + } + if (observerFallbackRef.current) { + clearTimeout(observerFallbackRef.current); + } + }; + }, []); + useImperativeHandle(ref, () => ({ scrollToMessage: (messageId: string) => { suppressScrollRef.current = true; + // Clean up previous observer and fallback timer + if (observerRef.current) { + observerRef.current.disconnect(); + observerRef.current = null; + } + if (observerFallbackRef.current) { + clearTimeout(observerFallbackRef.current); + observerFallbackRef.current = null; + } + // Remove highlight from previously highlighted element if (highlightedElRef.current) { highlightedElRef.current.classList.remove("msg-highlight-breathe"); + highlightedElRef.current = null; } const el = document.querySelector(`[data-message-id="${messageId}"]`); - if (el) { - el.scrollIntoView({ behavior: "smooth", block: "center" }); - // Apply breathing light effect + if (!el) { + setTimeout(() => { + suppressScrollRef.current = false; + }, 500); + return; + } + + // Scroll the element into view first (smooth) + el.scrollIntoView({ behavior: "smooth", block: "center" }); + + // Get the scrollable viewport as the IntersectionObserver root + const viewport = scrollAreaRef.current?.querySelector("[data-radix-scroll-area-viewport]") || null; + + let highlightApplied = false; + + const applyHighlight = () => { + if (highlightApplied) return; + highlightApplied = true; el.classList.add("msg-highlight-breathe"); highlightedElRef.current = el; // Remove the class after animation completes (3 iterations * 0.8s) @@ -62,7 +102,43 @@ const Messages = forwardRef( highlightedElRef.current = null; } }, 2600); - } + }; + + // Use IntersectionObserver to wait until the element is fully visible + const observer = new IntersectionObserver( + (entries) => { + for (const entry of entries) { + if (entry.intersectionRatio >= 0.99) { + // Clear fallback timer + if (observerFallbackRef.current) { + clearTimeout(observerFallbackRef.current); + observerFallbackRef.current = null; + } + applyHighlight(); + observer.disconnect(); + observerRef.current = null; + return; + } + } + }, + { + root: viewport, + threshold: [0.99], + } + ); + + observer.observe(el); + observerRef.current = observer; + + // Fallback: if the element never becomes fully visible within 2s + // (e.g., element is too large to fit), apply animation anyway + observerFallbackRef.current = setTimeout(() => { + if (observerRef.current) { + observerRef.current.disconnect(); + observerRef.current = null; + } + applyHighlight(); + }, 2000); // Re-enable auto-scroll after a delay setTimeout(() => { @@ -85,19 +161,16 @@ const Messages = forwardRef( return ( { - console.log("eeeee", e); - }} - className="flex-1 w-full max-w-237.5 mx-auto min-w-sm min-h-0 overflow-hidden" + className="flex-1 w-full max-w-237.5 mx-auto min-w-sm min-h-0 px-4 overflow-hidden" > -
+
{messages.map((msg, index) => { const prevMsg = index > 0 ? messages[index - 1] : null; const shouldConnect = prevMsg ? prevMsg.role !== "user" && msg.role !== "user" : false; const msgId = msg.id || `msg-${index}`; const wrapWithId = (element: React.ReactNode, key: string) => ( -
+
{element}
); diff --git a/packages/vscode-ide-companion/src/webview/components/PermissionPrompt.tsx b/packages/vscode-ide-companion/src/webview/components/PermissionPrompt.tsx index 5c518e2a..22ad43d9 100644 --- a/packages/vscode-ide-companion/src/webview/components/PermissionPrompt.tsx +++ b/packages/vscode-ide-companion/src/webview/components/PermissionPrompt.tsx @@ -259,7 +259,7 @@ export default function PermissionPrompt({
- {canAlwaysAllow && ( - )} -
diff --git a/packages/vscode-ide-companion/src/webview/components/SearchDialog.tsx b/packages/vscode-ide-companion/src/webview/components/SearchDialog.tsx index fafd5820..551073ef 100644 --- a/packages/vscode-ide-companion/src/webview/components/SearchDialog.tsx +++ b/packages/vscode-ide-companion/src/webview/components/SearchDialog.tsx @@ -22,13 +22,13 @@ interface SearchDialogProps { function getRoleIcon(role: string) { switch (role) { case "user": - return ; + return ; case "assistant": - return ; + return ; case "tool": - return ; + return ; case "system": - return ; + return ; default: return null; } @@ -50,6 +50,7 @@ function getRoleLabel(role: string) { } const SearchDialog = memo(function SearchDialog({ open, onOpenChange, messages, onSelectMessage }: SearchDialogProps) { + console.log("messages:", messages); // Build a flat list of searchable items with their message IDs. // Only recompute when messages reference changes (shallow compare via React.memo). const searchableItems = useMemo( @@ -63,11 +64,13 @@ const SearchDialog = memo(function SearchDialog({ open, onOpenChange, messages, role: msg.role, content: msg.content, searchValue: `${preview} ${getRoleLabel(msg.role)}`, + visible: msg.visible, + createTime: msg.createTime, index, preview, }; }) - .filter((item) => item.content.trim()), + .filter((item) => item.visible && item.content.trim()), [messages] ); @@ -82,16 +85,21 @@ const SearchDialog = memo(function SearchDialog({ open, onOpenChange, messages, return ( - + No messages found. {searchableItems.map((item) => ( - handleSelect(item.id)}> + handleSelect(item.id)}>
- {getRoleIcon(item.role)} -
- {getRoleLabel(item.role)} +
{getRoleIcon(item.role)}
+
+
+ {getRoleLabel(item.role)} + + {new Date(item.createTime || 0).toLocaleString()} + +
{item.preview}
diff --git a/packages/vscode-ide-companion/src/webview/components/SessionList.tsx b/packages/vscode-ide-companion/src/webview/components/SessionList.tsx index 5e70d785..953507a4 100644 --- a/packages/vscode-ide-companion/src/webview/components/SessionList.tsx +++ b/packages/vscode-ide-companion/src/webview/components/SessionList.tsx @@ -217,7 +217,7 @@ export default function SessionList({ console.error("Failed to open chat panel:", err); } }, - [onSelect, onCreateNewSession, handleCloseDrawer, activeSessionId] + [onCreateNewSession, handleCloseDrawer, activeSessionId] ); const handleInspectJsonl = useCallback(async (sessionId: string) => { @@ -314,6 +314,7 @@ export default function SessionList({ Sessions setQuery(e.target.value)} @@ -357,7 +358,7 @@ export default function SessionList({ ref={editInputRef} autoFocus placeholder="Enter new session title" - className="flex-1 h-10 bg-transparent border-b shadow-none outline-0 border-primary outline-none text-xs px-1 py-0" + className="flex-1 h-10 bg-transparent rounded border-b shadow-none outline-0 border-primary outline-none text-xs px-1 py-0" value={editValue} onChange={(e) => setEditValue(e.target.value)} onKeyDown={(e) => handleRenameKeyDown(e, s.id)} @@ -488,7 +489,7 @@ export default function SessionList({
- diff --git a/packages/vscode-ide-companion/src/webview/types.ts b/packages/vscode-ide-companion/src/webview/types.ts index 1282c9d8..a0ba282d 100644 --- a/packages/vscode-ide-companion/src/webview/types.ts +++ b/packages/vscode-ide-companion/src/webview/types.ts @@ -9,6 +9,12 @@ export interface SessionMessage { content: string; meta?: MessageMeta; visible?: boolean; + checkpointHash?: string; + compacted?: boolean; + contentParams?: Record; + messageParams?: Record; + createTime?: string; + updateTime?: string; } // --- Editing state --- From 95a72c610f667a292a7a0554f3806a30986ca1fc Mon Sep 17 00:00:00 2001 From: hcyang Date: Thu, 23 Jul 2026 10:23:37 +0800 Subject: [PATCH 46/51] =?UTF-8?q?feat(webview):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E8=BE=93=E5=85=A5=E6=8F=90=E7=A4=BA=E5=92=8C=E6=8A=80=E8=83=BD?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=EF=BC=8C=E5=AE=8C=E5=96=84=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E7=B2=98=E8=B4=B4=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 调整ContinuePrompt和PermissionPrompt组件顶部内边距为pt-2替代py-2 - 新增ATTACHMENT_LABEL和ATTACHMENT_PASTE_MAX常量以统一管理粘贴图片标签和大小限制 - usePromptAttachments支持最大粘贴图片数量限制和超额提示回调,改进粘贴事件逻辑 - InputPrompt新增技能加载动画和激活技能列表展示 - 输入区域优化判断是否含内容逻辑,提升性能 - 优化停止按钮样式和交互 - Messages组件无内容视图添加左右内边距,文本居中显示 - 技能相关组件SkillsPanel和SkillsTags统一使用toTitleCase展示技能名 - toTitleCase函数支持连字符、空格和下划线分隔,智能识别API、ID等缩略词 - router中默认显示提示改为ATTACHMENT_LABEL统一标签显示 - ThemeProvider统一React导入格式,提升代码规范性 --- packages/vscode-ide-companion/src/router.ts | 3 +- .../src/webview/components/ContinuePrompt.tsx | 2 +- .../src/webview/components/InputPrompt.tsx | 51 ++++++++-- .../src/webview/components/Messages.tsx | 6 +- .../webview/components/PermissionPrompt.tsx | 2 +- .../src/webview/components/SkillsPanel.tsx | 3 +- .../src/webview/components/SkillsTags.tsx | 3 +- .../src/webview/constants/index.ts | 9 ++ .../src/webview/context/ThemeProvider.tsx | 2 +- .../src/webview/hooks/usePromptAttachments.ts | 92 ++++++++++++++----- .../src/webview/utils/index.ts | 32 ++++++- .../src/webview/utils/utils.test.ts | 11 ++- 12 files changed, 164 insertions(+), 52 deletions(-) create mode 100644 packages/vscode-ide-companion/src/webview/constants/index.ts diff --git a/packages/vscode-ide-companion/src/router.ts b/packages/vscode-ide-companion/src/router.ts index 9e3eb518..4bedeff0 100644 --- a/packages/vscode-ide-companion/src/router.ts +++ b/packages/vscode-ide-companion/src/router.ts @@ -5,6 +5,7 @@ import * as vscodeApi from "vscode"; import z from "zod"; import { getProjectCode } from "@vegamo/deepcode-core"; import type { SessionManager, SkillInfo, UserToolPermission, PermissionScope } from "@vegamo/deepcode-core"; +import { ATTACHMENT_LABEL } from "@/webview/constants"; export interface RouterContext { sessionManager: SessionManager; @@ -144,7 +145,7 @@ export const appRouter = router({ return { ok: false, error: "Empty prompt" }; } - const displayPrompt = prompt || (normalizedImages.length > 0 ? "粘贴的图像" : ""); + const displayPrompt = prompt || (normalizedImages.length > 0 ? ATTACHMENT_LABEL : ""); const promptTrimmed = prompt.trim(); const isPermissionContinue = promptTrimmed === "/continue" && diff --git a/packages/vscode-ide-companion/src/webview/components/ContinuePrompt.tsx b/packages/vscode-ide-companion/src/webview/components/ContinuePrompt.tsx index 4ed36fa6..cd97d4f6 100644 --- a/packages/vscode-ide-companion/src/webview/components/ContinuePrompt.tsx +++ b/packages/vscode-ide-companion/src/webview/components/ContinuePrompt.tsx @@ -8,7 +8,7 @@ export interface ContinuePromptProps { export default function ContinuePrompt({ onContinue, onDismiss }: ContinuePromptProps) { return ( -
+
Session interrupted diff --git a/packages/vscode-ide-companion/src/webview/components/InputPrompt.tsx b/packages/vscode-ide-companion/src/webview/components/InputPrompt.tsx index cf8252cb..f2dc6f91 100644 --- a/packages/vscode-ide-companion/src/webview/components/InputPrompt.tsx +++ b/packages/vscode-ide-companion/src/webview/components/InputPrompt.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useRef, useState } from "react"; +import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"; import SkillsPanel from "@/webview/components/SkillsPanel"; import SkillsTags from "@/webview/components/SkillsTags"; import ContextIndicator from "@/webview/components/ContextIndicator"; @@ -22,6 +22,8 @@ import { } from "@/webview/components/ui/dropdown-menu"; import { Item, ItemContent, ItemDescription, ItemMedia, ItemTitle } from "@/webview/components/ui/item"; import { usePromptAttachments } from "@/webview/hooks/usePromptAttachments"; +import { toTitleCase } from "@/webview/utils"; +import { toast } from "@/webview/components/ui/sonner"; export interface InputPromptProps { loading: boolean; @@ -69,7 +71,11 @@ export default function InputPrompt({ const [draftBeforeHistory, setDraftBeforeHistory] = useState(""); const textareaRef = useRef(null); const { attachments, handlePaste, removeAttachment, clearAttachments, getImageUrls, loadImages } = - usePromptAttachments(); + usePromptAttachments({ + onMaxExceeded: () => { + toast.warning("You can paste up to 10 images at a time", { position: "top-center" }); + }, + }); // Rebuild history from messages when messages change (e.g., loading a session) useEffect(() => { @@ -210,11 +216,42 @@ export default function InputPrompt({ [handleSend, history, historyIdx, value, draftBeforeHistory] ); - const hasContent = value.trim().length > 0 || attachments.length > 0; + /** + * Get the active skill badge to display when skills are loading + */ + const getActiveSkill = useCallback(() => { + if (loading && availableSkills.length > 0 && availableSkills.filter((x) => x.isLoaded).length > 0) { + return ( +
+ {availableSkills + .filter((x) => x.isLoaded) + .map((skill) => ( +
+ + + + + {toTitleCase(skill.name)} +
+ ))} +
+ ); + } + return null; + }, [loading, availableSkills]); + + /** + * Determine if the input has content (text or attachments) + */ + const hasContent = useMemo(() => value.trim().length > 0 || attachments.length > 0, [value, attachments]); return ( + {getActiveSkill()}
{loading ? ( - + diff --git a/packages/vscode-ide-companion/src/webview/components/Messages.tsx b/packages/vscode-ide-companion/src/webview/components/Messages.tsx index 12178f96..6c5c45bf 100644 --- a/packages/vscode-ide-companion/src/webview/components/Messages.tsx +++ b/packages/vscode-ide-companion/src/webview/components/Messages.tsx @@ -149,10 +149,10 @@ const Messages = forwardRef( if (messages.length === 0) { return ( -
+
-
Welcome to the Deep Code AI IDE!
-

+

Welcome to the Deep Code AI IDE!
+

What would you like to do? Ask about this codebase or we can start writing code.

diff --git a/packages/vscode-ide-companion/src/webview/components/PermissionPrompt.tsx b/packages/vscode-ide-companion/src/webview/components/PermissionPrompt.tsx index 22ad43d9..f9642a7d 100644 --- a/packages/vscode-ide-companion/src/webview/components/PermissionPrompt.tsx +++ b/packages/vscode-ide-companion/src/webview/components/PermissionPrompt.tsx @@ -248,7 +248,7 @@ export default function PermissionPrompt({ const canAlwaysAllow = VALID_SCOPES.includes(prompt.scope); return ( -
+
diff --git a/packages/vscode-ide-companion/src/webview/components/SkillsPanel.tsx b/packages/vscode-ide-companion/src/webview/components/SkillsPanel.tsx index f9e5a6ec..749b75b3 100644 --- a/packages/vscode-ide-companion/src/webview/components/SkillsPanel.tsx +++ b/packages/vscode-ide-companion/src/webview/components/SkillsPanel.tsx @@ -11,6 +11,7 @@ import { CommandList, } from "@/webview/components/ui/command"; import { GraduationCap } from "lucide-react"; +import { toTitleCase } from "@/webview/utils"; interface SkillsPanelProps { availableSkills: SkillInfo[]; @@ -52,7 +53,7 @@ export default function SkillsPanel({ availableSkills, selectedSkills, onToggle title={skill.path} > - {skill.name} + {toTitleCase(skill.name)} {skill.path} ); diff --git a/packages/vscode-ide-companion/src/webview/components/SkillsTags.tsx b/packages/vscode-ide-companion/src/webview/components/SkillsTags.tsx index 62015b3a..0099d331 100644 --- a/packages/vscode-ide-companion/src/webview/components/SkillsTags.tsx +++ b/packages/vscode-ide-companion/src/webview/components/SkillsTags.tsx @@ -3,6 +3,7 @@ import type { SkillInfo } from "@/webview/types"; import { X } from "lucide-react"; import { InputGroupAddon } from "./ui/input-group"; import { Button } from "./ui/button"; +import { toTitleCase } from "@/webview/utils"; interface SkillsTagsProps { selectedSkills: SkillInfo[]; @@ -16,7 +17,7 @@ export default function SkillsTags({ selectedSkills, onRemove }: SkillsTagsProps {selectedSkills.map((skill) => ( - {skill.name} + {toTitleCase(skill.name)} + ) + ), +})); + +vi.mock("./ui/collapsible", () => ({ + Collapsible: vi.fn( + ({ children, open }: { children: React.ReactNode; open: boolean; onOpenChange?: (open: boolean) => void }) => ( +
+ {children} +
+ ) + ), + CollapsibleContent: vi.fn(({ children }: { children: React.ReactNode }) => ( +
{children}
+ )), + CollapsibleTrigger: vi.fn(({ children }: { children: React.ReactNode }) => ( +
{children}
+ )), +})); + +vi.mock("./ui/field", () => ({ + Field: vi.fn(({ children }: { children: React.ReactNode }) =>
{children}
), + FieldContent: vi.fn(({ children }: { children: React.ReactNode }) => ( +
{children}
+ )), + FieldDescription: vi.fn(({ children }: { children: React.ReactNode }) => ( +
{children}
+ )), + FieldError: vi.fn(() => null), + FieldGroup: vi.fn(({ children }: { children: React.ReactNode }) =>
{children}
), + FieldLabel: vi.fn(({ children, htmlFor }: { children: React.ReactNode; htmlFor?: string }) => ( + + )), +})); + +vi.mock("./ui/checkbox", () => ({ + Checkbox: vi.fn( + ({ + id, + checked, + onCheckedChange, + }: { + id: string; + checked: boolean; + onCheckedChange?: (checked: boolean) => void; + }) => ( + onCheckedChange?.(e.target.checked)} + /> + ) + ), +})); + +vi.mock("./ui/radio-group", () => ({ + RadioGroup: vi.fn( + ({ children, value }: { children: React.ReactNode; value?: string; onValueChange?: (val: string) => void }) => ( +
+ {children} +
+ ) + ), + RadioGroupItem: vi.fn(({ value, id }: { value: string; id: string }) => ( + + )), +})); + +vi.mock("./ui/input", () => ({ + Input: vi.fn(({ placeholder, ...props }: { placeholder?: string; [key: string]: unknown }) => ( + + )), +})); + +vi.mock("lucide-react", () => ({ + ChevronDownIcon: vi.fn(() => ), + ChevronLeft: vi.fn(() => ), + ChevronRight: vi.fn(() => ), + X: vi.fn(() => ), +})); + +interface Question { + question: string; + multiSelect: boolean; + options: Array<{ label: string; description?: string }>; +} + +const singleSelectQuestion: Question = { + question: "Which framework?", + multiSelect: false, + options: [ + { label: "React", description: "UI library" }, + { label: "Vue", description: "Progressive framework" }, + ], +}; + +const multiSelectQuestion: Question = { + question: "Which features?", + multiSelect: true, + options: [ + { label: "Auth", description: "Authentication module" }, + { label: "API", description: "REST API" }, + ], +}; + +describe("AskQuestionCarousel", () => { + beforeEach(() => { + vi.clearAllMocks(); + mockSubmitHandler = null; + }); + + it("returns null when questions array is empty", () => { + const { container } = render(); + expect(container).toBeEmptyDOMElement(); + }); + + it("renders the carousel with questions", () => { + render(); + expect(screen.getByTestId("carousel")).toBeInTheDocument(); + expect(screen.getByTestId("collapsible")).toBeInTheDocument(); + }); + + it("renders the first question text in the header", () => { + render(); + expect(screen.getByText("Which framework?")).toBeInTheDocument(); + }); + + it("renders a submit button as type=submit", () => { + render(); + const buttons = screen.getAllByTestId("ui-button"); + const submitBtn = buttons.find((b) => b.getAttribute("type") === "submit"); + expect(submitBtn).toBeInTheDocument(); + expect(submitBtn?.textContent).toBe("Submit"); + }); + + it("renders the form for submitting answers", () => { + render(); + const form = document.querySelector("form"); + expect(form).toBeInTheDocument(); + }); + + it("renders both question types when mixed", () => { + render(); + const items = screen.getAllByTestId("carousel-item"); + expect(items).toHaveLength(2); + }); +}); diff --git a/packages/vscode-ide-companion/src/webview/components/AskQuestionSummary.test.tsx b/packages/vscode-ide-companion/src/webview/components/AskQuestionSummary.test.tsx new file mode 100644 index 00000000..216553c2 --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/AskQuestionSummary.test.tsx @@ -0,0 +1,90 @@ +/** + * Unit tests for AskQuestionSummary component + * + * Tests cover: + * - Rendering Q&A content + * - Styling of Q: lines vs A: lines + * - Multiple Q&A pairs + * - Empty content + * - BubbleDot rendering + */ + +import React from "react"; +import { render, screen } from "@testing-library/react"; +import { describe, it, expect, vi, beforeEach } from "vitest"; +import AskQuestionSummary from "./AskQuestionSummary"; + +vi.mock("@/webview/components/bubbles/BubbleDot", () => ({ + default: vi.fn(({ variant }: { variant: string }) => ), +})); + +// cn from @/webview/lib/utils is used with clsx objects, so we need a proper mock +vi.mock("@/webview/lib/utils", () => ({ + cn: (...inputs: (string | Record | undefined | null)[]) => { + return inputs + .map((input) => { + if (!input) return ""; + if (typeof input === "string") return input; + if (typeof input === "object") { + return Object.entries(input) + .filter(([, v]) => v) + .map(([k]) => k) + .join(" "); + } + return String(input); + }) + .filter(Boolean) + .join(" "); + }, +})); + +describe("AskQuestionSummary", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("renders Q&A content", () => { + const content = "Q: What framework?" + "\n" + "A: React"; + render(); + expect(screen.getByText("Q: What framework?")).toBeInTheDocument(); + expect(screen.getByText("A: React")).toBeInTheDocument(); + }); + + it("renders '明白了,请稍等...' follow-up text", () => { + const content = "Q: What framework?" + "\n" + "A: React"; + render(); + expect(screen.getByText("明白了,请稍等...")).toBeInTheDocument(); + }); + + it("renders Q lines with muted style", () => { + render(); + const qLine = screen.getByText("Q: What framework?"); + expect(qLine.className).toContain("text-muted-foreground"); + expect(qLine.className).toContain("font-normal"); + }); + + it("renders non-Q lines with bold style", () => { + render(); + const aLine = screen.getByText("A: React"); + expect(aLine.className).toContain("font-bold"); + }); + + it("renders BubbleDot with success variant", () => { + render(); + const dot = screen.getByTestId("bubble-dot"); + expect(dot).toBeInTheDocument(); + expect(dot.getAttribute("data-variant")).toBe("success"); + }); + + it("renders multiple Q&A pairs", () => { + const content = ["Q: First question?", "A: Option A, Option B", "Q: Second question?", "A: Value"].join("\n"); + render(); + expect(screen.getByText("Q: First question?")).toBeInTheDocument(); + expect(screen.getByText("Q: Second question?")).toBeInTheDocument(); + }); + + it("handles single line content", () => { + render(); + expect(screen.getByText("Single answer")).toBeInTheDocument(); + }); +}); diff --git a/packages/vscode-ide-companion/src/webview/components/ContextIndicator.test.tsx b/packages/vscode-ide-companion/src/webview/components/ContextIndicator.test.tsx new file mode 100644 index 00000000..d9b5f327 --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/ContextIndicator.test.tsx @@ -0,0 +1,164 @@ +/** + * Unit tests for ContextIndicator component + * + * Tests cover: + * - Rendering ProgressRing trigger + * - HoverCard content (model, thinking, effort, tokens) + * - Session usage display + * - Token formatting + * - Missing/empty tokenTelemetry + */ + +import React from "react"; +import { render, screen } from "@testing-library/react"; +import { describe, it, expect, vi, beforeEach } from "vitest"; +import ContextIndicator from "./ContextIndicator"; +import type { TokenTelemetry } from "@/webview/types"; + +vi.mock("./ui/hover-card", () => ({ + HoverCard: vi.fn(({ children }: { children: React.ReactNode }) =>
{children}
), + HoverCardContent: vi.fn(({ children }: { children: React.ReactNode }) => ( +
{children}
+ )), + HoverCardTrigger: vi.fn(({ children }: { children: React.ReactNode }) => ( +
{children}
+ )), +})); + +vi.mock("./ui/input-group", () => ({ + InputGroupButton: vi.fn(({ children, ...props }: { children: React.ReactNode }) => ( + + )), +})); + +vi.mock("./ui/progress-ring", () => ({ + ProgressRing: vi.fn(({ value }: { value: number }) => ), +})); + +vi.mock("./ui/progress", () => ({ + Progress: vi.fn(({ value }: { value: number }) => ), +})); + +vi.mock("./ui/field", () => ({ + Field: vi.fn(({ children }: { children: React.ReactNode }) =>
{children}
), + FieldLabel: vi.fn(({ children, htmlFor }: { children: React.ReactNode; htmlFor?: string }) => ( + + )), +})); + +vi.mock("./ui/separator", () => ({ + Separator: vi.fn(() =>
), +})); + +vi.mock("@/webview/utils", () => ({ + flattenUsageFields: vi.fn((usage: Record | undefined) => { + if (!usage) return []; + return [ + ["total_tokens", 5000], + ["prompt_cached_tokens", 2000], + ]; + }), + formatUsageFieldLabel: vi.fn((label: string) => label), + getTokenUsagePercent: vi.fn((tt: TokenTelemetry | undefined) => { + if (!tt?.activeTokens || !tt?.compactPromptTokenThreshold) return 0; + return Math.min(100, Math.floor((tt.activeTokens / tt.compactPromptTokenThreshold) * 100)); + }), + toTitleCase: vi.fn((str: string) => str.charAt(0).toUpperCase() + str.slice(1)), +})); + +const baseTelemetry: TokenTelemetry = { + model: "claude-sonnet-4-20250514", + thinkingEnabled: true, + reasoningEffort: "max", + activeTokens: 50000, + compactPromptTokenThreshold: 200000, + usage: { + total_tokens: 150000, + prompt_cached_tokens: 50000, + }, +}; + +describe("ContextIndicator", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("renders the ProgressRing trigger button", () => { + render(); + expect(screen.getByTestId("input-group-button")).toBeInTheDocument(); + expect(screen.getByTestId("progress-ring")).toBeInTheDocument(); + }); + + it("renders with 0% when tokenTelemetry is undefined", () => { + render(); + const ring = screen.getByTestId("progress-ring"); + expect(ring.getAttribute("data-value")).toBe("0"); + }); + + it("displays model name in hover card", () => { + render(); + expect(screen.getByText("claude-sonnet-4-20250514")).toBeInTheDocument(); + }); + + it('displays "unknown" model when not provided', () => { + render(); + expect(screen.getByText("unknown")).toBeInTheDocument(); + }); + + it("displays thinking enabled state", () => { + render(); + expect(screen.getByText("true")).toBeInTheDocument(); + }); + + it("displays thinking disabled state", () => { + render(); + expect(screen.getByText("false")).toBeInTheDocument(); + }); + + it("displays reasoning effort", () => { + render(); + expect(screen.getByText("max")).toBeInTheDocument(); + }); + + it('displays "max" for missing reasoning effort', () => { + render(); + expect(screen.getByText("max")).toBeInTheDocument(); + }); + + it("displays active tokens formatted", () => { + render(); + // Should render a span with textContent that includes "50,000" + const tokenSpans = screen.getAllByText(/50,000/); + expect(tokenSpans.length).toBeGreaterThan(0); + }); + + it("shows session usage separator when usage data exists", () => { + render(); + expect(screen.getByTestId("separator")).toBeInTheDocument(); + }); + + it("does not show separator when no usage data", () => { + render(); + expect(screen.queryByTestId("separator")).not.toBeInTheDocument(); + }); + + it('displays "Context Window" title in hover card', () => { + render(); + expect(screen.getByText("Context Window")).toBeInTheDocument(); + }); + + it("renders usage percentage in hover card label", () => { + render(); + // getTokenUsagePercent mock returns (50000/200000)*100 = 25 + expect(screen.getByText("25%")).toBeInTheDocument(); + }); + + it("renders a progress bar for usage", () => { + render(); + expect(screen.getByTestId("progress-bar")).toBeInTheDocument(); + }); +}); diff --git a/packages/vscode-ide-companion/src/webview/components/Header.test.tsx b/packages/vscode-ide-companion/src/webview/components/Header.test.tsx new file mode 100644 index 00000000..152d52b9 --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/Header.test.tsx @@ -0,0 +1,171 @@ +/** + * Unit tests for Header component + * + * Tests cover: + * - Displaying session summary + * - "New Conversation" when no active session + * - Search button visibility conditions + * - Rendering SessionList + * - Delegating callbacks + */ + +import React from "react"; +import { render, screen, fireEvent } from "@testing-library/react"; +import { describe, it, expect, vi, beforeEach } from "vitest"; +import Header from "./Header"; +import type { SessionSummary } from "@/webview/types"; + +// Mock the image import +vi.mock("../../../assets/deepcoding_icon.png", () => ({ + default: "data:image/png;base64,mockicon", +})); + +vi.mock("./SessionList", () => ({ + default: vi.fn( + ({ + sessions, + open, + onOpenChange, + onSelect, + }: { + sessions: SessionSummary[]; + open: boolean; + onOpenChange: (open: boolean) => void; + onSelect: (id: string) => void; + }) => ( +
+
+ ) + ), +})); + +vi.mock("./ui/button", () => ({ + Button: vi.fn(({ children, onClick, ...props }: { children: React.ReactNode; onClick?: () => void }) => ( + + )), +})); + +vi.mock("./ui/tooltip", () => ({ + Tooltip: vi.fn(({ children }: { children: React.ReactNode }) =>
{children}
), + TooltipContent: vi.fn(({ children }: { children: React.ReactNode }) => ( +
{children}
+ )), + TooltipTrigger: vi.fn(({ children }: { children: React.ReactNode }) => ( +
{children}
+ )), +})); + +vi.mock("lucide-react", () => ({ + Search: vi.fn(() => ), +})); + +const sessions: SessionSummary[] = [ + { + id: "session-1", + summary: "Build a REST API", + createTime: "2024-01-01", + updateTime: "2024-01-02", + status: "active", + }, + { id: "session-2", summary: "Fix CSS bugs", createTime: "2024-01-03", updateTime: "2024-01-04", status: "idle" }, +]; + +const defaultProps = { + sessions, + activeSessionId: "session-1" as string | null, + onSelectSession: vi.fn(), + onCreateNewSession: vi.fn(), + onRenameSession: vi.fn(), + onDeleteSession: vi.fn(), + sessionListOpen: false, + onToggleSessionList: vi.fn(), + hasMessages: true, + onToggleSearchPanel: vi.fn(), +}; + +describe("Header", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("renders the active session summary", () => { + render(
); + expect(screen.getByText("Build a REST API")).toBeInTheDocument(); + }); + + it('shows "New Conversation" when no active session', () => { + render(
); + expect(screen.getByText("New Conversation")).toBeInTheDocument(); + }); + + it('shows "Deep Code" when activeSessionId but no matching session', () => { + render(
); + expect(screen.getByText("Deep Code")).toBeInTheDocument(); + }); + + it("renders the logo image", () => { + render(
); + const img = screen.getByAltText(""); + expect(img).toBeInTheDocument(); + expect(img.tagName).toBe("IMG"); + }); + + it("shows search button when active session exists and has messages", () => { + render(
); + expect(screen.getByTestId("search-icon")).toBeInTheDocument(); + }); + + it("does not show search button when no active session", () => { + render(
); + expect(screen.queryByTestId("search-icon")).not.toBeInTheDocument(); + }); + + it("does not show search button when no messages", () => { + render(
); + expect(screen.queryByTestId("search-icon")).not.toBeInTheDocument(); + }); + + it("calls onToggleSearchPanel when search button clicked", () => { + render(
); + const searchButtons = screen.getAllByTestId("ui-button"); + // The search button is one of the ui-buttons + const searchBtn = searchButtons.find((btn) => btn.querySelector('[data-testid="search-icon"]')); + if (searchBtn) { + fireEvent.click(searchBtn); + expect(defaultProps.onToggleSearchPanel).toHaveBeenCalledWith(true); + } + }); + + it("renders SessionList component", () => { + render(
); + expect(screen.getByTestId("session-list")).toBeInTheDocument(); + }); + + it("passes sessions to SessionList", () => { + render(
); + const sessionList = screen.getByTestId("session-list"); + expect(sessionList.getAttribute("data-count")).toBe("2"); + }); + + it("passes open state to SessionList", () => { + render(
); + const sessionList = screen.getByTestId("session-list"); + expect(sessionList.getAttribute("data-open")).toBe("true"); + }); + + it("calls onSelectSession when SessionList selects a session", () => { + render(
); + fireEvent.click(screen.getByTestId("session-list-select")); + expect(defaultProps.onSelectSession).toHaveBeenCalledWith("session-1"); + }); + + it("calls onToggleSessionList when SessionList toggles", () => { + render(
); + fireEvent.click(screen.getByTestId("session-list-toggle")); + expect(defaultProps.onToggleSessionList).toHaveBeenCalled(); + }); +}); diff --git a/packages/vscode-ide-companion/src/webview/components/Messages.test.tsx b/packages/vscode-ide-companion/src/webview/components/Messages.test.tsx index 67c94d34..b2aee1f1 100644 --- a/packages/vscode-ide-companion/src/webview/components/Messages.test.tsx +++ b/packages/vscode-ide-companion/src/webview/components/Messages.test.tsx @@ -52,7 +52,7 @@ describe("Messages", () => { it("renders welcome screen when no messages", () => { render(); - expect(screen.getByText("Welcome to the Deep Code AI IDE!")).toBeInTheDocument(); + expect(screen.getByText("Welcome to the Deep Code!")).toBeInTheDocument(); }); it("renders user message", () => { diff --git a/packages/vscode-ide-companion/src/webview/components/Messages.tsx b/packages/vscode-ide-companion/src/webview/components/Messages.tsx index 6c5c45bf..0b42f1f2 100644 --- a/packages/vscode-ide-companion/src/webview/components/Messages.tsx +++ b/packages/vscode-ide-companion/src/webview/components/Messages.tsx @@ -151,7 +151,7 @@ const Messages = forwardRef( return (
-
Welcome to the Deep Code AI IDE!
+
Welcome to the Deep Code!

What would you like to do? Ask about this codebase or we can start writing code.

diff --git a/packages/vscode-ide-companion/src/webview/components/PermissionPrompt.test.tsx b/packages/vscode-ide-companion/src/webview/components/PermissionPrompt.test.tsx index ecba2604..cf4360df 100644 --- a/packages/vscode-ide-companion/src/webview/components/PermissionPrompt.test.tsx +++ b/packages/vscode-ide-companion/src/webview/components/PermissionPrompt.test.tsx @@ -33,6 +33,10 @@ vi.mock("@/webview/components/ui/hover-card", () => ({ vi.mock("lucide-react", () => ({ X: vi.fn(() => ), ShieldAlert: vi.fn(() => ), + ChevronDownIcon: vi.fn(() => ), + ChevronLeft: vi.fn(() => ), + ChevronRight: vi.fn(() => ), + Terminal: vi.fn(() => ), })); const mockDispatch = vi.fn<(action: AppAction) => void>(); @@ -87,7 +91,8 @@ describe("PermissionPrompt", () => { sessionStatus: "ask_permission" as const, }; render(); - expect(screen.getByText("Permission required")).toBeInTheDocument(); + // Header now includes tool name via capitalize in the collapsible trigger + expect(screen.getByText(/Permission required/)).toBeInTheDocument(); }); it("renders denied state when permission denied", () => { @@ -155,8 +160,9 @@ describe("PermissionPrompt", () => { sessionStatus: "ask_permission" as const, }; render(); - const cancelButton = screen.getByTitle("Interrupt"); - fireEvent.click(cancelButton); + // The close (X) button in the collapsible header calls handleCancel -> onInterrupt + const xIcon = screen.getByTestId("x-icon"); + fireEvent.click(xIcon); expect(mockOnInterrupt).toHaveBeenCalled(); }); @@ -171,7 +177,7 @@ describe("PermissionPrompt", () => { expect(document.body.innerHTML).toContain("bg-green-500/15"); }); - it("renders multiple permission requests with index", () => { + it("renders multiple permission requests in carousel layout", () => { const props = { ...defaultProps, askPermissions: [ @@ -181,6 +187,11 @@ describe("PermissionPrompt", () => { sessionStatus: "ask_permission" as const, }; render(); - expect(screen.getByText("1/2")).toBeInTheDocument(); + // Carousel navigation elements should be present (prev/next buttons) + expect(screen.getByTestId("chevron-left-icon")).toBeInTheDocument(); + expect(screen.getByTestId("chevron-right-icon")).toBeInTheDocument(); + // Both tool names should be rendered as carousel slides + expect(screen.getByText("Read")).toBeInTheDocument(); + expect(screen.getByText("Write")).toBeInTheDocument(); }); }); diff --git a/packages/vscode-ide-companion/src/webview/components/PermissionPrompt.tsx b/packages/vscode-ide-companion/src/webview/components/PermissionPrompt.tsx index f9642a7d..2e3de4e9 100644 --- a/packages/vscode-ide-companion/src/webview/components/PermissionPrompt.tsx +++ b/packages/vscode-ide-companion/src/webview/components/PermissionPrompt.tsx @@ -1,9 +1,13 @@ -import { useMemo, useCallback, useState, useEffect } from "react"; +import React, { useMemo, useCallback, useState, useEffect, useRef } from "react"; import { Button } from "@/webview/components/ui/button"; import type { AppAction, AskPermissionRequest, PermissionPromptState, SkillInfo } from "@/webview/types"; -import { ShieldAlert, X } from "lucide-react"; +import { ShieldAlert, X, ChevronDownIcon, ChevronLeft, ChevronRight, Terminal } from "lucide-react"; import { Alert, AlertDescription, AlertTitle } from "@/webview/components/ui/alert"; import { capitalize } from "@/webview/utils"; +import type { CarouselApi } from "@/webview/components/ui/carousel"; +import { Carousel, CarouselContent, CarouselItem } from "@/webview/components/ui/carousel"; +import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/webview/components/ui/collapsible"; +import { Card, CardContent } from "@/webview/components/ui/card"; export interface PermissionPromptProps { askPermissions: AskPermissionRequest[]; @@ -105,11 +109,17 @@ export default function PermissionPrompt({ onSendPrompt, onInterrupt, }: PermissionPromptProps) { + const [api, setApi] = React.useState(); + const carouselApiRef = useRef(null); + const pendingScrollRef = useRef(null); + const [open, setOpen] = React.useState(true); + const [current, setCurrent] = React.useState(0); + const [count, setCount] = React.useState(0); const normalized = useMemo(() => normalizeRequests(askPermissions), [askPermissions]); const isAskPermission = sessionStatus === "ask_permission" && normalized.length > 0; const isDenied = (pendingPermissionReply && sessionStatus === "permission_denied") as boolean; - // Build prompts from requests + // Build prompts from requests — one per (request, scope) pair const prompts = useMemo(() => { const result: Array<{ request: AskPermissionRequest; scope: string }> = []; for (const req of normalized) { @@ -121,43 +131,50 @@ export default function PermissionPrompt({ return result; }, [normalized]); - // Use internal state for decisions + // Internal state for decisions (no sequential index — carousel manages position) const [localState, setLocalState] = useState<{ - index: number; decisions: Record; alwaysAllows: string[]; submitting: boolean; - }>({ index: 0, decisions: {}, alwaysAllows: [], submitting: false }); + }>({ decisions: {}, alwaysAllows: [], submitting: false }); // Reset when prompts change useEffect(() => { - setLocalState({ index: 0, decisions: {}, alwaysAllows: [], submitting: false }); + setLocalState({ decisions: {}, alwaysAllows: [], submitting: false }); }, [askPermissions]); - const findNextIdx = useCallback( - (fromIdx: number, alwaysAllows: string[]) => { - let idx = fromIdx; - while (idx < prompts.length) { - const scope = prompts[idx].scope; - if (VALID_SCOPES.includes(scope) && alwaysAllows.includes(scope)) { - idx++; - continue; - } - return idx; - } - return prompts.length; - }, - [prompts] - ); + // Store carousel API in ref for stable access from callbacks (avoids stale closures) + useEffect(() => { + carouselApiRef.current = api || null; + }, [api]); - const effectiveIndex = findNextIdx(localState.index, localState.alwaysAllows); + // Sync carousel slide counter + useEffect(() => { + if (!api) return; + setCount(api.scrollSnapList().length); + setCurrent(api.selectedScrollSnap() + 1); + api.on("select", () => { + setCurrent(api.selectedScrollSnap() + 1); + }); + }, [api]); + + // Execute pending auto-scroll after React commits the state update + useEffect(() => { + if (pendingScrollRef.current !== null && carouselApiRef.current) { + const idx = pendingScrollRef.current; + pendingScrollRef.current = null; + carouselApiRef.current.scrollTo(idx); + } + }); const commitDecision = useCallback( - (kind: "allow" | "deny" | "always") => { - if (localState.submitting || effectiveIndex >= prompts.length) return; + (kind: "allow" | "deny" | "always", slideIndex: number) => { + if (localState.submitting) return; setLocalState((prev) => { - const prompt = prompts[effectiveIndex]; + const prompt = prompts[slideIndex]; + if (!prompt) return prev; + const newDecisions = { ...prev.decisions }; const newAlwaysAllows = [...prev.alwaysAllows]; @@ -176,18 +193,28 @@ export default function PermissionPrompt({ } } - const nextIdx = effectiveIndex + 1; - const nextEffective = findNextIdx(nextIdx, newAlwaysAllows); + // Find next undecided prompt after the current slide + let nextIdx = slideIndex + 1; + while (nextIdx < prompts.length) { + const s = prompts[nextIdx].scope; + const t = prompts[nextIdx].request.toolCallId; + if (VALID_SCOPES.includes(s) && newAlwaysAllows.includes(s)) { + nextIdx++; + continue; + } + if (newDecisions[t] !== undefined) { + nextIdx++; + continue; + } + break; + } - if (nextEffective >= prompts.length) { - // Submit - const permissions = normalized.map((req): { toolCallId: string; permission: "allow" | "deny" } => { - const decision = newDecisions[req.toolCallId]; - return { - toolCallId: req.toolCallId, - permission: decision === "deny" ? "deny" : "allow", - }; - }); + if (nextIdx >= prompts.length) { + // All prompts decided — submit + const permissions = normalized.map((req) => ({ + toolCallId: req.toolCallId, + permission: (newDecisions[req.toolCallId] === "deny" ? "deny" : "allow") as "allow" | "deny", + })); const hasDeny = permissions.some((p) => p.permission === "deny"); if (hasDeny) { @@ -203,29 +230,22 @@ export default function PermissionPrompt({ }); } - return { ...prev, index: nextIdx, decisions: newDecisions, alwaysAllows: newAlwaysAllows, submitting: true }; + return { ...prev, decisions: newDecisions, alwaysAllows: newAlwaysAllows, submitting: true }; } - return { ...prev, index: nextIdx, decisions: newDecisions, alwaysAllows: newAlwaysAllows }; + // Schedule auto-scroll to the next undecided prompt (executed after render via useEffect) + pendingScrollRef.current = nextIdx; + + return { ...prev, decisions: newDecisions, alwaysAllows: newAlwaysAllows }; }); }, - [ - localState, - effectiveIndex, - prompts, - normalized, - findNextIdx, - dispatch, - onDenyPermission, - onSendPrompt, - activeSessionId, - ] + [localState, prompts, normalized, dispatch, onDenyPermission, onSendPrompt, activeSessionId] ); const handleCancel = useCallback(() => { dispatch({ type: "SET_PENDING_PERMISSION_REPLY", reply: null }); onInterrupt(); - setLocalState({ index: 0, decisions: {}, alwaysAllows: [], submitting: false }); + setLocalState({ decisions: {}, alwaysAllows: [], submitting: false }); }, [dispatch, onInterrupt]); if (!isAskPermission && !isDenied) return null; @@ -242,56 +262,111 @@ export default function PermissionPrompt({ ); } - const prompt = prompts[effectiveIndex]; - if (!prompt) return null; + if (prompts.length === 0) return null; - const canAlwaysAllow = VALID_SCOPES.includes(prompt.scope); + // Header label — show the tool name from the first prompt + const headerLabel = `Permission required — ${capitalize(prompts[0].request.name || "Tool")}`; return ( -
-
-
-
- Permission required - - {effectiveIndex + 1}/{prompts.length} - +
+
+ + + +
+ {headerLabel} +
+ + +
+
+
+ + + + {prompts.map((p, idx) => ( + + + +
+ + {capitalize(p.request.name)} +
+
+ {p.request.command || "(no command)"} +
+ {p.request.description && ( +
{p.request.description}
+ )} +
+ {describeScope(p.scope)} +
+
+
+
+ ))} +
+
+
+
+
+ {/* Navigation footer — matches AskQuestionCarousel style */} +
+
Do you want to proceed?
+
+
+ + {VALID_SCOPES.includes(prompts[current - 1]?.scope || "") && ( + + )} + +
+
+ {open && ( + <> + + + + )} + + {current}/{count} + +
- -
- -
{capitalize(prompt.request.name)}
-
{prompt.request.command || "(no command)"}
- {prompt.request.description && ( -
{prompt.request.description}
- )} - -
- {describeScope(prompt.scope)} -
- -
Do you want to proceed?
- -
- - {canAlwaysAllow && ( - - )} -
diff --git a/packages/vscode-ide-companion/src/webview/components/PlanRenderer.test.tsx b/packages/vscode-ide-companion/src/webview/components/PlanRenderer.test.tsx new file mode 100644 index 00000000..f1b61a47 --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/PlanRenderer.test.tsx @@ -0,0 +1,193 @@ +/** + * Unit tests for PlanRenderer component + * + * Tests cover: + * - Rendering of headings at all 6 levels + * - Task items with different statuses ([ ], [x], [>], [!]) + * - Bullet list items + * - Plain paragraphs + * - Inline markdown (code, bold, italic) + * - Indentation of nested items + * - Empty input + * - HTML escaping + */ + +import React from "react"; +import { render, screen } from "@testing-library/react"; +import { describe, it, expect, vi } from "vitest"; +import PlanRenderer from "./PlanRenderer"; + +vi.mock("lucide-react", () => ({ + Circle: vi.fn(({ className }: { className?: string }) => ), + CircleCheckBig: vi.fn(({ className }: { className?: string }) => ( + + )), + Clock: vi.fn(({ className }: { className?: string }) => ), + CircleAlert: vi.fn(({ className }: { className?: string }) => ( + + )), +})); + +describe("PlanRenderer", () => { + it("renders spacer for empty plan input", () => { + const { container } = render(); + const wrapper = container.querySelector(".update-plan-markdown"); + expect(wrapper).toBeInTheDocument(); + // Empty string produces one empty line which renders as a spacer div + expect(wrapper?.children.length).toBe(1); + }); + + it("renders headings at different levels", () => { + const plan = "# H1\n## H2\n### H3\n#### H4\n##### H5\n###### H6"; + render(); + + // Headings render via dangerouslySetInnerHTML inside + expect(screen.getByText("H1")).toBeInTheDocument(); + expect(screen.getByText("H2")).toBeInTheDocument(); + expect(screen.getByText("H3")).toBeInTheDocument(); + expect(screen.getByText("H4")).toBeInTheDocument(); + expect(screen.getByText("H5")).toBeInTheDocument(); + expect(screen.getByText("H6")).toBeInTheDocument(); + + // The heading text is inside a within the

/

elements + const h1Text = screen.getByText("H1"); + expect(h1Text.closest("h1")).toBeInTheDocument(); + const h6Text = screen.getByText("H6"); + expect(h6Text.closest("h6")).toBeInTheDocument(); + }); + + it("falls through to paragraph when heading has too many #", () => { + // 7 # characters won't match the heading regex, so it falls through to paragraph + const plan = "####### Too Deep"; + render(); + // The whole line renders as a paragraph + const p = document.querySelector("p"); + expect(p).toBeInTheDocument(); + expect(p?.textContent).toContain("Too Deep"); + }); + + it("renders todo task items with Circle icon", () => { + const plan = "- [ ] Write tests"; + render(); + // Text is rendered via dangerouslySetInnerHTML + expect(screen.getByText("Write tests")).toBeInTheDocument(); + // Todo status uses Circle icon + expect(screen.getByTestId("icon-circle")).toBeInTheDocument(); + }); + + it("renders completed task items with check icon", () => { + const plan = "- [x] Implement login"; + render(); + expect(screen.getByText("Implement login")).toBeInTheDocument(); + expect(screen.getByTestId("icon-check")).toBeInTheDocument(); + }); + + it("renders active task items with clock icon", () => { + const plan = "- [>] In progress feature"; + render(); + expect(screen.getByText("In progress feature")).toBeInTheDocument(); + expect(screen.getByTestId("icon-clock")).toBeInTheDocument(); + }); + + it("renders attention task items with alert icon", () => { + const plan = "- [!] Blocked by dependency"; + render(); + expect(screen.getByText("Blocked by dependency")).toBeInTheDocument(); + expect(screen.getByTestId("icon-alert")).toBeInTheDocument(); + }); + + it("supports X (uppercase) for completed status", () => { + const plan = "- [X] Done (uppercase X)"; + render(); + expect(screen.getByText("Done (uppercase X)")).toBeInTheDocument(); + expect(screen.getByTestId("icon-check")).toBeInTheDocument(); + }); + + it("renders bullet list items", () => { + const plan = "- Regular bullet\n* Star bullet"; + render(); + expect(screen.getByText("Regular bullet")).toBeInTheDocument(); + expect(screen.getByText("Star bullet")).toBeInTheDocument(); + }); + + it("renders plain paragraphs", () => { + const plan = "This is a plain paragraph."; + render(); + expect(screen.getByText("This is a plain paragraph.")).toBeInTheDocument(); + }); + + it("renders inline code in items", () => { + const plan = "- [x] Use `useMemo` for optimization"; + render(); + const codeEl = document.querySelector("code"); + expect(codeEl).toBeInTheDocument(); + expect(codeEl?.textContent).toBe("useMemo"); + }); + + it("renders inline bold text", () => { + const plan = "- [x] Fix **critical** bug"; + render(); + const strongEl = document.querySelector("strong"); + expect(strongEl).toBeInTheDocument(); + expect(strongEl?.textContent).toBe("critical"); + }); + + it("renders inline italic text", () => { + const plan = "- Note: *optional* parameter"; + render(); + const emEl = document.querySelector("em"); + expect(emEl).toBeInTheDocument(); + expect(emEl?.textContent).toBe("optional"); + }); + + it("escapes HTML in plan content", () => { + const plan = "- [x] Test "; + render(); + const rendered = document.body.innerHTML; + expect(rendered).toContain("<script>"); + expect(rendered).not.toContain("