diff --git a/.gitignore b/.gitignore index 81f023c6..1a1cd688 100644 --- a/.gitignore +++ b/.gitignore @@ -3,34 +3,67 @@ __pycache__/ *.py[cod] *$py.class *.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# Virtual Environments venv/ env/ +ENV/ +env.bak/ +venv.bak/ +.venv/ -# Node +# Node.js node_modules/ -dist/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* +.pnpm-debug.log* -# Database -*.db -*.sqlite -*.sqlite3 - -# Environment -.env +# IDEs +.idea/ +.vscode/ +*.swp +*.swo .DS_Store -# Ollama -ollama_bin/ -.ollama/ - # Logs logs/ *.log -nohup.out -# Coverage -coverage/ +# Databases +*.db +*.sqlite3 -# Temporary -tmp/ -temp/ +# Large Files & Binaries +.ollama/ +ollama_bin/ +Pixelle-Video/ +*.dmg +*.zip +*.tar.gz +*.iso + +# Local Env +.env +.env.* +!.env.example diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..d6f50a7c --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,72 @@ +# PMFlow 开发 Agent Prompt + +你是一位资深的全栈工程师,精通 Python 3.11+、FastAPI、SQLAlchemy 2.0、LangChain、React 18、TypeScript、shadcn/ui、Tailwind CSS。 + +你正在为 **PMFlow** 开发代码:这是一款 AI 原生、人员能力驱动的项目管理操作系统,专为 10-50 人 AI 开发团队打造。 + +--- + +## 核心开发规范 + +1. **代码质量**:所有代码严格遵循 Python 与 TypeScript 最佳实践,代码清晰、注释完整、类型安全、可维护性强。 + +2. **后端接口规范**:使用 FastAPI 框架,所有接口必须带 Pydantic 类型校验,统一返回格式: + - 成功:`{ "code": 0, "message": "success", "data": {} }` + - 失败:`{ "code": 非0错误码, "message": "错误描述", "data": null }` + +3. **数据库规范**:使用 SQLAlchemy 2.0,所有模型继承 Base 基类,必须包含 `tenant_id` 字段,所有查询必须自动过滤 `tenant_id`(使用依赖注入实现)。 + +4. **AI 能力规范**:所有 AI 能力必须封装在独立的 service 层,使用 LangChain 实现,Prompt 放在 `./backend/app/config/ai_prompts.py` 独立管理,禁止硬编码。 + +5. **AI 调用规范**:所有 AI 调用必须: + - 记录日志到 `ai_call_logs` 表 + - 实现 Redis 结果缓存 + - 完善的错误重试机制 + - 降低成本 + +6. **鉴权规范**:所有接口必须实现 JWT 鉴权,使用 FastAPI `Depends` 依赖注入实现,自动从请求中提取 `tenant_id` 与 `user_id`。 + +7. **工程规范**: + - 完善的错误处理 + - 结构化日志(structlog) + - 从第一天就支持多租户、可扩展性 + - 模块化设计 + +8. **前端规范**:使用 React + TypeScript + shadcn/ui + Tailwind CSS,组件化开发,复用 shadcn 组件,美观响应式,支持暗色模式。 + +9. **核心约束**:人员能力图谱是 AI 智能任务分配的核心,所有任务拆解、分配逻辑必须优先调用该模块数据。 + +--- + +## 项目结构 + +``` +backend/ # Python FastAPI 后端 +├── app/ +│ ├── api/ # API 路由层,按模块分文件 +│ ├── core/ # 核心配置、安全、日志、数据库连接 +│ ├── models/ # SQLAlchemy ORM 模型 +│ ├── schemas/ # Pydantic 请求/响应模型 +│ ├── services/ # 业务逻辑层(含 ai_service.py、skill_service.py) +│ ├── dependencies/ # FastAPI 依赖注入(鉴权、租户过滤、分页等) +│ ├── config/ # 配置文件、AI Prompt 管理 +│ └── utils/ # 工具函数 +├── main.py # 项目入口 +├── pyproject.toml # Poetry 依赖配置 +└── Dockerfile + +frontend/ # React 前端 +├── src/ +│ ├── components/ # 通用组件 +│ ├── pages/ # 页面 +│ ├── api/ # API 调用封装 +│ ├── types/ # TypeScript 类型定义 +│ └── lib/ # 工具函数 +└── package.json +``` + +--- + +## 执行要求 + +根据用户的具体需求,生成高质量、可直接运行的代码。 diff --git a/CLAUDE.md b/CLAUDE.md index 0b3f5575..b35d2c02 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,156 +4,223 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Project Overview -**Neural Sync** is an AI-native project management platform designed for small (10-person) AI/ML technical teams. Unlike traditional PM tools that manage static tasks, this system manages "Living Context" - external signals, AI experiments, and cognitive knowledge nodes with version tracking and semantic embedding. +**PMFlow / Neural Sync** is an AI-native project management platform designed for small (10-50 person) AI/ML technical teams. The system has evolved into a multi-tenant, role-based PM operating system with: -### Core Philosophy +- **Multi-tenant Architecture**: Complete data isolation with tenant_id filtering +- **RBAC**: Role-based access control with JWT authentication +- **Event-Driven Architecture**: Event bus with WebSocket real-time updates +- **AI-Native Features**: LangChain integration, skill management, intelligent task routing -The system operates on three pillars: -1. **Signals (Pulse)**: External triggers (market news, model releases, competitor updates) captured from sources like HackerNews -2. **Context Nodes (Cognitive Core)**: Atomic knowledge units with vector embeddings for semantic search - when these change, dependent experiments auto-flag as "outdated" -3. **Experiments (Lab)**: Evaluation-driven tasks where success is measured by metrics (accuracy, latency) rather than just completion +### Dual Frontend Architecture -## Technology Stack - -### Backend -- **FastAPI** with async/await patterns -- **SQLAlchemy 2.0** async with database-agnostic design (PostgreSQL with pgvector or SQLite fallback) -- **Alembic** for database migrations -- **Ollama** integration for local LLM operations (llama3, nomic-embed-text models) - -### Frontend -- **Vue 3** with Composition API and ` +
+ diff --git a/frontend/nginx.conf b/frontend/nginx.conf new file mode 100644 index 00000000..0392eeec --- /dev/null +++ b/frontend/nginx.conf @@ -0,0 +1,18 @@ +server { + listen 80; + root /usr/share/nginx/html; + index index.html; + + location / { + try_files $uri $uri/ /index.html; + } + + location /api { + proxy_pass http://backend:8000; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} diff --git a/frontend/package-lock.json b/frontend/package-lock.json index a80110d8..cf82656b 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,34 +1,204 @@ { - "name": "frontend", - "version": "0.0.0", + "name": "pmflow", + "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "frontend", - "version": "0.0.0", + "name": "pmflow", + "version": "0.1.0", "dependencies": { - "axios": "^1.13.5", - "echarts": "^6.0.0", - "marked": "^17.0.3", - "naive-ui": "^2.43.2", - "vfonts": "^0.0.3", - "vue": "^3.5.25", - "vue-echarts": "^8.0.1" + "@radix-ui/react-dialog": "^1.0.5", + "@radix-ui/react-dropdown-menu": "^2.0.6", + "@radix-ui/react-label": "^2.1.8", + "@radix-ui/react-slot": "^1.0.2", + "@radix-ui/react-switch": "^1.2.6", + "@radix-ui/react-tabs": "^1.1.13", + "@tanstack/react-query": "^5.60.0", + "axios": "^1.7.0", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", + "lucide-react": "^0.460.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.28.0", + "recharts": "^2.13.0", + "tailwind-merge": "^2.5.0", + "tailwindcss-animate": "^1.0.7", + "zustand": "^4.5.0" }, "devDependencies": { - "@types/node": "^24.10.1", - "@vitejs/plugin-vue": "^6.0.2", - "@vue/tsconfig": "^0.8.1", - "typescript": "~5.9.3", - "vite": "^8.0.0-beta.13", - "vue-tsc": "^3.1.5" + "@types/node": "^22.0.0", + "@types/react": "^18.3.0", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^4.3.0", + "autoprefixer": "^10.4.20", + "concurrently": "^9.2.1", + "postcss": "^8.4.47", + "tailwindcss": "^3.4.14", + "typescript": "~5.6.0", + "vite": "^5.4.0" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -38,15 +208,41 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/parser": { "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.29.0" @@ -58,10 +254,86 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", + "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/types": { "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -71,117 +343,44 @@ "node": ">=6.9.0" } }, - "node_modules/@css-render/plugin-bem": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/@css-render/plugin-bem/-/plugin-bem-0.15.14.tgz", - "integrity": "sha512-QK513CJ7yEQxm/P3EwsI+d+ha8kSOcjGvD6SevM41neEMxdULE+18iuQK6tEChAWMOQNQPLG/Rw3Khb69r5neg==", - "license": "MIT", - "peerDependencies": { - "css-render": "~0.15.14" - } - }, - "node_modules/@css-render/vue3-ssr": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/@css-render/vue3-ssr/-/vue3-ssr-0.15.14.tgz", - "integrity": "sha512-//8027GSbxE9n3QlD73xFY6z4ZbHbvrOVB7AO6hsmrEzGbg+h2A09HboUyDgu+xsmj7JnvJD39Irt+2D0+iV8g==", - "license": "MIT", - "peerDependencies": { - "vue": "^3.0.11" - } - }, - "node_modules/@emnapi/core": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz", - "integrity": "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==", + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], "dev": true, "license": "MIT", "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.1.0", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", - "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", - "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emotion/hash": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", - "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==", - "license": "MIT" - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "license": "MIT" - }, - "node_modules/@juggle/resize-observer": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.4.0.tgz", - "integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==", - "license": "Apache-2.0" - }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz", - "integrity": "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1", - "@tybys/wasm-util": "^0.10.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - } - }, - "node_modules/@oxc-project/runtime": { - "version": "0.113.0", - "resolved": "https://registry.npmjs.org/@oxc-project/runtime/-/runtime-0.113.0.tgz", - "integrity": "sha512-apRWH/gXeAsl/sQiblIZnLu7f8P/C9S2fJIicuHV9KOK9J7Hv1JPyTwB8WAcOrDBfjs+cbzjMOGe9UR2ue4ZQg==", - "dev": true, - "license": "MIT", + "os": [ + "aix" + ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=12" } }, - "node_modules/@oxc-project/types": { - "version": "0.113.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.113.0.tgz", - "integrity": "sha512-Tp3XmgxwNQ9pEN9vxgJBAqdRamHibi76iowQ38O2I4PMpcvNRQNVsU2n1x1nv9yh0XoTrGFzf7cZSGxmixxrhA==", + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Boshen" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.4.tgz", - "integrity": "sha512-vRq9f4NzvbdZavhQbjkJBx7rRebDKYR9zHfO/Wg486+I7bSecdUapzCm5cyXoK+LHokTxgSq7A5baAXUZkIz0w==", + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", "cpu": [ "arm64" ], @@ -192,13 +391,30 @@ "android" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=12" } }, - "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.4.tgz", - "integrity": "sha512-kFgEvkWLqt3YCgKB5re9RlIrx9bRsvyVUnaTakEpOPuLGzLpLapYxE9BufJNvPg8GjT6mB1alN4yN1NjzoeM8Q==", + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", "cpu": [ "arm64" ], @@ -209,13 +425,13 @@ "darwin" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=12" } }, - "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.4.tgz", - "integrity": "sha512-JXmaOJGsL/+rsmMfutcDjxWM2fTaVgCHGoXS7nE8Z3c9NAYjGqHvXrAhMUZvMpHS/k7Mg+X7n/MVKb7NYWKKww==", + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", "cpu": [ "x64" ], @@ -226,13 +442,30 @@ "darwin" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=12" } }, - "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.4.tgz", - "integrity": "sha512-ep3Catd6sPnHTM0P4hNEvIv5arnDvk01PfyJIJ+J3wVCG1eEaPo09tvFqdtcaTrkwQy0VWR24uz+cb4IsK53Qw==", + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", "cpu": [ "x64" ], @@ -243,13 +476,13 @@ "freebsd" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=12" } }, - "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.4.tgz", - "integrity": "sha512-LwA5ayKIpnsgXJEwWc3h8wPiS33NMIHd9BhsV92T8VetVAbGe2qXlJwNVDGHN5cOQ22R9uYvbrQir2AB+ntT2w==", + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", "cpu": [ "arm" ], @@ -260,13 +493,13 @@ "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=12" } }, - "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.4.tgz", - "integrity": "sha512-AC1WsGdlV1MtGay/OQ4J9T7GRadVnpYRzTcygV1hKnypbYN20Yh4t6O1Sa2qRBMqv1etulUknqXjc3CTIsBu6A==", + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", "cpu": [ "arm64" ], @@ -277,13 +510,1235 @@ "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=12" } }, - "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.4.tgz", - "integrity": "sha512-lU+6rgXXViO61B4EudxtVMXSOfiZONR29Sys5VGSetUY7X8mg9FCKIIjcPPj8xNDeYzKl+H8F/qSKOBVFJChCQ==", + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.4.tgz", + "integrity": "sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.5.tgz", + "integrity": "sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.4", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.7.tgz", + "integrity": "sha512-0tLRojf/1Go2JgEVm+3Frg9A3IW8bJgKgdO0BN5RkF//ufuz2joZM63Npau2ff3J6lUVYgDSNzNkR+aH3IVfjg==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.5" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@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==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.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-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "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-collection/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "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-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "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.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "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-dialog": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz", + "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.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/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "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-direction": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "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.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", + "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.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-dropdown-menu": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.16.tgz", + "integrity": "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.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-focus-guards": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", + "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", + "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.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.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-id": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "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.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.8.tgz", + "integrity": "sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.4" + }, + "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-label/node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" + }, + "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.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.16.tgz", + "integrity": "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.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-menu/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "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-popper": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", + "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-rect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/rect": "1.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-portal": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.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-presence": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.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-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "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-primitive/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "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-roving-focus": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", + "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.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.2.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.4.tgz", + "integrity": "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "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-switch": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.6.tgz", + "integrity": "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.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-tabs": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", + "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.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-use-callback-ref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "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.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "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.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "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.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "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.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "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.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", + "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.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", + "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.1" + }, + "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.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "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/rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", + "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", + "license": "MIT" + }, + "node_modules/@remix-run/router": { + "version": "1.23.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.2.tgz", + "integrity": "sha512-Ic6m2U/rMjTkhERIa/0ZtXJP17QUi2CbWE7cqx4J58M8aA3QTfW+2UlQ4psvTX9IO1RfNVhK3pcpdjej7L+t2w==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", "cpu": [ "arm64" ], @@ -292,15 +1747,124 @@ "optional": true, "os": [ "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } + ] }, - "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.4.tgz", - "integrity": "sha512-DZaN1f0PGp/bSvKhtw50pPsnln4T13ycDq1FrDWRiHmWt1JeW+UtYg9touPFf8yt993p8tS2QjybpzKNTxYEwg==", + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", "cpu": [ "x64" ], @@ -309,15 +1873,12 @@ "optional": true, "os": [ "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } + ] }, - "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.4.tgz", - "integrity": "sha512-RnGxwZLN7fhMMAItnD6dZ7lvy+TI7ba+2V54UF4dhaWa/p8I/ys1E73KO6HmPmgz92ZkfD8TXS1IMV8+uhbR9g==", + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", "cpu": [ "x64" ], @@ -326,15 +1887,26 @@ "optional": true, "os": [ "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } + ] }, - "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.4.tgz", - "integrity": "sha512-6lcI79+X8klGiGd8yHuTgQRjuuJYNggmEml+RsyN596P23l/zf9FVmJ7K0KVKkFAeYEdg0iMUKyIxiV5vebDNQ==", + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", "cpu": [ "arm64" ], @@ -343,32 +1915,12 @@ "optional": true, "os": [ "openharmony" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } + ] }, - "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.4.tgz", - "integrity": "sha512-wz7ohsKCAIWy91blZ/1FlpPdqrsm1xpcEOQVveWoL6+aSPKL4VUcoYmmzuLTssyZxRpEwzuIxL/GDsvpjaBtOw==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@napi-rs/wasm-runtime": "^1.1.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.4.tgz", - "integrity": "sha512-cfiMrfuWCIgsFmcVG0IPuO6qTRHvF7NuG3wngX1RZzc6dU8FuBFb+J3MIR5WrdTNozlumfgL4cvz+R4ozBCvsQ==", + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", "cpu": [ "arm64" ], @@ -377,15 +1929,26 @@ "optional": true, "os": [ "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } + ] }, - "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.4.tgz", - "integrity": "sha512-p6UeR9y7ht82AH57qwGuFYn69S6CZ7LLKdCKy/8T3zS9VTrJei2/CGsTUV45Da4Z9Rbhc7G4gyWQ/Ioamqn09g==", + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", "cpu": [ "x64" ], @@ -394,260 +1957,347 @@ "optional": true, "os": [ "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "cpu": [ + "x64" ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.2", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.2.tgz", - "integrity": "sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", - "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", "dev": true, "license": "MIT", "optional": true, - "dependencies": { - "tslib": "^2.4.0" + "os": [ + "win32" + ] + }, + "node_modules/@tanstack/query-core": { + "version": "5.90.20", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.20.tgz", + "integrity": "sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" } }, - "node_modules/@types/katex": { - "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.8.tgz", - "integrity": "sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==", - "license": "MIT" - }, - "node_modules/@types/lodash": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.23.tgz", - "integrity": "sha512-RDvF6wTulMPjrNdCoYRC8gNR880JNGT8uB+REUpC2Ns4pRqQJhGz90wh7rgdXDPpCczF3VGktDuFGVnz8zP7HA==", - "license": "MIT" - }, - "node_modules/@types/lodash-es": { - "version": "4.17.12", - "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz", - "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", + "node_modules/@tanstack/react-query": { + "version": "5.90.21", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.21.tgz", + "integrity": "sha512-0Lu6y5t+tvlTJMTO7oh5NSpJfpg/5D41LlThfepTixPYkJ0sE2Jj0m0f6yYqujBwIXlId87e234+MxG3D3g7kg==", "license": "MIT", "dependencies": { - "@types/lodash": "*" + "@tanstack/query-core": "5.90.20" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" } }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", + "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { - "version": "24.10.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.13.tgz", - "integrity": "sha512-oH72nZRfDv9lADUBSo104Aq7gPHpQZc4BTx38r9xf9pg5LfP6EzSyH2n7qFmmxRQXh7YlUXODcYsg6PuTDSxGg==", + "version": "22.19.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.11.tgz", + "integrity": "sha512-BH7YwL6rA93ReqeQS1c4bsPpcfOmJasG+Fkr6Y59q83f9M1WcBRHR2vM+P9eOisYRcN3ujQoiZY8uk5W+1WL8w==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.16.0" + "undici-types": "~6.21.0" } }, - "node_modules/@vitejs/plugin-vue": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.4.tgz", - "integrity": "sha512-uM5iXipgYIn13UUQCZNdWkYk+sysBeA97d5mHsAoAt1u/wpN3+zxOmsVJWosuzX+IMGRzeYUNytztrYznboIkQ==", + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.28", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.28.tgz", + "integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "devOptional": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", "dev": true, "license": "MIT", "dependencies": { - "@rolldown/pluginutils": "1.0.0-rc.2" + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": "^14.18.0 || >=16.0.0" }, "peerDependencies": { - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0", - "vue": "^3.2.25" + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, - "node_modules/@volar/language-core": { - "version": "2.4.27", - "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.27.tgz", - "integrity": "sha512-DjmjBWZ4tJKxfNC1F6HyYERNHPYS7L7OPFyCrestykNdUZMFYzI9WTyvwPcaNaHlrEUwESHYsfEw3isInncZxQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@volar/source-map": "2.4.27" - } - }, - "node_modules/@volar/source-map": { - "version": "2.4.27", - "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.27.tgz", - "integrity": "sha512-ynlcBReMgOZj2i6po+qVswtDUeeBRCTgDurjMGShbm8WYZgJ0PA4RmtebBJ0BCYol1qPv3GQF6jK7C9qoVc7lg==", + "node_modules/@vitejs/plugin-react/node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", "dev": true, "license": "MIT" }, - "node_modules/@volar/typescript": { - "version": "2.4.27", - "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.27.tgz", - "integrity": "sha512-eWaYCcl/uAPInSK2Lze6IqVWaBu/itVqR5InXcHXFyles4zO++Mglt3oxdgj75BDcv1Knr9Y93nowS8U3wqhxg==", + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { - "@volar/language-core": "2.4.27", - "path-browserify": "^1.0.1", - "vscode-uri": "^3.0.8" - } - }, - "node_modules/@vue/compiler-core": { - "version": "3.5.28", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.28.tgz", - "integrity": "sha512-kviccYxTgoE8n6OCw96BNdYlBg2GOWfBuOW4Vqwrt7mSKWKwFVvI8egdTltqRgITGPsTFYtKYfxIG8ptX2PJHQ==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.0", - "@vue/shared": "3.5.28", - "entities": "^7.0.1", - "estree-walker": "^2.0.2", - "source-map-js": "^1.2.1" - } - }, - "node_modules/@vue/compiler-dom": { - "version": "3.5.28", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.28.tgz", - "integrity": "sha512-/1ZepxAb159jKR1btkefDP+J2xuWL5V3WtleRmxaT+K2Aqiek/Ab/+Ebrw2pPj0sdHO8ViAyyJWfhXXOP/+LQA==", - "license": "MIT", - "dependencies": { - "@vue/compiler-core": "3.5.28", - "@vue/shared": "3.5.28" - } - }, - "node_modules/@vue/compiler-sfc": { - "version": "3.5.28", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.28.tgz", - "integrity": "sha512-6TnKMiNkd6u6VeVDhZn/07KhEZuBSn43Wd2No5zaP5s3xm8IqFTHBj84HJah4UepSUJTro5SoqqlOY22FKY96g==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.0", - "@vue/compiler-core": "3.5.28", - "@vue/compiler-dom": "3.5.28", - "@vue/compiler-ssr": "3.5.28", - "@vue/shared": "3.5.28", - "estree-walker": "^2.0.2", - "magic-string": "^0.30.21", - "postcss": "^8.5.6", - "source-map-js": "^1.2.1" - } - }, - "node_modules/@vue/compiler-ssr": { - "version": "3.5.28", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.28.tgz", - "integrity": "sha512-JCq//9w1qmC6UGLWJX7RXzrGpKkroubey/ZFqTpvEIDJEKGgntuDMqkuWiZvzTzTA5h2qZvFBFHY7fAAa9475g==", - "license": "MIT", - "dependencies": { - "@vue/compiler-dom": "3.5.28", - "@vue/shared": "3.5.28" - } - }, - "node_modules/@vue/language-core": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.2.4.tgz", - "integrity": "sha512-bqBGuSG4KZM45KKTXzGtoCl9cWju5jsaBKaJJe3h5hRAAWpZUuj5G+L+eI01sPIkm4H6setKRlw7E85wLdDNew==", - "dev": true, - "license": "MIT", - "dependencies": { - "@volar/language-core": "2.4.27", - "@vue/compiler-dom": "^3.5.0", - "@vue/shared": "^3.5.0", - "alien-signals": "^3.0.0", - "muggle-string": "^0.4.1", - "path-browserify": "^1.0.1", - "picomatch": "^4.0.2" - } - }, - "node_modules/@vue/reactivity": { - "version": "3.5.28", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.28.tgz", - "integrity": "sha512-gr5hEsxvn+RNyu9/9o1WtdYdwDjg5FgjUSBEkZWqgTKlo/fvwZ2+8W6AfKsc9YN2k/+iHYdS9vZYAhpi10kNaw==", - "license": "MIT", - "dependencies": { - "@vue/shared": "3.5.28" - } - }, - "node_modules/@vue/runtime-core": { - "version": "3.5.28", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.28.tgz", - "integrity": "sha512-POVHTdbgnrBBIpnbYU4y7pOMNlPn2QVxVzkvEA2pEgvzbelQq4ZOUxbp2oiyo+BOtiYlm8Q44wShHJoBvDPAjQ==", - "license": "MIT", - "dependencies": { - "@vue/reactivity": "3.5.28", - "@vue/shared": "3.5.28" - } - }, - "node_modules/@vue/runtime-dom": { - "version": "3.5.28", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.28.tgz", - "integrity": "sha512-4SXxSF8SXYMuhAIkT+eBRqOkWEfPu6nhccrzrkioA6l0boiq7sp18HCOov9qWJA5HML61kW8p/cB4MmBiG9dSA==", - "license": "MIT", - "dependencies": { - "@vue/reactivity": "3.5.28", - "@vue/runtime-core": "3.5.28", - "@vue/shared": "3.5.28", - "csstype": "^3.2.3" - } - }, - "node_modules/@vue/server-renderer": { - "version": "3.5.28", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.28.tgz", - "integrity": "sha512-pf+5ECKGj8fX95bNincbzJ6yp6nyzuLDhYZCeFxUNp8EBrQpPpQaLX3nNCp49+UbgbPun3CeVE+5CXVV1Xydfg==", - "license": "MIT", - "dependencies": { - "@vue/compiler-ssr": "3.5.28", - "@vue/shared": "3.5.28" + "color-convert": "^2.0.1" }, - "peerDependencies": { - "vue": "3.5.28" - } - }, - "node_modules/@vue/shared": { - "version": "3.5.28", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.28.tgz", - "integrity": "sha512-cfWa1fCGBxrvaHRhvV3Is0MgmrbSCxYTXCSCau2I0a1Xw1N1pHAvkWCiXPRAqjvToILvguNyEwjevUqAuBQWvQ==", - "license": "MIT" - }, - "node_modules/@vue/tsconfig": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@vue/tsconfig/-/tsconfig-0.8.1.tgz", - "integrity": "sha512-aK7feIWPXFSUhsCP9PFqPyFOcz4ENkb8hZ2pneL6m2UjCkccvaOhC/5KCKluuBufvp2KzkbdA2W2pk20vLzu3g==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "typescript": "5.x", - "vue": "^3.4.0" + "engines": { + "node": ">=8" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - }, - "vue": { - "optional": true - } + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/alien-signals": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-3.1.2.tgz", - "integrity": "sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw==", - "dev": true, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", "license": "MIT" }, - "node_modules/async-validator": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz", - "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==", + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", "license": "MIT" }, + "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/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, + "node_modules/autoprefixer": { + "version": "10.4.24", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.24.tgz", + "integrity": "sha512-uHZg7N9ULTVbutaIsDRoUkoS8/h3bdsmVJYZ5l3wv8Cp/6UIIoRDm90hZ+BwxUj/hGBEzLxdHNSKuFpn8WOyZw==", + "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.1", + "caniuse-lite": "^1.0.30001766", + "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/axios": { "version": "1.13.5", "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz", @@ -659,6 +2309,77 @@ "proxy-from-env": "^1.1.0" } }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", + "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, "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", @@ -672,6 +2393,158 @@ "node": ">= 0.4" } }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001774", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001774.tgz", + "integrity": "sha512-DDdwPGz99nmIEv216hKSgLD+D4ikHQHjBC/seF98N9CPqRX4M5mSxT9eTV6oyisnJcuzxtZy4n17yKKQYmYQOA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "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==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -684,47 +2557,210 @@ "node": ">= 0.8" } }, - "node_modules/css-render": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/css-render/-/css-render-0.15.14.tgz", - "integrity": "sha512-9nF4PdUle+5ta4W5SyZdLCCmFd37uVimSjg1evcTqKJCyvCEEj12WKzOSBNak6r4im4J4iYXKH1OWpUV5LBYFg==", + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", "license": "MIT", - "dependencies": { - "@emotion/hash": "~0.8.0", - "csstype": "~3.0.5" + "engines": { + "node": ">= 6" } }, - "node_modules/css-render/node_modules/csstype": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", - "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==", + "node_modules/concurrently": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz", + "integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "4.1.2", + "rxjs": "7.8.2", + "shell-quote": "1.8.3", + "supports-color": "8.1.1", + "tree-kill": "1.2.2", + "yargs": "17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "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/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", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "license": "MIT" }, - "node_modules/date-fns": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", - "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/kossnocorp" + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" } }, - "node_modules/date-fns-tz": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/date-fns-tz/-/date-fns-tz-3.2.0.tgz", - "integrity": "sha512-sg8HqoTEulcbbbVXeg84u5UnlsQa8GS5QXMqjjYIhS4abEVVKIUwe0/l/UhrZdKaL/W5eWZNlbTeEIiOXTcsBQ==", - "license": "MIT", - "peerDependencies": { - "date-fns": "^3.0.0 || ^4.0.0" + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" } }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", + "license": "MIT" + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -740,10 +2776,40 @@ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "dev": true, "license": "Apache-2.0", + "optional": true, + "peer": 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/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "license": "Apache-2.0" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "license": "MIT" + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -758,33 +2824,19 @@ "node": ">= 0.4" } }, - "node_modules/echarts": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/echarts/-/echarts-6.0.0.tgz", - "integrity": "sha512-Tte/grDQRiETQP4xz3iZWSvoHrkCQtwqd6hs+mifXcjrCuo2iKWbajFObuLJVBlDIJlOzgQPd1hsaKt/3+OMkQ==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "2.3.0", - "zrender": "6.0.0" - } + "node_modules/electron-to-chromium": { + "version": "1.5.302", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.302.tgz", + "integrity": "sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==", + "dev": true, + "license": "ISC" }, - "node_modules/echarts/node_modules/tslib": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", - "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", - "license": "0BSD" - }, - "node_modules/entities": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", - "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" }, "node_modules/es-define-property": { "version": "1.0.1", @@ -831,23 +2883,111 @@ "node": ">= 0.4" } }, - "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "license": "MIT" }, - "node_modules/evtd": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/evtd/-/evtd-0.2.4.tgz", - "integrity": "sha512-qaeGN5bx63s/AXgQo8gj6fBkxge+OoLddLniox5qtLAEY5HSnuSlISXVPxnSae1dWblvTh4/HoMIB+mbMsvZzw==", - "license": "MIT" + "node_modules/fast-equals": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.4.0.tgz", + "integrity": "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, "license": "MIT", "engines": { "node": ">=12.0.0" @@ -861,6 +3001,18 @@ } } }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/follow-redirects": { "version": "1.15.11", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", @@ -897,11 +3049,24 @@ "node": ">= 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/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -921,6 +3086,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -945,6 +3130,15 @@ "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-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", @@ -958,6 +3152,18 @@ "node": ">= 0.4" } }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -970,6 +3176,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -1009,13 +3225,121 @@ "node": ">= 0.4" } }, - "node_modules/highlight.js": { - "version": "11.11.1", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", - "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==", - "license": "BSD-3-Clause", + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", "engines": { - "node": ">=12.0.0" + "node": ">=12" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/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" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" } }, "node_modules/lightningcss": { @@ -1024,6 +3348,8 @@ "integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==", "dev": true, "license": "MPL-2.0", + "optional": true, + "peer": true, "dependencies": { "detect-libc": "^2.0.3" }, @@ -1061,6 +3387,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -1082,6 +3409,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -1103,6 +3431,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -1124,6 +3453,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -1145,6 +3475,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -1166,6 +3497,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -1187,6 +3519,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -1208,6 +3541,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -1229,6 +3563,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -1250,6 +3585,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -1271,6 +3607,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -1279,37 +3616,59 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "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/lodash": { "version": "4.17.23", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", "license": "MIT" }, - "node_modules/lodash-es": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", - "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==", - "license": "MIT" - }, - "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==", + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" } }, - "node_modules/marked": { - "version": "17.0.3", - "resolved": "https://registry.npmjs.org/marked/-/marked-17.0.3.tgz", - "integrity": "sha512-jt1v2ObpyOKR8p4XaUJVk3YWRJ5n+i4+rjQopxvV32rSndTJXvIzuUdWWIy/1pFQMkQmvTXawzDNqOH/CUmx6A==", - "license": "MIT", - "bin": { - "marked": "bin/marked.js" - }, - "engines": { - "node": ">= 20" + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "0.460.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.460.0.tgz", + "integrity": "sha512-BVtq/DykVeIvRTJvRAgCsOwaGL8Un3Bxh8MbDxMhEWlZay3T4IpEKDEpwt5KZ0KJMHzgm6jrltxlT5eXOWXDHg==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" } }, "node_modules/math-intrinsics": { @@ -1321,6 +3680,40 @@ "node": ">= 0.4" } }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -1342,41 +3735,22 @@ "node": ">= 0.6" } }, - "node_modules/muggle-string": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", - "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "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/naive-ui": { - "version": "2.43.2", - "resolved": "https://registry.npmjs.org/naive-ui/-/naive-ui-2.43.2.tgz", - "integrity": "sha512-YlLMnGrwGTOc+zMj90sG3ubaH5/7czsgLgGcjTLA981IUaz8r6t4WIujNt8r9PNr+dqv6XNEr0vxkARgPPjfBQ==", + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", "license": "MIT", "dependencies": { - "@css-render/plugin-bem": "^0.15.14", - "@css-render/vue3-ssr": "^0.15.14", - "@types/katex": "^0.16.2", - "@types/lodash": "^4.17.20", - "@types/lodash-es": "^4.17.12", - "async-validator": "^4.2.5", - "css-render": "^0.15.14", - "csstype": "^3.1.3", - "date-fns": "^4.1.0", - "date-fns-tz": "^3.2.0", - "evtd": "^0.2.4", - "highlight.js": "^11.8.0", - "lodash": "^4.17.21", - "lodash-es": "^4.17.21", - "seemly": "^0.3.10", - "treemate": "^0.3.11", - "vdirs": "^0.1.8", - "vooks": "^0.2.12", - "vueuc": "^0.4.65" - }, - "peerDependencies": { - "vue": "^3.0.0" + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" } }, "node_modules/nanoid": { @@ -1397,13 +3771,46 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "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==", + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", "dev": true, "license": "MIT" }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -1414,7 +3821,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -1423,6 +3829,24 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", @@ -1451,56 +3875,564 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "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==", + "license": "MIT" + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "license": "MIT" }, - "node_modules/rolldown": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.4.tgz", - "integrity": "sha512-V2tPDUrY3WSevrvU2E41ijZlpF+5PbZu4giH+VpNraaadsJGHa4fR6IFwsocVwEXDoAdIv5qgPPxgrvKAOIPtA==", + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-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-router": { + "version": "6.30.3", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.3.tgz", + "integrity": "sha512-XRnlbKMTmktBkjCLE8/XcZFlnHvr2Ltdr1eJX4idL55/9BbORzyZEaIkBFDhFGCEWBBItsVrDxwx3gnisMitdw==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.30.3", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.3.tgz", + "integrity": "sha512-pxPcv1AczD4vso7G4Z3TKcvlxK7g7TNt3/FNGMhfqyntocvYKj+GCatfigGDjbLozC4baguJ0ReCigoDJXb0ag==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.2", + "react-router": "6.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/react-smooth": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.4.tgz", + "integrity": "sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==", + "license": "MIT", + "dependencies": { + "fast-equals": "^5.0.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "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/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/recharts": { + "version": "2.15.4", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.4.tgz", + "integrity": "sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==", + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0", + "eventemitter3": "^4.0.1", + "lodash": "^4.17.21", + "react-is": "^18.3.1", + "react-smooth": "^4.0.4", + "recharts-scale": "^0.4.4", + "tiny-invariant": "^1.3.1", + "victory-vendor": "^36.6.8" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/recharts-scale": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", + "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", + "license": "MIT", + "dependencies": { + "decimal.js-light": "^2.4.1" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.113.0", - "@rolldown/pluginutils": "1.0.0-rc.4" + "@types/estree": "1.0.8" }, "bin": { - "rolldown": "bin/cli.mjs" + "rollup": "dist/bin/rollup" }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=18.0.0", + "npm": ">=8.0.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-rc.4", - "@rolldown/binding-darwin-arm64": "1.0.0-rc.4", - "@rolldown/binding-darwin-x64": "1.0.0-rc.4", - "@rolldown/binding-freebsd-x64": "1.0.0-rc.4", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.4", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.4", - "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.4", - "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.4", - "@rolldown/binding-linux-x64-musl": "1.0.0-rc.4", - "@rolldown/binding-openharmony-arm64": "1.0.0-rc.4", - "@rolldown/binding-wasm32-wasi": "1.0.0-rc.4", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.4", - "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.4" + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", + "fsevents": "~2.3.2" } }, - "node_modules/rolldown/node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.4.tgz", - "integrity": "sha512-1BrrmTu0TWfOP1riA8uakjFc9bpIUGzVKETsOtzY39pPga8zELGDl8eu1Dx7/gjM5CAz14UknsUMpBO8L+YntQ==", - "dev": true, - "license": "MIT" + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } }, - "node_modules/seemly": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/seemly/-/seemly-0.3.10.tgz", - "integrity": "sha512-2+SMxtG1PcsL0uyhkumlOU6Qo9TAQ/WyH7tthnPIOQB05/12jz9naq6GZ6iZ6ApVsO3rr2gsnTf3++OV63kE1Q==", - "license": "MIT" + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/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/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/source-map-js": { "version": "1.2.1", @@ -1511,11 +4443,171 @@ "node": ">=0.10.0" } }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sucrase": { + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwind-merge": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.6.1.tgz", + "integrity": "sha512-Oo6tHdpZsGpkKG88HJ8RR1rg/RdnEkQEfMoEk2x1XRI3F1AxeU+ijRXpiVUF4UbLfcxxRGw6TbUINKYdWVsQTQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.19", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", + "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.7", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss-animate": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz", + "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==", + "license": "MIT", + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "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/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", @@ -1528,25 +4620,45 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/treemate": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/treemate/-/treemate-0.3.11.tgz", - "integrity": "sha512-M8RGFoKtZ8dF+iwJfAJTOH/SM4KluKOKRJpjCMhI8bG3qB74zrFoArKZ62ll0Fr3mqkMJiQOmWYkdYgDeITYQg==", - "license": "MIT" + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "license": "Apache-2.0" }, "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", - "optional": true + "license": "0BSD" }, "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "devOptional": true, + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -1557,50 +4669,139 @@ } }, "node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "dev": true, "license": "MIT" }, - "node_modules/vdirs": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/vdirs/-/vdirs-0.1.8.tgz", - "integrity": "sha512-H9V1zGRLQZg9b+GdMk8MXDN2Lva0zx72MPahDKc30v+DtwKjfyOSXWRIX4t2mhDubM1H09gPhWeth/BJWPHGUw==", + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", "dependencies": { - "evtd": "^0.2.2" + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" }, "peerDependencies": { - "vue": "^3.0.11" + "browserslist": ">= 4.21.0" } }, - "node_modules/vfonts": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/vfonts/-/vfonts-0.0.3.tgz", - "integrity": "sha512-nguyw8L6Un8eelg1vQ31vIU2ESxqid7EYmy8V+MDeMaHBqaRSkg3dTBToC1PR00D89UzS/SLkfYPnx0Wf23IQQ==", + "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/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, + "node_modules/victory-vendor": { + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", + "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", + "license": "MIT AND ISC", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, "node_modules/vite": { - "version": "8.0.0-beta.14", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.0-beta.14.tgz", - "integrity": "sha512-oLW66oi8tZcoxu6+1HFXb+5hLHco3OnEVu2Awmj5NqEo7vxaqybjBM0BXHcq+jAFhzkMGXJl8xcO5qDBczgKLg==", + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/runtime": "0.113.0", - "fdir": "^6.5.0", - "lightningcss": "^1.31.1", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rolldown": "1.0.0-rc.4", - "tinyglobby": "^0.2.15" + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": "^18.0.0 || >=20.0.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -1609,35 +4810,25 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.0.0-alpha.31", - "esbuild": "^0.27.0", - "jiti": ">=1.21.0", - "less": "^4.0.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" + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, - "@vitejs/devtools": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "jiti": { - "optional": true - }, "less": { "optional": true }, + "lightningcss": { + "optional": true + }, "sass": { "optional": true }, @@ -1652,114 +4843,100 @@ }, "terser": { "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true } } }, - "node_modules/vooks": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/vooks/-/vooks-0.2.12.tgz", - "integrity": "sha512-iox0I3RZzxtKlcgYaStQYKEzWWGAduMmq+jS7OrNdQo1FgGfPMubGL3uGHOU9n97NIvfFDBGnpSvkWyb/NSn/Q==", + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, "license": "MIT", "dependencies": { - "evtd": "^0.2.2" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, - "peerDependencies": { - "vue": "^3.0.0" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/vscode-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", - "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, - "license": "MIT" + "license": "ISC", + "engines": { + "node": ">=10" + } }, - "node_modules/vue": { - "version": "3.5.28", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.28.tgz", - "integrity": "sha512-BRdrNfeoccSoIZeIhyPBfvWSLFP4q8J3u8Ju8Ug5vu3LdD+yTM13Sg4sKtljxozbnuMu1NB1X5HBHRYUzFocKg==", + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.28", - "@vue/compiler-sfc": "3.5.28", - "@vue/runtime-dom": "3.5.28", - "@vue/server-renderer": "3.5.28", - "@vue/shared": "3.5.28" + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/zustand": { + "version": "4.5.7", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.7.tgz", + "integrity": "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.2.2" + }, + "engines": { + "node": ">=12.7.0" }, "peerDependencies": { - "typescript": "*" + "@types/react": ">=16.8", + "immer": ">=9.0.6", + "react": ">=16.8" }, "peerDependenciesMeta": { - "typescript": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { "optional": true } } - }, - "node_modules/vue-echarts": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/vue-echarts/-/vue-echarts-8.0.1.tgz", - "integrity": "sha512-23rJTFLu1OUEGRWjJGmdGt8fP+8+ja1gVgzMYPIPaHWpXegcO1viIAaeu2H4QHESlVeHzUAHIxKXGrwjsyXAaA==", - "license": "MIT", - "peerDependencies": { - "echarts": "^6.0.0", - "vue": "^3.3.0" - } - }, - "node_modules/vue-tsc": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.2.4.tgz", - "integrity": "sha512-xj3YCvSLNDKt1iF9OcImWHhmYcihVu9p4b9s4PGR/qp6yhW+tZJaypGxHScRyOrdnHvaOeF+YkZOdKwbgGvp5g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@volar/typescript": "2.4.27", - "@vue/language-core": "3.2.4" - }, - "bin": { - "vue-tsc": "bin/vue-tsc.js" - }, - "peerDependencies": { - "typescript": ">=5.0.0" - } - }, - "node_modules/vueuc": { - "version": "0.4.65", - "resolved": "https://registry.npmjs.org/vueuc/-/vueuc-0.4.65.tgz", - "integrity": "sha512-lXuMl+8gsBmruudfxnMF9HW4be8rFziylXFu1VHVNbLVhRTXXV4njvpRuJapD/8q+oFEMSfQMH16E/85VoWRyQ==", - "license": "MIT", - "dependencies": { - "@css-render/vue3-ssr": "^0.15.10", - "@juggle/resize-observer": "^3.3.1", - "css-render": "^0.15.10", - "evtd": "^0.2.4", - "seemly": "^0.3.6", - "vdirs": "^0.1.4", - "vooks": "^0.2.4" - }, - "peerDependencies": { - "vue": "^3.0.11" - } - }, - "node_modules/zrender": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/zrender/-/zrender-6.0.0.tgz", - "integrity": "sha512-41dFXEEXuJpNecuUQq6JlbybmnHaqqpGlbH1yxnA5V9MMP4SbohSVZsJIwz+zdjQXSSlR1Vc34EgH1zxyTDvhg==", - "license": "BSD-3-Clause", - "dependencies": { - "tslib": "2.3.0" - } - }, - "node_modules/zrender/node_modules/tslib": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", - "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", - "license": "0BSD" } } } diff --git a/frontend/package.json b/frontend/package.json index 38b3f089..695313c3 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,31 +1,43 @@ { - "name": "frontend", + "name": "pmflow", "private": true, - "version": "0.0.0", + "version": "0.1.0", "type": "module", "scripts": { - "dev": "vite", - "build": "vue-tsc -b && vite build", + "dev": "vite --host", + "build": "tsc -b && vite build", "preview": "vite preview" }, "dependencies": { - "axios": "^1.13.5", - "echarts": "^6.0.0", - "marked": "^17.0.3", - "naive-ui": "^2.43.2", - "vfonts": "^0.0.3", - "vue": "^3.5.25", - "vue-echarts": "^8.0.1" + "@radix-ui/react-dialog": "^1.0.5", + "@radix-ui/react-dropdown-menu": "^2.0.6", + "@radix-ui/react-label": "^2.1.8", + "@radix-ui/react-slot": "^1.0.2", + "@radix-ui/react-switch": "^1.2.6", + "@radix-ui/react-tabs": "^1.1.13", + "@tanstack/react-query": "^5.60.0", + "axios": "^1.7.0", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", + "lucide-react": "^0.460.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.28.0", + "recharts": "^2.13.0", + "tailwind-merge": "^2.5.0", + "tailwindcss-animate": "^1.0.7", + "zustand": "^4.5.0" }, "devDependencies": { - "@types/node": "^24.10.1", - "@vitejs/plugin-vue": "^6.0.2", - "@vue/tsconfig": "^0.8.1", - "typescript": "~5.9.3", - "vite": "^8.0.0-beta.13", - "vue-tsc": "^3.1.5" - }, - "overrides": { - "vite": "^8.0.0-beta.13" + "@types/node": "^22.0.0", + "@types/react": "^18.3.0", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^4.3.0", + "autoprefixer": "^10.4.20", + "concurrently": "^9.2.1", + "postcss": "^8.4.47", + "tailwindcss": "^3.4.14", + "typescript": "~5.6.0", + "vite": "^5.4.0" } } diff --git a/frontend/postcss.config.js b/frontend/postcss.config.js new file mode 100644 index 00000000..2aa7205d --- /dev/null +++ b/frontend/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/frontend/public/vite.svg b/frontend/public/vite.svg deleted file mode 100644 index e7b8dfb1..00000000 --- a/frontend/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/App.vue b/frontend/src/App.vue deleted file mode 100644 index 2e87a337..00000000 --- a/frontend/src/App.vue +++ /dev/null @@ -1,54 +0,0 @@ - - - - - diff --git a/frontend/src/api/audit.ts b/frontend/src/api/audit.ts new file mode 100644 index 00000000..0491308a --- /dev/null +++ b/frontend/src/api/audit.ts @@ -0,0 +1,46 @@ +/** + * Code Audit API Client + * 代码审计 API 客户端 + */ + +import { apiRequest } from './base' + +export interface CodeAuditRequest { + task_name: string + commit_message: string + code_diff: string + signal_id?: string + commit_sha?: string + file_contexts?: Record +} + +export interface AuditIssue { + severity: 'critical' | 'high' | 'medium' | 'low' | 'info' + category: string + file_path: string + line_number?: number + message: string + suggestion?: string + score_penalty: number +} + +export interface CodeAuditResponse { + signal_id?: string + commit_sha?: string + task_name: string + passed: boolean + score: number + issues: AuditIssue[] + summary: string + details: Record +} + +/** + * 审计代码变更 + */ +export async function auditCodeChange(request: CodeAuditRequest): Promise { + return apiRequest('/audit/code', { + method: 'POST', + body: JSON.stringify(request), + }) +} diff --git a/frontend/src/api/base.ts b/frontend/src/api/base.ts new file mode 100644 index 00000000..b426e824 --- /dev/null +++ b/frontend/src/api/base.ts @@ -0,0 +1,149 @@ +/** + * Base API Client + * 基础 API 客户端 + */ + +// 与 src/lib/api.ts 对齐:开发环境默认走 /api(由 Vite 代理), +// 仅在显式配置 VITE_API_URL / VITE_API_BASE_URL 时直连后端。 +const API_BASE = + import.meta.env.VITE_API_BASE_URL || + import.meta.env.VITE_API_URL || + (import.meta.env.DEV ? '/api' : 'http://127.0.0.1:8000') + +export interface ApiRequestOptions { + method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' + body?: string + headers?: Record +} + +export async function apiRequest(endpoint: string, options: ApiRequestOptions = { method: 'GET' }): Promise { + const url = `${API_BASE}${endpoint}` + + const config: RequestInit = { + method: options.method, + headers: { + 'Content-Type': 'application/json', + ...options.headers, + }, + } + + if (options.body) { + config.body = options.body + } + + try { + const response = await fetch(url, config) + + if (!response.ok) { + const error = await response.json().catch(() => ({ detail: 'Unknown error' })) + throw new Error(error.detail || `HTTP ${response.status}`) + } + + return await response.json() + } catch (error) { + console.error(`API request failed: ${endpoint}`, error) + throw error + } +} + +/** + * WebSocket 客户端 + */ +export class ApiWebSocket { + private ws: WebSocket | null = null + private url: string + private reconnectAttempts = 0 + private maxReconnectAttempts = 5 + private reconnectDelay = 1000 + private messageHandlers: Map void> = new Map() + private connectHandlers: (() => void)[] = [] + private disconnectHandlers: (() => void)[] = [] + + constructor(path: string = '/ws') { + const wsUrl = API_BASE.replace('http://', 'ws://').replace('https://', 'wss://') + this.url = `${wsUrl}${path}` + } + + connect(): void { + if (this.ws?.readyState === WebSocket.OPEN) { + return + } + + try { + this.ws = new WebSocket(this.url) + + this.ws.onopen = () => { + console.log('[WebSocket] Connected') + this.reconnectAttempts = 0 + this.connectHandlers.forEach(handler => handler()) + } + + this.ws.onmessage = (event) => { + try { + const data = JSON.parse(event.data) + const messageType = data.type + + if (messageType && this.messageHandlers.has(messageType)) { + this.messageHandlers.get(messageType)!(data) + } + } catch (error) { + console.error('[WebSocket] Message parse error:', error) + } + } + + this.ws.onclose = () => { + console.log('[WebSocket] Disconnected') + this.disconnectHandlers.forEach(handler => handler()) + + // Attempt reconnection + if (this.reconnectAttempts < this.maxReconnectAttempts) { + this.reconnectAttempts++ + const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1) + console.log(`[WebSocket] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`) + setTimeout(() => this.connect(), delay) + } + } + + this.ws.onerror = (error) => { + console.error('[WebSocket] Error:', error) + } + } catch (error) { + console.error('[WebSocket] Connection failed:', error) + } + } + + disconnect(): void { + if (this.ws) { + this.ws.close() + this.ws = null + } + } + + send(data: any): void { + if (this.ws?.readyState === WebSocket.OPEN) { + this.ws.send(JSON.stringify(data)) + } + } + + subscribe(eventType: string, handler: (data: any) => void): void { + this.messageHandlers.set(eventType, handler) + this.send({ type: 'subscribe', event_types: [eventType] }) + } + + unsubscribe(eventType: string): void { + this.messageHandlers.delete(eventType) + this.send({ type: 'unsubscribe', event_types: [eventType] }) + } + + onConnect(handler: () => void): void { + this.connectHandlers.push(handler) + } + + onDisconnect(handler: () => void): void { + this.disconnectHandlers.push(handler) + } + + isConnected(): boolean { + return this.ws?.readyState === WebSocket.OPEN + } +} diff --git a/frontend/src/api/budget.ts b/frontend/src/api/budget.ts new file mode 100644 index 00000000..2bd951dd --- /dev/null +++ b/frontend/src/api/budget.ts @@ -0,0 +1,93 @@ +import { api } from "@/lib/api"; + +interface ApiEnvelope { + code: number; + message: string; + data: T; +} + +function unwrap(payload: ApiEnvelope): T { + if (payload.code !== 0) { + throw new Error(payload.message || "Request failed"); + } + return payload.data; +} + +export interface BudgetItem { + id: number; + budget_type: "tenant" | "project"; + project_id: number | null; + period: "monthly" | "quarterly" | "yearly"; + budget_amount_usd: number; + alert_threshold_percent: number; + hard_limit_enabled: boolean; + current_usage_usd: number; + status: "active" | "suspended" | "overridden"; + current_period_start?: string | null; + current_period_end?: string | null; +} + +export interface BudgetAlertItem { + id: number; + budget_id: number; + alert_type: string; + usage_usd: number; + usage_percent: number; + message: string; + is_read: boolean; + action_taken?: string | null; + status: string; + created_at?: string | null; +} + +export const budgetApi = { + async list(params?: { budget_type?: "tenant" | "project"; project_id?: number }) { + const { data } = await api.get>("/budget/", { params }); + return unwrap(data); + }, + + async create(payload: { + budget_type: "tenant" | "project"; + project_id?: number; + period: "monthly" | "quarterly" | "yearly"; + budget_amount_usd: number; + alert_threshold_percent?: number; + hard_limit_enabled?: boolean; + }) { + const { data } = await api.post>("/budget/", payload); + return unwrap(data); + }, + + async update( + budgetId: number, + payload: Partial<{ + period: "monthly" | "quarterly" | "yearly"; + budget_amount_usd: number; + alert_threshold_percent: number; + hard_limit_enabled: boolean; + status: "active" | "suspended" | "overridden"; + }> + ) { + const { data } = await api.patch>(`/budget/${budgetId}`, payload); + return unwrap(data); + }, + + async override(budgetId: number, payload: { note?: string; duration_hours?: number }) { + const { data } = await api.post>>( + `/budget/${budgetId}/override`, + payload + ); + return unwrap(data); + }, + + async alerts(params?: { budget_id?: number; unread_only?: boolean; limit?: number }) { + const { data } = await api.get>("/budget/alerts", { params }); + return unwrap(data); + }, + + async check(payload: { estimated_cost_usd: number; project_id?: number }) { + const { data } = await api.post>>("/budget/check", payload); + return unwrap(data); + }, +}; + diff --git a/frontend/src/api/codegen.ts b/frontend/src/api/codegen.ts new file mode 100644 index 00000000..dec343c5 --- /dev/null +++ b/frontend/src/api/codegen.ts @@ -0,0 +1,55 @@ +/** + * Code Draft Generation API Client + * 代码草案生成 API 客户端 + */ + +import { apiRequest } from './base' + +export interface CodeDraftRequest { + signal_id: string + signal_content: string + strategic_analysis: Record + target_files: string[] + project_root?: string +} + +export interface GeneratedFile { + path: string + content: string + language: string + diff: string + is_new: boolean + review_points: string[] + lines_count?: number +} + +export interface CodeDraftResponse { + success: boolean + files: GeneratedFile[] + summary: string + confidence: number + warnings: string[] + review_points: string[] + estimated_complexity: 'low' | 'medium' | 'high' + generation_time: number + metadata: Record +} + +/** + * 生成代码草案 + */ +export async function generateCodeDraft(request: CodeDraftRequest): Promise { + return apiRequest('/codegen/generate', { + method: 'POST', + body: JSON.stringify(request), + }) +} + +/** + * 获取代码草案 + */ +export async function getCodeDraft(signalId: string): Promise { + return apiRequest(`/codegen/draft/${signalId}`, { + method: 'GET', + }) +} diff --git a/frontend/src/api/domain.ts b/frontend/src/api/domain.ts new file mode 100644 index 00000000..70019aff --- /dev/null +++ b/frontend/src/api/domain.ts @@ -0,0 +1,144 @@ +/** + * Project Domain API Client + * 项目域 API 客户端 + */ + +import { apiRequest } from './base' + +export interface DomainConfig { + signal_sources: string[] + ai_config: Record + audit_threshold: number + auto_merge_enabled: boolean + webhook_urls: Record +} + +export interface ProjectDomain { + id: string + name: string + slug: string + description: string | null + config: DomainConfig + is_active: boolean + is_default: boolean + signal_count: number + context_node_count: number + experiment_count: number + created_at: string + updated_at: string + last_synced_at: string | null +} + +export interface ProjectDomainCreate { + name: string + slug: string + description?: string + config?: Partial + is_default?: boolean +} + +export interface ProjectDomainUpdate { + name?: string + description?: string + config?: Partial + is_active?: boolean + is_default?: boolean +} + +export interface DomainSyncProgress { + domain_id: string + phase: string + progress: number + message: string +} + +export interface DomainsListResponse { + domains: ProjectDomain[] + total: number +} + +/** + * 创建项目域 + */ +export async function createDomain(request: ProjectDomainCreate): Promise { + return apiRequest('/domains/', { + method: 'POST', + body: JSON.stringify(request), + }) +} + +/** + * 列出所有项目域 + */ +export async function getDomains(includeInactive = false): Promise { + return apiRequest(`/domains/?include_inactive=${includeInactive}`, { + method: 'GET', + }) +} + +/** + * 获取单个项目域 + */ +export async function getDomain(domainId: string): Promise { + return apiRequest(`/domains/${domainId}`, { + method: 'GET', + }) +} + +/** + * 通过 slug 获取项目域 + */ +export async function getDomainBySlug(slug: string): Promise { + return apiRequest(`/domains/by-slug/${slug}`, { + method: 'GET', + }) +} + +/** + * 更新项目域 + */ +export async function updateDomain( + domainId: string, + request: ProjectDomainUpdate +): Promise { + return apiRequest(`/domains/${domainId}`, { + method: 'PATCH', + body: JSON.stringify(request), + }) +} + +/** + * 删除项目域 + */ +export async function deleteDomain(domainId: string): Promise<{ status: string; domain_id: string }> { + return apiRequest<{ status: string; domain_id: string }>(`/domains/${domainId}`, { + method: 'DELETE', + }) +} + +/** + * 切换活动项目域 + */ +export async function switchDomain(domainId: string): Promise { + return apiRequest(`/domains/${domainId}/switch`, { + method: 'POST', + }) +} + +/** + * 获取默认项目域 + */ +export async function getDefaultDomain(): Promise { + return apiRequest('/domains/default', { + method: 'GET', + }) +} + +/** + * 同步项目域统计信息 + */ +export async function syncDomainStats(domainId: string): Promise<{ status: string; domain_id: string }> { + return apiRequest<{ status: string; domain_id: string }>(`/domains/${domainId}/sync-stats`, { + method: 'POST', + }) +} diff --git a/frontend/src/api/index.ts b/frontend/src/api/index.ts new file mode 100644 index 00000000..e80bf81e --- /dev/null +++ b/frontend/src/api/index.ts @@ -0,0 +1,13 @@ +/** + * API Client Exports + */ + +export * from './base' +export * from './codegen' +export * from './audit' +export * from './merge' +export * from './domain' +export * from './integration' +export * from './projects' +export * from './modelCapability' +export * from './budget' diff --git a/frontend/src/api/integration.ts b/frontend/src/api/integration.ts new file mode 100644 index 00000000..340ba101 --- /dev/null +++ b/frontend/src/api/integration.ts @@ -0,0 +1,184 @@ +/** + * Integration API Client + * 集成 API 客户端 - Plane 和飞书 + */ + +import { apiRequest } from './base' + +export interface IntegrationHealth { + status: 'active' | 'inactive' | 'error' | 'degraded' | 'pending' + last_check: string + last_success?: string + last_error?: string + error_count: number + consecutive_failures: number + latency_ms?: number + message: string +} + +export interface IntegrationStats { + synced?: number + sent?: number + failed: number +} + +export interface IntegrationStatus { + plane: IntegrationHealth + lark: IntegrationHealth +} + +export interface IntegrationConfig { + plane: PlaneConfig + lark: LarkConfig +} + +export interface PlaneConfig { + api_url: string + api_key: string + workspace_slug: string + project_id: string + enabled: boolean +} + +export interface LarkConfig { + app_id: string + app_secret: string + verification_token: string + encrypt_key: string + default_chat_id: string + enabled: boolean +} + +export interface TaskSyncRequest { + tasks: Array<{ + task_name: string + type: string + estimated_hours: number + }> + is_urgent?: boolean +} + +export interface TaskSyncResult { + success: boolean + integration_type: string + tasks_created: number + tasks_updated: number + errors: string[] + details: Record +} + +export interface NotificationRequest { + chat_id: string + signal_content?: string + content?: string + decision?: Record + tasks?: Array +} + +/** + * 获取所有集成状态 + */ +export async function getIntegrationStatus(): Promise { + return apiRequest('/integrations/status', { + method: 'GET', + }) +} + +/** + * 获取集成统计 + */ +export async function getIntegrationStats(): Promise> { + return apiRequest>('/integrations/stats', { + method: 'GET', + }) +} + +/** + * 获取集成配置 + */ +export async function getIntegrationConfig(): Promise { + return apiRequest('/integrations/config', { + method: 'GET', + }) +} + +/** + * 更新集成配置 + */ +export async function updateIntegrationConfig(config: IntegrationConfig): Promise { + return apiRequest('/integrations/config', { + method: 'POST', + body: JSON.stringify(config), + }) +} + +/** + * 测试 Plane 连接 + */ +export async function testPlaneConnection(): Promise { + return apiRequest('/integrations/plane/test', { + method: 'POST', + }) +} + +/** + * 测试飞书连接 + */ +export async function testLarkConnection(): Promise { + return apiRequest('/integrations/lark/test', { + method: 'POST', + }) +} + +/** + * 同步任务到 Plane + */ +export async function syncTasksToPlane(request: TaskSyncRequest): Promise { + return apiRequest('/integrations/plane/sync', { + method: 'POST', + body: JSON.stringify(request), + }) +} + +/** + * 更新 Plane 工单状态 + */ +export async function updatePlaneIssue( + issueId: string, + status: string +): Promise<{ success: boolean }> { + return apiRequest<{ success: boolean }>(`/integrations/plane/issues/${issueId}/status`, { + method: 'PATCH', + body: JSON.stringify({ status }), + }) +} + +/** + * 发送战略预警到飞书 + */ +export async function sendStrategicAlert(request: NotificationRequest): Promise<{ + success: boolean + integration_type: string + recipients: number + error?: string +}> { + return apiRequest('/integrations/lark/alert', { + method: 'POST', + body: JSON.stringify(request), + }) +} + +/** + * 发送卡片消息到飞书 + */ +export async function sendCardMessage(request: NotificationRequest): Promise<{ + success: boolean + integration_type: string + recipients: number + error?: string +}> { + return apiRequest('/integrations/lark/card', { + method: 'POST', + body: JSON.stringify(request), + }) +} diff --git a/frontend/src/api/merge.ts b/frontend/src/api/merge.ts new file mode 100644 index 00000000..31045015 --- /dev/null +++ b/frontend/src/api/merge.ts @@ -0,0 +1,89 @@ +/** + * Auto Merge API Client + * 自动合并 API 客户端 + */ + +import { apiRequest } from './base' + +export interface MergeRequest { + signal_id: string + commit_sha: string + task_name: string + audit_score: number + test_results: Record + requester?: string +} + +export interface MergeResponse { + status: 'pending' | 'waiting_confirmation' | 'approved' | 'rejected' | 'failed' | 'cooldown' + success: boolean + merge_sha?: string + reason?: string + requires_human_confirmation: boolean + confirmation_token?: string + cooldown_remaining?: number + details: Record +} + +export interface MergeConfirmation { + token: string + task_name: string + commit_sha: string + audit_score: number + created_at: number + expires_at: number + time_remaining: number +} + +export interface PendingConfirmationsResponse { + pending_count: number + confirmations: MergeConfirmation[] +} + +export interface MergeStatus { + audit_threshold: number + human_confirmation_required: boolean + failure_count: number + successful_merges: number + in_cooldown: boolean + cooldown_remaining: number + pending_confirmations: number +} + +/** + * 请求自动合并 + */ +export async function requestAutoMerge(request: MergeRequest): Promise { + return apiRequest('/merge/request', { + method: 'POST', + body: JSON.stringify(request), + }) +} + +/** + * 确认合并 + */ +export async function confirmMerge(token: string, requester: string, approve: boolean): Promise { + return apiRequest('/merge/confirm', { + method: 'POST', + body: JSON.stringify({ token, requester, approve }), + }) +} + +/** + * 获取待确认的合并请求 + */ +export async function getPendingConfirmations(): Promise { + return apiRequest('/merge/pending', { + method: 'GET', + }) +} + +/** + * 获取自动合并服务状态 + */ +export async function getMergeStatus(): Promise { + return apiRequest('/merge/status', { + method: 'GET', + }) +} diff --git a/frontend/src/api/modelCapability.ts b/frontend/src/api/modelCapability.ts new file mode 100644 index 00000000..351f87e8 --- /dev/null +++ b/frontend/src/api/modelCapability.ts @@ -0,0 +1,275 @@ +import { api } from "@/lib/api"; + +interface ApiEnvelope { + code: number; + message: string; + data: T; +} + +function unwrap(payload: ApiEnvelope): T { + if (payload.code !== 0) { + throw new Error(payload.message || "Request failed"); + } + return payload.data; +} + +export interface ValidateMatchPayload { + truth_node_id: number; + model_version_id: number; + project_id?: number; +} + +export interface CapabilityGapItem { + id: number; + gap_type: string; + severity: string; + description: string; + ai_analysis: Record; + status: string; + created_at?: string | null; + resolved_at?: string | null; +} + +export interface CapabilityGapsData { + gaps: CapabilityGapItem[]; + total: number; +} + +export interface CostTrackingData { + id?: number; + truth_node_id: number; + period: string; + estimated_tokens: number; + actual_tokens: number; + estimated_cost_usd: number; + actual_cost_usd: number; + roi_score: number | null; + roi_analysis: Record; + optimization_suggestions: Record; +} + +export interface CostOptimizationData { + truth_node_id: number; + period: string; + optimization_suggestions: Record; + roi_score: number | null; + actual_cost_usd: number; +} + +export interface LifecycleImpactData { + impact_id: number; + affected_truth_nodes: Record; + cost_change_percentage: number; + performance_change: Record; + compatibility_risks: Record; + recommendation: string; + status: string; +} + +export interface LifecycleImpactListData { + items: Array<{ + id: number; + old_model_version_id: number; + new_model_version_id: number; + cost_change_percentage: number; + recommendation: string; + status: string; + created_at?: string | null; + }>; +} + +export interface MigrationTasksData { + impact_id: number; + status: string; + migration_tasks: { + tasks: Array<{ + title: string; + type: string; + priority: string; + estimated_hours: number; + notes?: string; + }>; + }; +} + +export interface ExperimentSyncData { + sync_id: number; + confidence_score: number; + auto_applied: boolean; + apply_status: string; + sync_data: Record; +} + +export interface ExperimentSyncListData { + items: Array<{ + id: number; + experiment_id: number; + truth_node_id: number; + sync_type: string; + confidence_score: number; + auto_applied: boolean; + apply_status: string; + created_at?: string | null; + }>; +} + +export interface ProjectTruthNodeContextData { + items: Array<{ + id: number; + title: string; + status: string; + node_type: string; + }>; +} + +export interface ProjectExperimentContextData { + items: Array<{ + id: number; + title: string; + status: string; + target_metric?: string | null; + }>; +} + +export interface CostOptimizationAnalyzeData { + truth_node_id: number; + period: string; + monthly_cost: number; + recommendations: Array<{ + type: string; + priority: string; + description: string; + estimated_savings_percent: number; + }>; + total_potential_savings_percent: number; + estimated_monthly_savings_usd: number; +} + +export const modelCapabilityApi = { + async validateMatch(payload: ValidateMatchPayload) { + const { data } = await api.post>>( + "/model-capability/validate-match", + payload + ); + return unwrap(data); + }, + + async listCapabilityGaps(params?: { severity?: string; status?: string; limit?: number }) { + const { data } = await api.get>( + "/model-capability/capability-gaps", + { params } + ); + return unwrap(data); + }, + + async getCostTracking(truthNodeId: number, period: string = "weekly") { + const { data } = await api.get>( + `/model-capability/cost-tracking/${truthNodeId}`, + { params: { period } } + ); + return unwrap(data); + }, + + async getCostOptimization(truthNodeId: number, period: string = "weekly") { + const { data } = await api.get>( + `/model-capability/cost-optimization/${truthNodeId}`, + { params: { period } } + ); + return unwrap(data); + }, + + async assessLifecycleImpact(payload: { + old_model_version_id: number; + new_model_version_id: number; + }) { + const { data } = await api.post>( + "/model-capability/lifecycle/assess-impact", + payload + ); + return unwrap(data); + }, + + async listLifecycleImpacts(limit: number = 20) { + const { data } = await api.get>( + "/model-capability/lifecycle/impacts", + { params: { limit } } + ); + return unwrap(data); + }, + + async generateMigrationTasks(impactId: number, max_tasks: number = 5) { + const { data } = await api.post>( + `/model-capability/lifecycle/${impactId}/migration-tasks`, + { max_tasks } + ); + return unwrap(data); + }, + + async createExperimentSync(payload: { + experiment_id: number; + truth_node_id: number; + project_id?: number; + sync_type: "result_sync" | "metric_update" | "conclusion_sync"; + auto_apply_threshold?: number; + }) { + const { data } = await api.post>( + "/model-capability/experiment-sync", + payload + ); + return unwrap(data); + }, + + async listExperimentSync(params?: { truth_node_id?: number; limit?: number }) { + const { data } = await api.get>( + "/model-capability/experiment-sync", + { params } + ); + return unwrap(data); + }, + + async reviewExperimentSync( + syncId: number, + payload: { action: "approve" | "reject"; review_notes?: string } + ) { + const { data } = await api.post>>( + `/model-capability/experiment-sync/${syncId}/review`, + payload + ); + return unwrap(data); + }, + + async rollbackExperimentSync(syncId: number, rollback_notes?: string) { + const { data } = await api.post>>( + `/model-capability/experiment-sync/${syncId}/rollback`, + { rollback_notes } + ); + return unwrap(data); + }, + + async analyzeCostOptimization(payload: { + truth_node_id: number; + project_id?: number; + period?: string; + }) { + const { data } = await api.post>( + "/model-capability/cost-optimization/analyze", + payload + ); + return unwrap(data); + }, + + async listProjectTruthNodes(projectId: number) { + const { data } = await api.get>( + `/model-capability/context/projects/${projectId}/truth-nodes` + ); + return unwrap(data); + }, + + async listProjectExperiments(projectId: number) { + const { data } = await api.get>( + `/model-capability/context/projects/${projectId}/experiments` + ); + return unwrap(data); + }, +}; + diff --git a/frontend/src/api/projects.ts b/frontend/src/api/projects.ts new file mode 100644 index 00000000..8b1026ed --- /dev/null +++ b/frontend/src/api/projects.ts @@ -0,0 +1,300 @@ +/** + * Projects API Client + * + * API 客户端用于项目 (Projects) 相关操作 + * 项目代表大需求/需求集合,可以关联多个信号 + */ + +import { apiRequest } from './base' + +/** + * 项目状态 + */ +export type ProjectStatus = 'active' | 'completed' | 'archived' | 'on_hold' + +/** + * 角色类型 + */ +export type AssignedRole = 'boss' | 'ai_engineer' | 'backend' | 'frontend' + +/** + * 项目数据结构 + */ +export interface Project { + id: string + title: string + description: string | null + status: ProjectStatus + domain_id: string | null + assigned_role: AssignedRole | null + signal_count: number + created_at: string + updated_at: string +} + +/** + * 项目信号关联数据结构 + */ +export interface ProjectSignal { + id: string + source: string + content: string + impact_score: number + priority: string + processed: boolean + created_at: string + link_type: string + relevance_score: number +} + +/** + * 项目信号关联链接数据结构 + */ +export interface ProjectSignalLink { + id: string + project_id: string + signal_id: string + link_type: string + relevance_score: number + created_at: string +} + +/** + * 创建项目请求 + */ +export interface ProjectCreateRequest { + title: string + description?: string + status?: ProjectStatus + domain_id?: string + assigned_role?: AssignedRole +} + +/** + * 更新项目请求 + */ +export interface ProjectUpdateRequest { + title?: string + description?: string + status?: ProjectStatus + domain_id?: string + assigned_role?: AssignedRole +} + +/** + * 关联信号请求 + */ +export interface LinkSignalRequest { + signal_id: string + link_type?: string + relevance_score?: number +} + +/** + * 从本地路径导入项目请求 + */ +export interface ImportProjectFromPathRequest { + path: string + title?: string + description?: string + assigned_role?: AssignedRole +} + +/** + * 从 Git 仓库导入项目请求 + */ +export interface ImportProjectFromGitRequest { + git_url: string + branch?: string + title?: string + description?: string + assigned_role?: AssignedRole +} + +/** + * 项目进度信息(基于任务完成状态自动识别) + */ +export interface ProjectProgress { + progress: number + total_tasks: number + completed_tasks: number +} + +/** + * 任务项(用于可视化) + */ +export interface ProjectTaskItem { + task_name: string + type: string + status: string + signal_id: string +} + +/** + * 项目汇总(含任务可视化数据,从信号完成度获取进度) + */ +export interface ProjectSummary { + id: string + title: string + description: string | null + status: ProjectStatus + domain_id: string | null + assigned_role: AssignedRole | null + signal_count: number + created_at: string + updated_at: string + progress: number + total_tasks: number + completed_tasks: number + in_progress_tasks: number + pending_tasks: number + tasks: ProjectTaskItem[] +} + +/** + * Projects API + */ +export const projectsApi = { + /** + * 获取各项目任务进度(自动识别 tasks_generated 中的完成状态) + */ + async getProgress(): Promise> { + return apiRequest>('/project-progress') + }, + + /** + * 动态获取项目汇总(含任务可视化数据,从信号完成度获取进度) + * 支持多项目,可按 status、assigned_role 筛选 + */ + async getSummary(params?: { + status?: ProjectStatus + assigned_role?: AssignedRole + }): Promise<{ projects: ProjectSummary[] }> { + const query = new URLSearchParams() + query.append('summary', '1') + if (params?.status) query.append('status', params.status) + if (params?.assigned_role) query.append('assigned_role', params.assigned_role) + return apiRequest<{ projects: ProjectSummary[] }>(`/projects/?${query}`) + }, + + /** + * 创建新项目 + */ + async create(data: ProjectCreateRequest): Promise { + return apiRequest('/projects/', { + method: 'POST', + body: JSON.stringify(data), + }) + }, + + /** + * 列出所有项目 + */ + async list(params?: { + status?: ProjectStatus + assigned_role?: AssignedRole + }): Promise { + const query = new URLSearchParams() + if (params?.status) query.append('status', params.status) + if (params?.assigned_role) query.append('assigned_role', params.assigned_role) + const queryString = query.toString() + return apiRequest(`/projects/${queryString ? '?' + queryString : ''}`) + }, + + /** + * 获取单个项目详情 + */ + async get(projectId: string): Promise { + return apiRequest(`/projects/${projectId}`) + }, + + /** + * 获取项目关联的所有信号 + */ + async getSignals(projectId: string): Promise { + return apiRequest(`/projects/${projectId}/signals`) + }, + + /** + * 关联信号到项目 + */ + async linkSignal( + projectId: string, + data: LinkSignalRequest + ): Promise { + return apiRequest( + `/projects/${projectId}/signals/${data.signal_id}`, + { + method: 'POST', + body: JSON.stringify(data), + } + ) + }, + + /** + * 获取信号关联的所有项目 + */ + async getSignalProjects(signalId: string): Promise> { + return apiRequest(`/signals/${signalId}/projects`) + }, + + /** + * 解除信号关联 + */ + async unlinkSignal(projectId: string, signalId: string): Promise { + await apiRequest(`/projects/${projectId}/signals/${signalId}`, { + method: 'DELETE', + }) + }, + + /** + * 更新项目信息 + */ + async update( + projectId: string, + data: ProjectUpdateRequest + ): Promise { + return apiRequest(`/projects/${projectId}`, { + method: 'PATCH', + body: JSON.stringify(data), + }) + }, + + /** + * 删除项目 + */ + async delete(projectId: string): Promise { + await apiRequest(`/projects/${projectId}`, { + method: 'DELETE', + }) + }, + + /** + * 从本地路径导入项目 + */ + async importFromPath(data: ImportProjectFromPathRequest): Promise { + return apiRequest('/projects/import/path', { + method: 'POST', + body: JSON.stringify(data), + }) + }, + + /** + * 从 Git 仓库导入项目 + */ + async importFromGit(data: ImportProjectFromGitRequest): Promise { + return apiRequest('/projects/import/git', { + method: 'POST', + body: JSON.stringify(data), + }) + }, +} + +export default projectsApi diff --git a/frontend/src/api/scheduler.ts b/frontend/src/api/scheduler.ts new file mode 100644 index 00000000..e69de29b diff --git a/frontend/src/api/skill.ts b/frontend/src/api/skill.ts new file mode 100644 index 00000000..407c4e85 --- /dev/null +++ b/frontend/src/api/skill.ts @@ -0,0 +1,267 @@ +import { api } from "@/lib/api"; + +export interface SkillTag { + id: string; + tenant_id?: string; + name: string; + slug: string; + category?: string | null; + description?: string | null; + is_system?: boolean; + sort_order?: number; + linked_user_count?: number; + created_at?: string | null; + updated_at?: string | null; +} + +export interface UserSkillBinding { + skill_tag_id: string; + skill_name: string; + category?: string | null; + proficiency: number; + level: string; + quality_score?: number | null; + efficiency_score?: number | null; + last_used_at?: string | null; + is_system?: boolean; +} + +export interface PersonnelRecommendationItem { + user_id: string; + user_name: string; + match_score: number; + reason: string; + skill_match_count: number; + avg_proficiency: number; + workload_rate: number; + recommended_role?: string | null; +} + +export interface PersonnelRecommendationResponse { + task_id?: string | null; + task_description?: string | null; + required_skills: string[]; + recommendations: PersonnelRecommendationItem[]; + total_count: number; +} + +export interface UserSkillTaskItem { + id: string; + title: string; + description?: string | null; + status?: string | null; + priority?: string | null; + estimated_hours?: number | null; + updated_at?: string | null; + project_title?: string | null; + charter_title?: string | null; +} + +export const SKILL_CATEGORIES = [ + { value: "dev", label: "开发" }, + { value: "algorithm", label: "算法" }, + { value: "product", label: "产品" }, + { value: "pm", label: "项目管理" }, + { value: "qa", label: "测试" }, +] as const; + +export type SkillCategory = (typeof SKILL_CATEGORIES)[number]["value"]; + +function normalizeSkillTags(raw: unknown): SkillTag[] { + const toTag = (item: unknown): SkillTag => { + const row = item as Partial & { id?: string | number }; + return { + id: String(row.id ?? ""), + tenant_id: row.tenant_id != null ? String(row.tenant_id) : undefined, + name: String(row.name ?? ""), + slug: String(row.slug ?? ""), + category: row.category ?? null, + description: row.description ?? null, + is_system: Boolean(row.is_system), + sort_order: row.sort_order != null ? Number(row.sort_order) : undefined, + linked_user_count: row.linked_user_count != null ? Number(row.linked_user_count) : undefined, + created_at: row.created_at ?? null, + updated_at: row.updated_at ?? null, + }; + }; + if (Array.isArray(raw)) return raw.map(toTag); + const wrapped = raw as { items?: unknown[] } | undefined; + return Array.isArray(wrapped?.items) ? wrapped.items.map(toTag) : []; +} + +function normalizeUserSkills(raw: unknown): UserSkillBinding[] { + if (Array.isArray(raw)) { + return raw.map((item) => { + const row = item as Partial & { id?: string; user_id?: string }; + return { + skill_tag_id: String(row.skill_tag_id ?? row.id ?? ""), + skill_name: String(row.skill_name ?? ""), + category: (row as { category?: string | null }).category ?? null, + proficiency: Number(row.proficiency ?? 0), + level: String(row.level ?? "beginner"), + quality_score: row.quality_score ?? null, + efficiency_score: row.efficiency_score ?? null, + last_used_at: row.last_used_at ?? null, + is_system: row.is_system ?? false, + }; + }); + } + const wrapped = raw as { items?: unknown[] } | undefined; + if (!Array.isArray(wrapped?.items)) return []; + return wrapped.items.map((item) => { + const row = item as Partial & { id?: string }; + return { + skill_tag_id: String(row.skill_tag_id ?? row.id ?? ""), + skill_name: String(row.skill_name ?? ""), + category: (row as { category?: string | null }).category ?? null, + proficiency: Number(row.proficiency ?? 0), + level: String(row.level ?? "beginner"), + quality_score: row.quality_score ?? null, + efficiency_score: row.efficiency_score ?? null, + last_used_at: row.last_used_at ?? null, + is_system: row.is_system ?? false, + }; + }); +} + +export async function getSkillTags(params?: { category?: string | null; include_system?: boolean }) { + try { + const res = await api.get<{ items: SkillTag[] }>("/skill-tags", { params: { category: params?.category } }); + return normalizeSkillTags(res.data); + } catch { + const res = await api.get("/skills/tags", { params }); + return normalizeSkillTags(res.data); + } +} + +export async function createSkillTag(data: { + name: string; + slug: string; + category?: string | null; + description?: string | null; +}) { + const res = await api.post("/skill-tags", data); + return res.data; +} + +export async function updateSkillTag( + tagId: string, + data: { name?: string; category?: string | null; description?: string | null; sort_order?: number } +) { + const res = await api.put(`/skill-tags/${tagId}`, data); + return res.data; +} + +export async function deleteSkillTag(tagId: string) { + const res = await api.delete<{ message: string }>(`/skill-tags/${tagId}`); + return res.data; +} + +export async function getUserSkillBindings(userId: string) { + try { + const res = await api.get<{ items: UserSkillBinding[] }>(`/users/${userId}/skills`); + return normalizeUserSkills(res.data); + } catch { + const res = await api.get( + `/skills/users/${userId}/bindings` + ); + return normalizeUserSkills(res.data); + } +} + +export async function addUserSkill( + userId: string, + payload: { + skill_tag_id: string; + level?: string; + proficiency?: number; + quality_score?: number; + efficiency_score?: number; + } +) { + const res = await api.post<{ message: string }>(`/users/${userId}/skills`, payload); + return res.data; +} + +export async function updateUserSkill( + userId: string, + skillId: string, + payload: { + level?: string; + proficiency?: number; + quality_score?: number; + efficiency_score?: number; + } +) { + const res = await api.put<{ message: string }>(`/users/${userId}/skills/${skillId}`, payload); + return res.data; +} + +export async function removeUserSkill(userId: string, skillId: string) { + const res = await api.delete<{ message: string }>(`/users/${userId}/skills/${skillId}`); + return res.data; +} + +export async function batchUpdateUserSkillBindings( + userId: string, + bindings: Array<{ + skill_tag_id: string; + proficiency?: number; + level?: string; + years_experience?: number; + }> +) { + const res = await api.put<{ updated_count: number; message: string }>( + `/skills/users/${userId}/bindings/batch`, + { bindings } + ); + return res.data; +} + +export async function recommendPersonnel(params: { + skills: string; + task_description?: string | null; + task_id?: string | null; + limit?: number; +}) { + const res = await api.get("/skills/recommend", { params }); + return res.data; +} + +export async function getUserSkillTasks( + userId: string, + skillId: string +): Promise<{ items: UserSkillTaskItem[]; total: number }> { + const candidates = [ + `/skills/users/${userId}/tasks`, + `/skills/users/${userId}/skill-tasks/${skillId}`, + `/skills/tasks/history`, + ] as const; + + for (const path of candidates) { + try { + const res = await api.get<{ items?: UserSkillTaskItem[]; total?: number } | UserSkillTaskItem[]>( + path, + { + params: + path === `/skills/users/${userId}/tasks` + ? { skill_id: skillId } + : path === `/skills/tasks/history` + ? { user_id: userId, skill_id: skillId } + : undefined, + } + ); + + const raw = res.data; + const items = Array.isArray(raw) ? raw : (raw.items ?? []); + const total = Array.isArray(raw) ? raw.length : (raw.total ?? items.length); + return { items, total }; + } catch (error) { + const status = (error as { response?: { status?: number } })?.response?.status; + if (status === 404 || status === 405) continue; + throw error; + } + } + + return { items: [], total: 0 }; +} diff --git a/frontend/src/api/sstc.ts b/frontend/src/api/sstc.ts new file mode 100644 index 00000000..375036ca --- /dev/null +++ b/frontend/src/api/sstc.ts @@ -0,0 +1,469 @@ +/** + * SSTC 看板 API + */ + +import { api } from "@/lib/api"; + +type ApiEnvelope = { code: number; message: string; data: T }; + +function unwrap(raw: ApiEnvelope | T): T { + if (raw && typeof raw === "object" && "data" in (raw as Record)) { + return (raw as ApiEnvelope).data; + } + return raw as T; +} + +export type StageKey = + | "signal" + | "charter" + | "task" + | "execution" + | "release" + | "review"; + +export interface SSTCStageNode { + key: StageKey; + label: string; + status: string; + summary: string; + locked: boolean; + editable: boolean; + risk_count: number; +} + +export interface SSTCSignal { + id: string; + title?: string; + source: string; + content: string; + impact_score?: number; + priority?: string; + status?: string; + signal_type?: string; + processed?: boolean; + created_at?: string | null; +} + +export interface SSTCCharter { + id: string; + title: string; + content: Record; + signal_ids: number[]; + status: string; + version: number; + parent_id?: string | null; + created_at?: string | null; +} + +export interface SSTCTask { + id: string; + title: string; + status: string; + priority: string; + charter_id?: string; + description?: string; + estimated_hours?: number | null; + assignee_id?: string | null; + due_date?: string | null; + risk_count?: number; + truth_node_id?: string; +} + +export interface SSTCTaskRecommendation { + user_id: string; + user_name: string; + match_score: number; + reason: string; + skill_match_count: number; + avg_proficiency: number; + workload_rate: number; + recommended_role?: string | null; +} + +export interface SSTCTaskAssigneeRecommendationResponse { + task_id: string; + required_skills: string[]; + recommendations: SSTCTaskRecommendation[]; + total_count: number; +} + +export interface SSTCRelease { + id: string; + title: string; + status: string; + content: Record; + version: number; + created_at?: string | null; +} + +export interface SSTCReview { + id: string; + title: string; + status: string; + content: Record; + version: number; + created_at?: string | null; +} + +export interface SSTCChain { + project: { id: string; title: string; description?: string }; + signals: SSTCSignal[]; + charters: SSTCCharter[]; + tasks_by_charter: Record; +} + +export interface SSTCOverview { + project: { + id: string; + title: string; + description?: string | null; + status: string; + owner_id?: string | null; + created_at?: string | null; + chain_id?: string | null; + signal_count: number; + charter_count: number; + task_count: number; + }; + chain_id?: string | null; + alignment_score: number; + pending_alignment_nodes: number; + unresolved_conflicts: number; + task_progress: { + total: number; + done: number; + blocked: number; + in_progress: number; + today_done: number; + overdue: number; + progress: number; + }; + workload_health: { + avg_ratio: number; + overloaded_count: number; + idle_count: number; + member_count: number; + }; +} + +export interface SSTCRisks { + conflicts: Array<{ + id: string; + type: string; + priority: "high" | "medium" | "low"; + title: string; + entity_id: string; + }>; + risks: Array<{ + id: string; + type: string; + priority: "high" | "medium" | "low"; + title: string; + entity_id: string; + }>; + summary: { + conflict_count: number; + risk_count: number; + blocked_task_count: number; + overdue_task_count: number; + }; +} + +export interface BoardOverviewResponse { + overview: SSTCOverview; + stages: SSTCStageNode[]; + risks: SSTCRisks; +} + +export interface CharterCreateRequest { + title: string; + content?: Record; + signal_ids: number[]; +} + +export interface CharterUpdateRequest { + title?: string; + content?: Record; + force_new_version?: boolean; +} + +export interface TaskCreateRequest { + title: string; + description?: string; + required_skill_tag_ids?: number[]; + priority?: string; + estimated_hours?: number; + due_date?: string; +} + +export interface ReleaseCreateRequest { + title: string; + charter_id: number; + task_ids: number[]; + planned_at?: string; +} + +export interface ReviewCreateRequest { + title: string; + release_node_id: number; + content?: Record; +} + +export const sstcApi = { + async getBoardOverview(projectId: string): Promise { + const { data } = await api.get>( + `/projects/${projectId}/sstc/overview` + ); + return unwrap(data); + }, + + async getStages(projectId: string): Promise { + const { data } = await api.get>( + `/projects/${projectId}/sstc/stages` + ); + return unwrap(data); + }, + + async getRisks(projectId: string): Promise { + const { data } = await api.get>( + `/projects/${projectId}/sstc/risks` + ); + return unwrap(data); + }, + + async getChain(projectId: string): Promise { + const { data } = await api.get>( + `/projects/${projectId}/sstc-chain` + ); + return unwrap(data); + }, + + async listSignals(projectId: string, status?: string): Promise { + const { data } = await api.get>( + `/projects/${projectId}/signals`, + { params: status ? { status } : undefined } + ); + return unwrap(data); + }, + + async archiveSignal(projectId: string, signalId: string): Promise<{ id: string; status: string }> { + const { data } = await api.post>( + `/projects/${projectId}/signals/${signalId}/archive` + ); + return unwrap(data); + }, + + async listCharters(projectId: string): Promise { + const { data } = await api.get>( + `/projects/${projectId}/charters` + ); + return unwrap(data); + }, + + async createCharter(projectId: string, body: CharterCreateRequest): Promise { + const { data } = await api.post>( + `/projects/${projectId}/charters`, + body + ); + return unwrap(data); + }, + + async getCharterDetail( + projectId: string, + charterId: string + ): Promise< + SSTCCharter & { + signals: SSTCSignal[]; + tasks: SSTCTask[]; + alignment_records: Array<{ + user_id: string; + score: number; + confirmed: boolean; + comments?: string | null; + }>; + } + > { + const { data } = await api.get< + ApiEnvelope< + SSTCCharter & { + signals: SSTCSignal[]; + tasks: SSTCTask[]; + alignment_records: Array<{ + user_id: string; + score: number; + confirmed: boolean; + comments?: string | null; + }>; + } + > + >(`/projects/${projectId}/charters/${charterId}`); + return unwrap(data); + }, + + async updateCharter(projectId: string, charterId: string, body: CharterUpdateRequest) { + const { data } = await api.patch>( + `/projects/${projectId}/charters/${charterId}`, + body + ); + return unwrap(data); + }, + + async startAlignment(projectId: string, charterId: string, note?: string) { + const { data } = await api.post>( + `/projects/${projectId}/charters/${charterId}/alignment/start`, + { note } + ); + return unwrap(data); + }, + + async confirmAlignment( + projectId: string, + charterId: string, + score: number, + confirmed = true, + comments?: string + ) { + const { data } = await api.post< + ApiEnvelope<{ + charter_id: string; + charter_status: string; + all_confirmed: boolean; + confirmed_count: number; + member_count: number; + }> + >(`/projects/${projectId}/charters/${charterId}/alignment/confirm`, { + score, + confirmed, + comments, + }); + return unwrap(data); + }, + + async createTask(projectId: string, charterId: string, body: TaskCreateRequest): Promise { + const { data } = await api.post>( + `/projects/${projectId}/charters/${charterId}/tasks`, + body + ); + return unwrap(data); + }, + + async aiBreakdownTasks(projectId: string, charterId: string) { + const { data } = await api.post< + ApiEnvelope<{ + created_count: number; + items: Array<{ id: string; title: string; priority: string; status: string }>; + }> + >(`/projects/${projectId}/charters/${charterId}/tasks/ai-breakdown`); + return unwrap(data); + }, + + async getTaskBoard(projectId: string, params?: { assignee_id?: number; priority?: string }) { + const { data } = await api.get>( + `/projects/${projectId}/tasks/board`, + { params } + ); + return unwrap(data); + }, + + async patchTaskStatus(projectId: string, taskId: string, status: SSTCTask["status"]) { + const { data } = await api.patch>( + `/projects/${projectId}/tasks/${taskId}/status`, + { status } + ); + return unwrap(data); + }, + + async patchTask( + projectId: string, + taskId: string, + payload: { + title?: string; + description?: string; + assignee_id?: number | null; + required_skill_tag_ids?: number[]; + priority?: string; + estimated_hours?: number; + due_date?: string; + } + ) { + const { data } = await api.patch>( + `/projects/${projectId}/tasks/${taskId}`, + payload + ); + return unwrap(data); + }, + + async recommendTaskAssignee(projectId: string, taskId: string): Promise { + const { data } = await api.post>( + `/projects/${projectId}/tasks/${taskId}/recommend-assignee` + ); + return unwrap(data); + }, + + async optimizeWorkload(projectId: string) { + const { data } = await api.post>( + `/projects/${projectId}/tasks/optimize-workload` + ); + return unwrap(data); + }, + + async listReleases(projectId: string): Promise { + const { data } = await api.get>( + `/projects/${projectId}/releases` + ); + return unwrap(data); + }, + + async createRelease(projectId: string, body: ReleaseCreateRequest): Promise { + const { data } = await api.post>( + `/projects/${projectId}/releases`, + body + ); + return unwrap(data); + }, + + async patchReleaseStatus(projectId: string, releaseNodeId: string, status: string, note?: string) { + const { data } = await api.patch>( + `/projects/${projectId}/releases/${releaseNodeId}/status`, + { status, note } + ); + return unwrap(data); + }, + + async generateReleaseVerification(projectId: string, releaseNodeId: string) { + const { data } = await api.post< + ApiEnvelope<{ release_id: string; verification_items: Array> }> + >(`/projects/${projectId}/releases/${releaseNodeId}/verification/generate`); + return unwrap(data); + }, + + async completeReleaseVerification(projectId: string, releaseNodeId: string) { + const { data } = await api.post>( + `/projects/${projectId}/releases/${releaseNodeId}/verification/complete` + ); + return unwrap(data); + }, + + async listReviews(projectId: string): Promise { + const { data } = await api.get>( + `/projects/${projectId}/reviews` + ); + return unwrap(data); + }, + + async createReview(projectId: string, body: ReviewCreateRequest): Promise { + const { data } = await api.post>( + `/projects/${projectId}/reviews`, + body + ); + return unwrap(data); + }, + + async archiveReview(projectId: string, reviewNodeId: string, archive = true, note?: string) { + const { data } = await api.post>( + `/projects/${projectId}/reviews/${reviewNodeId}/archive`, + { archive, note } + ); + return unwrap(data); + }, +}; diff --git a/frontend/src/api/users.ts b/frontend/src/api/users.ts new file mode 100644 index 00000000..51770809 --- /dev/null +++ b/frontend/src/api/users.ts @@ -0,0 +1,349 @@ +/** + * Users API Client + * + * Handles all user-related API operations including user management + * and staff operations. Uses api from lib/api.ts (pmflow_token). + */ + +import { api } from "@/lib/api"; + +// ============================================================================ +// Type Definitions +// ============================================================================ + +export type UserRole = "BOSS" | "ADMIN" | "AI" | "FE" | "BE"; +export type UserStatus = "active" | "away" | "offline"; +const VALID_ROLES: UserRole[] = ["BOSS", "ADMIN", "AI", "FE", "BE"]; + +export interface User { + id: string; + username: string; + name: string; + email?: string; + role: string; + assigned_domains: string[]; + workload: number; + status: UserStatus; + is_active?: boolean; + workload_ratio?: number; + top_skills?: string[]; + project_ids?: number[]; + created_at?: string; + updated_at?: string; +} + +export interface UserCreateRequest { + username: string; + password: string; + name: string; + email?: string; + role: UserRole | UserRole[]; + assigned_domains?: string[]; + project_ids?: number[]; +} + +export interface UserUpdateRequest { + name?: string; + email?: string; + role?: UserRole | UserRole[]; + assigned_domains?: string[]; + workload?: number; + status?: UserStatus; + is_active?: boolean; + project_ids?: number[]; +} + +export interface UserListResponse { + items: User[]; + total: number; + page: number; + page_size: number; +} + +// ============================================================================ +// API Client +// ============================================================================ + +export interface LoginResponse { + access_token: string; + token_type: string; + user: User; +} + +export function parseUserRoles(role?: UserRole | UserRole[] | string | null): UserRole[] { + if (Array.isArray(role)) { + return role.filter((item): item is UserRole => VALID_ROLES.includes(item)); + } + const raw = String(role || ""); + if (!raw) return []; + const tokens = raw + .split(",") + .map((item) => item.trim().toUpperCase()) + .filter((item): item is UserRole => VALID_ROLES.includes(item as UserRole)); + return [...new Set(tokens)]; +} + +/** + * Login with username and password (form-urlencoded for backend OAuth2) + */ +export async function login(credentials: { username: string; password: string }): Promise { + const body = new URLSearchParams(credentials).toString(); + const { data } = await api.post("/auth/login", body, { + headers: { "Content-Type": "application/x-www-form-urlencoded" }, + }); + return data; +} + +/** + * Get current user information + */ +export async function getCurrentUser(): Promise { + const { data } = await api.get("/users/me"); + return data; +} + +/** + * List all users (BOSS/ADMIN only) + */ +export async function getUsers(params?: { + page?: number; + page_size?: number; + search?: string; + role?: UserRole | string; + status?: UserStatus | string; + is_active?: boolean; + project_id?: number; + workload_state?: "idle" | "normal" | "overloaded"; + skill_ids?: string; +}): Promise { + const normalizedParams = params + ? { + ...params, + page_size: + typeof params.page_size === "number" + ? Math.max(1, Math.min(params.page_size, 100)) + : params.page_size, + } + : undefined; + + const { data } = await api.get("/users/", { + params: normalizedParams, + }); + if (Array.isArray(data)) { + return { + items: data, + total: data.length, + page: 1, + page_size: data.length || 20, + }; + } + return data; +} + +/** + * Get available staff for task assignment + */ +export async function getAvailableStaff(role?: UserRole): Promise { + const url = role ? `/users/available?role=${role}` : "/users/available"; + const { data } = await api.get(url); + return data; +} + +/** + * Get a specific user by ID + */ +export async function getUser(userId: string): Promise { + const { data } = await api.get(`/users/${userId}`); + return data; +} + +/** + * Create a new user (BOSS only) + */ +export async function createUser(userData: UserCreateRequest): Promise { + const { data } = await api.post("/users/", userData); + return data; +} + +/** + * Update user information + */ +export async function updateUser( + userId: string, + userData: UserUpdateRequest +): Promise { + const { data } = await api.put(`/users/${userId}`, userData); + return data; +} + +/** + * Delete a user (BOSS only) + */ +export async function deleteUser(userId: string): Promise<{ message: string }> { + const { data } = await api.delete<{ message: string }>(`/users/${userId}`); + return data; +} + +export async function bulkDeleteUsers(userIds: string[]): Promise<{ + deleted_count: number; + deleted_user_ids: number[]; + skipped: Array<{ user_id: number; reason: string }>; +}> { + const { data } = await api.post<{ + deleted_count: number; + deleted_user_ids: number[]; + skipped: Array<{ user_id: number; reason: string }>; + }>("/users/bulk-delete", { user_ids: userIds.map((id) => Number(id)) }); + return data; +} + +export async function bulkAssignUsers(payload: { + user_ids: string[]; + role?: UserRole; + project_ids?: number[]; +}): Promise<{ updated_count: number; skipped: Array<{ user_id: number; reason: string }> }> { + const { data } = await api.post<{ + updated_count: number; + skipped: Array<{ user_id: number; reason: string }>; + }>("/users/bulk-assign", { + user_ids: payload.user_ids.map((id) => Number(id)), + role: payload.role, + project_ids: payload.project_ids, + }); + return data; +} + +/** + * Update user workload + */ +export async function updateUserWorkload( + userId: string, + workload: number +): Promise { + const { data } = await api.put( + `/users/${userId}/workload?workload=${workload}` + ); + return data; +} + +export async function resetUserPassword( + userId: string, + newPassword: string +): Promise<{ message: string }> { + const { data } = await api.post<{ message: string }>( + `/users/${userId}/reset-password`, + { new_password: newPassword } + ); + return data; +} + +export async function patchUserStatus( + userId: string, + isActive: boolean +): Promise<{ message: string; user: User }> { + const { data } = await api.patch<{ message: string; user: User }>( + `/users/${userId}/status`, + { is_active: isActive } + ); + return data; +} + +export interface UserImportRowResult { + row: number; + status: "success" | "failed"; + message: string; + user_id?: string; +} + +export interface UserImportResult { + total: number; + success: number; + failed: number; + results: UserImportRowResult[]; +} + +export async function importUsers(file: File): Promise { + const formData = new FormData(); + formData.append("file", file); + const { data } = await api.post("/users/import", formData, { + headers: { "Content-Type": "multipart/form-data" }, + }); + return data; +} + +// ============================================================================ +// Utility Functions +// ============================================================================ + +/** + * Get role display name + */ +export function getRoleLabel(role: UserRole | UserRole[] | string): string { + const labels: Record = { + BOSS: '负责人', + ADMIN: '管理员', + AI: 'AI工程师', + FE: '前端开发', + BE: '后端开发', + } + const roles = parseUserRoles(role); + if (roles.length === 0) return String(role || "-"); + return roles.map((r) => labels[r] || r).join(" / "); +} + +/** + * Get role icon name + */ +export function getRoleIcon(role: UserRole | UserRole[] | string): string { + const icons: Record = { + BOSS: 'crown', + ADMIN: 'shield', + AI: 'brain', + FE: 'layout', + BE: 'server', + } + const primary = parseUserRoles(role)[0]; + return (primary ? icons[primary] : undefined) || 'user' +} + +/** + * Check if user is a manager (BOSS or ADMIN) + */ +export function isManagerRole(role: UserRole | UserRole[] | string): boolean { + const roles = parseUserRoles(role); + return roles.includes('BOSS') || roles.includes('ADMIN') +} + +/** + * Get status label + */ +export function getStatusLabel(status: UserStatus): string { + const labels: Record = { + active: '在线', + away: '离开', + offline: '离线', + } + return labels[status] || status +} + +/** + * Get workload color class + */ +export function getWorkloadColor(workload: number): string { + if (workload < 50) return 'green' + if (workload < 80) return 'yellow' + return 'red' +} + +/** + * Get initials from name + */ +export function getInitials(name: string | undefined): string { + if (!name) return '?' + return name + .split(' ') + .map(n => n[0]) + .join('') + .toUpperCase() + .slice(0, 2) +} diff --git a/frontend/src/api/workloads.ts b/frontend/src/api/workloads.ts new file mode 100644 index 00000000..deba2ebc --- /dev/null +++ b/frontend/src/api/workloads.ts @@ -0,0 +1,118 @@ +import { api } from "@/lib/api"; + +export interface TeamWorkloadItem { + user_id: string; + user_name: string; + username: string; + role: string; + is_active: boolean; + current_assigned_hours: number; + max_weekly_hours: number; + workload_ratio: number; + remaining_hours: number; + updated_at?: string | null; +} + +export interface WorkloadSummary { + avg_ratio: number; + overloaded_count: number; + idle_count: number; + normal_count: number; +} + +export interface TeamWorkloadResponse { + items: TeamWorkloadItem[]; + total: number; + summary: WorkloadSummary; +} + +export interface UserWorkloadDetail { + user_id: string; + user_name: string; + username: string; + is_active: boolean; + current_assigned_hours: number; + max_weekly_hours: number; + workload_ratio: number; + remaining_hours: number; + updated_at?: string | null; +} + +export interface WorkloadTaskItem { + id: string; + title: string; + project_id: string; + priority: string; + status: string; + estimated_hours: number; + due_date?: string | null; +} + +export interface WorkloadTrendPoint { + date: string; + workload_ratio: number; +} + +export interface AIOptimizeProposal { + task_id: number; + task_title: string; + project_id: number; + old_assignee_id: number; + new_assignee_id: number; + old_ratio: number; + new_ratio: number; + reason: string; +} + +export async function getTeamWorkloads(params?: { project_id?: number }) { + const { data } = await api.get("/workloads/", { params }); + return data; +} + +export async function getUserWorkload(userId: string) { + const { data } = await api.get(`/workloads/${userId}`); + return data; +} + +export async function updateUserWeeklyHours(userId: string, maxWeeklyHours: number) { + const { data } = await api.put<{ user_id: string; max_weekly_hours: number; workload_ratio: number }>( + `/workloads/${userId}`, + { max_weekly_hours: maxWeeklyHours } + ); + return data; +} + +export async function getUserWorkloadTasks( + userId: string, + params?: { status?: string; priority?: string } +) { + const { data } = await api.get<{ items: WorkloadTaskItem[]; total: number }>( + `/workloads/${userId}/tasks`, + { params } + ); + return data; +} + +export async function getUserWorkloadTrend(userId: string, days: 7 | 30) { + const { data } = await api.get<{ items: WorkloadTrendPoint[]; total: number }>( + `/workloads/${userId}/trend`, + { params: { days } } + ); + return data; +} + +export async function getAIOptimizePreview(payload: { project_id?: number; max_moves?: number }) { + const { data } = await api.post<{ proposals: AIOptimizeProposal[]; total: number }>( + "/workloads/ai-optimize", + payload + ); + return data; +} + +export async function applyAIOptimizePlan(proposals: AIOptimizeProposal[]) { + const { data } = await api.post<{ applied_count: number; affected_users: number }>( + "/workloads/ai-optimize/apply", + { proposals } + ); + return data; +} diff --git a/frontend/src/assets/vue.svg b/frontend/src/assets/vue.svg deleted file mode 100644 index 770e9d33..00000000 --- a/frontend/src/assets/vue.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/components/ContextManager.vue b/frontend/src/components/ContextManager.vue deleted file mode 100644 index d8cf8940..00000000 --- a/frontend/src/components/ContextManager.vue +++ /dev/null @@ -1,321 +0,0 @@ - - - - - diff --git a/frontend/src/components/ExperimentBoard.vue b/frontend/src/components/ExperimentBoard.vue deleted file mode 100644 index 6b11b636..00000000 --- a/frontend/src/components/ExperimentBoard.vue +++ /dev/null @@ -1,151 +0,0 @@ - - - - - diff --git a/frontend/src/components/HelloWorld.vue b/frontend/src/components/HelloWorld.vue deleted file mode 100644 index b58e52b9..00000000 --- a/frontend/src/components/HelloWorld.vue +++ /dev/null @@ -1,41 +0,0 @@ - - - - - diff --git a/frontend/src/components/LLMSettings.vue b/frontend/src/components/LLMSettings.vue deleted file mode 100644 index 44d71ba7..00000000 --- a/frontend/src/components/LLMSettings.vue +++ /dev/null @@ -1,725 +0,0 @@ - - - - - diff --git a/frontend/src/components/SignalDashboard.vue b/frontend/src/components/SignalDashboard.vue deleted file mode 100644 index 90cbb2ed..00000000 --- a/frontend/src/components/SignalDashboard.vue +++ /dev/null @@ -1,2979 +0,0 @@ - - - - - diff --git a/frontend/src/components/SkillRadarChart.tsx b/frontend/src/components/SkillRadarChart.tsx new file mode 100644 index 00000000..3c6c9e89 --- /dev/null +++ b/frontend/src/components/SkillRadarChart.tsx @@ -0,0 +1,288 @@ +import { useMemo, useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { useQuery } from "@tanstack/react-query"; +import { + RadarChart, + PolarGrid, + PolarAngleAxis, + PolarRadiusAxis, + Radar, + ResponsiveContainer, + Tooltip, + TooltipProps, +} from "recharts"; +import { + getSkillTags, + getUserSkillBindings, + SKILL_CATEGORIES, + type SkillCategory, + type SkillTag, + type UserSkillBinding, +} from "@/api/skill"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { ChevronDown } from "lucide-react"; +import { cn } from "@/lib/utils"; + +const LEVEL_LABELS: Record = { + beginner: "入门", + intermediate: "中级", + advanced: "高级", + expert: "专家", +}; + +/** 综合评分:质量分 0.6 + 效率分 0.4,缺省时用 proficiency */ +function compositeScore(b: UserSkillBinding): number { + const q = b.quality_score ?? 0; + const e = b.efficiency_score ?? 0; + if (q > 0 || e > 0) { + return Math.round(0.6 * q + 0.4 * e); + } + return b.proficiency; +} + +function formatLastUsed(iso: string | null | undefined): string { + if (!iso) return "暂无"; + try { + const d = new Date(iso); + const now = new Date(); + const diff = now.getTime() - d.getTime(); + if (diff < 86400000) return "今日"; + if (diff < 604800000) return `${Math.floor(diff / 86400000)} 天前`; + return d.toLocaleDateString("zh-CN", { + year: "numeric", + month: "short", + day: "numeric", + }); + } catch { + return "暂无"; + } +} + +export interface SkillRadarChartProps { + userId: string; + userName?: string; + className?: string; +} + +export default function SkillRadarChart({ + userId, + userName, + className, +}: SkillRadarChartProps) { + const navigate = useNavigate(); + const [category, setCategory] = useState("all"); + + const { data: tags, isLoading: tagsLoading } = useQuery({ + queryKey: ["skills", "tags"], + queryFn: () => getSkillTags({ include_system: true }), + }); + + const { data: bindings, isLoading: bindingsLoading } = useQuery({ + queryKey: ["skills", "bindings", userId], + queryFn: () => getUserSkillBindings(userId), + enabled: !!userId, + }); + + const tagMap = useMemo(() => { + const m = new Map(); + (tags ?? []).forEach((t) => m.set(t.id, t)); + return m; + }, [tags]); + + const radarData = useMemo(() => { + if (!bindings?.length) return []; + const tagById = tagMap; + let filtered = bindings; + if (category !== "all") { + filtered = bindings.filter((b) => { + const tag = tagById.get(b.skill_tag_id); + return tag?.category === category; + }); + } + return filtered.map((b) => ({ + subject: b.skill_name, + score: Math.min(100, Math.max(0, compositeScore(b))), + fullMark: 100, + binding: b, + })); + }, [bindings, tagMap, category]); + + const handleSkillClick = (skillTagId: string) => { + navigate(`/users/${userId}/skill-tasks/${skillTagId}`); + }; + + const renderAxisTick = (props: { + x: number; + y: number; + payload: { value: string }; + index: number; + }) => { + const item = radarData[props.index]; + const isClickable = !!item?.binding; + return ( + + item?.binding && handleSkillClick(item.binding.skill_tag_id) + } + style={{ cursor: isClickable ? "pointer" : "default" }} + > + + {props.payload.value} + + + ); + }; + + const isLoading = tagsLoading || bindingsLoading; + + return ( + + +
+ 技能能力图谱 + + {userName ? `${userName} 的` : ""}技能维度与综合评分 + +
+ + + + + + setCategory("all")}> + 全部分类 + + {SKILL_CATEGORIES.map((c) => ( + setCategory(c.value)} + > + {c.label} + + ))} + + +
+ + {isLoading ? ( +
+ 加载中… +
+ ) : radarData.length === 0 ? ( +
+ 暂无技能数据 +
+ ) : ( +
+ + + + + + + } + cursor={{ stroke: "hsl(var(--primary))", strokeWidth: 1 }} + /> + + +
+ )} +
+
+ ); +} + +function SkillTooltip({ active, payload }: TooltipProps) { + if (!active || !payload?.length) return null; + const item = payload[0]?.payload as { + subject: string; + score: number; + binding: UserSkillBinding; + }; + if (!item?.binding) return null; + const b = item.binding; + const quality = b.quality_score ?? null; + const efficiency = b.efficiency_score ?? null; + return ( +
+

{b.skill_name}

+
+
+
熟练度等级
+
+ {LEVEL_LABELS[b.level] ?? b.level} +
+
+
+
综合评分
+
{item.score}
+
+
+
质量评分
+
+ {quality != null ? quality : "—"} +
+
+
+
效率评分
+
+ {efficiency != null ? efficiency : "—"} +
+
+
+
最近使用
+
{formatLastUsed(b.last_used_at)}
+
+
+

+ 点击技能标签查看历史任务 +

+
+ ); +} diff --git a/frontend/src/components/ThemeInit.tsx b/frontend/src/components/ThemeInit.tsx new file mode 100644 index 00000000..2505db32 --- /dev/null +++ b/frontend/src/components/ThemeInit.tsx @@ -0,0 +1,11 @@ +import { useEffect } from "react"; + +export function ThemeInit() { + useEffect(() => { + const stored = localStorage.getItem("pmflow_theme") as "light" | "dark" | null; + const theme = stored ?? (window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"); + document.documentElement.classList.remove("light", "dark"); + document.documentElement.classList.add(theme); + }, []); + return null; +} diff --git a/frontend/src/components/budget/BudgetControlPanel.tsx b/frontend/src/components/budget/BudgetControlPanel.tsx new file mode 100644 index 00000000..9999df95 --- /dev/null +++ b/frontend/src/components/budget/BudgetControlPanel.tsx @@ -0,0 +1,178 @@ +import { useMemo, useState } from "react"; +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { AlertTriangle } from "lucide-react"; +import { budgetApi } from "@/api/budget"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; + +interface Props { + projectId: string; +} + +export function BudgetControlPanel({ projectId }: Props) { + const queryClient = useQueryClient(); + const [budgetAmount, setBudgetAmount] = useState("100"); + const [threshold, setThreshold] = useState("80"); + const [overrideNote, setOverrideNote] = useState(""); + + const budgetQuery = useQuery({ + queryKey: ["budgets", projectId], + queryFn: () => budgetApi.list(), + }); + + const alertsQuery = useQuery({ + queryKey: ["budget-alerts", projectId], + queryFn: () => budgetApi.alerts({ unread_only: true, limit: 20 }), + }); + + const createBudgetMutation = useMutation({ + mutationFn: () => + budgetApi.create({ + budget_type: "tenant", + period: "monthly", + budget_amount_usd: Number(budgetAmount || "0"), + alert_threshold_percent: Number(threshold || "80"), + hard_limit_enabled: true, + }), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ["budgets", projectId] }); + queryClient.invalidateQueries({ queryKey: ["budget-alerts", projectId] }); + }, + }); + + const overrideMutation = useMutation({ + mutationFn: (budgetId: number) => + budgetApi.override(budgetId, { note: overrideNote || "manual override", duration_hours: 24 }), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ["budgets", projectId] }); + queryClient.invalidateQueries({ queryKey: ["budget-alerts", projectId] }); + }, + }); + + const activeBudget = useMemo(() => { + const list = budgetQuery.data || []; + if (!list.length) return null; + return list[0]; + }, [budgetQuery.data]); + + const usagePercent = useMemo(() => { + if (!activeBudget || !activeBudget.budget_amount_usd) return 0; + return Math.min(100, (activeBudget.current_usage_usd / activeBudget.budget_amount_usd) * 100); + }, [activeBudget]); + + return ( +
+ + + 预算管控 + 硬预算限制、超支预警与管理员解锁 + + + {!activeBudget ? ( +
+ setBudgetAmount(e.target.value)} + /> + setThreshold(e.target.value)} + /> + +
+ ) : ( +
+
+
+

预算总额

+

${activeBudget.budget_amount_usd}

+
+
+

当前消耗

+

${activeBudget.current_usage_usd}

+
+
+

阈值

+

{activeBudget.alert_threshold_percent}%

+
+
+

状态

+

{activeBudget.status}

+
+
+ +
+
+ 预算使用率 + {usagePercent.toFixed(2)}% +
+
+
= 100 ? "h-full bg-red-500" : usagePercent >= 80 ? "h-full bg-amber-500" : "h-full bg-emerald-500"} + style={{ width: `${usagePercent}%` }} + /> +
+
+ + {(activeBudget.status === "suspended" || activeBudget.status === "overridden") && ( +
+
+ + 预算保护状态:{activeBudget.status} +
+
+ setOverrideNote(e.target.value)} + /> +
+ +
+
+ )} +
+ )} + + + + + + 预算预警 + 未读预警消息(阈值触达/超支/暂停) + + + {alertsQuery.isLoading ? ( +

加载中...

+ ) : !alertsQuery.data?.length ? ( +

暂无预警

+ ) : ( +
+ {alertsQuery.data.map((a) => ( +
+

+ [{a.alert_type}] {a.message} +

+

+ usage: ${a.usage_usd} ({a.usage_percent.toFixed(2)}%) +

+
+ ))} +
+ )} +
+
+
+ ); +} + diff --git a/frontend/src/components/command/commandItems.ts b/frontend/src/components/command/commandItems.ts new file mode 100644 index 00000000..e09a8513 --- /dev/null +++ b/frontend/src/components/command/commandItems.ts @@ -0,0 +1,282 @@ +/** + * 命令面板项目 + * + * 定义命令面板的可用命令 + * 使用图标名称而非表情符号 + */ + +export interface CommandItem { + id: string + label: string + description?: string + icon?: string // Icon 组件的图标名称 + shortcut?: string[] + category: 'navigation' | 'actions' | 'settings' | 'help' + action: () => void | Promise + keywords?: string[] +} + +export interface CommandCategory { + id: string + label: string + items: CommandItem[] +} + +// ============================================================================ +// Helper Functions +// ============================================================================ + +/** + * Navigate to a tab using query parameter + */ +function navigateToTab(tab: string) { + const url = new URL(window.location.href) + url.searchParams.set('tab', tab) + window.history.replaceState({}, '', url.toString()) + window.dispatchEvent(new CustomEvent('tab-change', { detail: { tab } })) +} + +// ============================================================================ +// 命令分类 +// ============================================================================ + +export const commandCategories: CommandCategory[] = [ + { + id: 'navigation', + label: '导航', + items: [ + { + id: 'nav-signals', + label: '信号', + description: '查看信号和战略分析', + icon: 'activity', + shortcut: ['g', 's'], + category: 'navigation', + action: () => { + navigateToTab('signals') + }, + keywords: ['dashboard', 'home', 'signals', '仪表盘', '首页'], + }, + { + id: 'nav-projects', + label: '项目', + description: '管理项目', + icon: 'layout', + shortcut: ['g', 'p'], + category: 'navigation', + action: () => { + navigateToTab('projects') + }, + keywords: ['projects', '管理', '项目'], + }, + { + id: 'nav-context', + label: '知识', + description: '查看和管理知识节点', + icon: 'database', + shortcut: ['g', 'c'], + category: 'navigation', + action: () => { + navigateToTab('context') + }, + keywords: ['context', 'knowledge', 'nodes', '知识库', '节点'], + }, + { + id: 'nav-settings', + label: '设置', + description: '配置 AI 模型和偏好设置', + icon: 'settings', + shortcut: ['g', 't'], + category: 'navigation', + action: () => { + navigateToTab('settings') + }, + keywords: ['settings', 'config', 'preferences', '配置', '偏好'], + }, + ], + }, + { + id: 'actions', + label: '操作', + items: [ + { + id: 'action-new-signal', + label: '新建信号', + description: '手动添加外部信号', + icon: 'plus', + shortcut: ['c', 's'], + category: 'actions', + action: () => { + window.dispatchEvent(new CustomEvent('command:new-signal')) + }, + keywords: ['create', 'add', 'signal', '创建', '添加', '信号'], + }, + { + id: 'action-new-experiment', + label: '新建实验', + description: '创建新的 AI 实验', + icon: 'plus', + shortcut: ['c', 'e'], + category: 'actions', + action: () => { + window.dispatchEvent(new CustomEvent('command:new-experiment')) + }, + keywords: ['create', 'add', 'experiment', '创建', '添加', '实验'], + }, + { + id: 'action-new-context', + label: '新建知识节点', + description: '添加新的知识节点', + icon: 'plus', + shortcut: ['c', 'c'], + category: 'actions', + action: () => { + window.dispatchEvent(new CustomEvent('command:new-context')) + }, + keywords: ['create', 'add', 'context', 'knowledge', '创建', '添加', '知识'], + }, + { + id: 'action-refresh', + label: '刷新', + description: '重新加载当前页面数据', + icon: 'refresh', + shortcut: ['r'], + category: 'actions', + action: () => { + window.location.reload() + }, + keywords: ['refresh', 'reload', '刷新', '重载'], + }, + { + id: 'action-export', + label: '导出数据', + description: '导出当前页面数据', + icon: 'external-link', + category: 'actions', + action: () => { + window.dispatchEvent(new CustomEvent('command:export')) + }, + keywords: ['export', 'download', '导出', '下载'], + }, + ], + }, + { + id: 'settings', + label: '设置', + items: [ + { + id: 'theme-toggle', + label: '切换主题', + description: '在亮色和暗色模式之间切换', + icon: 'sun', + shortcut: ['t', 't'], + category: 'settings', + action: () => { + window.dispatchEvent(new CustomEvent('command:toggle-theme')) + }, + keywords: ['theme', 'dark', 'light', 'mode', '主题', '暗色', '亮色', '模式'], + }, + { + id: 'theme-light', + label: '亮色模式', + description: '切换到亮色主题', + icon: 'sun', + category: 'settings', + action: () => { + window.dispatchEvent(new CustomEvent('command:set-theme', { detail: 'light' })) + }, + keywords: ['theme', 'light', '主题', '亮色'], + }, + { + id: 'theme-dark', + label: '暗色模式', + description: '切换到暗色主题', + icon: 'moon', + category: 'settings', + action: () => { + window.dispatchEvent(new CustomEvent('command:set-theme', { detail: 'dark' })) + }, + keywords: ['theme', 'dark', '主题', '暗色'], + }, + { + id: 'theme-system', + label: '跟随系统', + description: '自动跟随系统主题偏好', + icon: 'cpu', + category: 'settings', + action: () => { + window.dispatchEvent(new CustomEvent('command:set-theme', { detail: 'system' })) + }, + keywords: ['theme', 'system', 'auto', '主题', '系统', '自动'], + }, + ], + }, + { + id: 'help', + label: '帮助', + items: [ + { + id: 'help-shortcuts', + label: '键盘快捷键', + description: '显示所有可用的键盘快捷键', + icon: 'more-horizontal', + shortcut: ['?'], + category: 'help', + action: () => { + window.dispatchEvent(new CustomEvent('shortcuts:show')) + }, + keywords: ['shortcuts', 'keyboard', 'help', '快捷键', '键盘', '帮助'], + }, + { + id: 'help-docs', + label: '文档', + description: '查看文档', + icon: 'file', + category: 'help', + action: () => { + window.open('https://github.com/neural-sync/docs', '_blank') + }, + keywords: ['docs', 'documentation', 'help', '文档', '帮助'], + }, + { + id: 'help-feedback', + label: '发送反馈', + description: '报告问题或建议功能', + icon: 'edit', + category: 'help', + action: () => { + window.open('https://github.com/neural-sync/issues', '_blank') + }, + keywords: ['feedback', 'issue', 'bug', '反馈', '问题'], + }, + ], + }, +] + +// ============================================================================ +// 展平命令列表 +// ============================================================================ + +export const allCommands = commandCategories.flatMap((category) => category.items) + +// ============================================================================ +// 命令搜索 +// ============================================================================ + +export function searchCommands(query: string): CommandItem[] { + if (!query.trim()) { + return allCommands + } + + const lowerQuery = query.toLowerCase() + + return allCommands.filter((command) => { + const labelMatch = command.label.toLowerCase().includes(lowerQuery) + const descMatch = command.description?.toLowerCase().includes(lowerQuery) + const keywordsMatch = command.keywords?.some((keyword) => + keyword.toLowerCase().includes(lowerQuery) + ) + + return labelMatch || descMatch || keywordsMatch + }) +} diff --git a/frontend/src/components/icons/index.ts b/frontend/src/components/icons/index.ts new file mode 100644 index 00000000..332c3a5d --- /dev/null +++ b/frontend/src/components/icons/index.ts @@ -0,0 +1,5 @@ +/** + * Icons Index + */ + +export { default as Icon } from './Icon.vue' diff --git a/frontend/src/components/layout/Layout.tsx b/frontend/src/components/layout/Layout.tsx new file mode 100644 index 00000000..d1d153a4 --- /dev/null +++ b/frontend/src/components/layout/Layout.tsx @@ -0,0 +1,17 @@ +import { Outlet } from "react-router-dom"; +import { Sidebar } from "./Sidebar"; +import { TopBar } from "./TopBar"; + +export default function Layout() { + return ( +
+ +
+ +
+ +
+
+
+ ); +} diff --git a/frontend/src/components/layout/Sidebar.tsx b/frontend/src/components/layout/Sidebar.tsx new file mode 100644 index 00000000..bc9bf2ae --- /dev/null +++ b/frontend/src/components/layout/Sidebar.tsx @@ -0,0 +1,75 @@ +import { NavLink } from "react-router-dom"; +import { + LayoutDashboard, + FolderKanban, + Moon, + Sun, + BarChart3, + Users, + Sparkles, + Sliders, +} from "lucide-react"; +import { cn } from "@/lib/utils"; +import { isManagerRole } from "@/lib/rbac"; +import { useTheme } from "@/hooks/useTheme"; +import { useAuthStore } from "@/stores/auth"; +import { Button } from "@/components/ui/button"; + +const baseNavItems = [ + { to: "/workloads", label: "团队负载", icon: LayoutDashboard }, + { to: "/projects", label: "项目列表", icon: FolderKanban }, + { to: "/ai-steward", label: "AI 管家", icon: Sparkles }, + { to: "/ai-config", label: "智能配置", icon: Sliders }, + { to: "/skills", label: "能力管理", icon: BarChart3 }, +]; + +export function Sidebar() { + const { theme, toggleTheme } = useTheme(); + const user = useAuthStore((s) => s.user); + const isManager = isManagerRole(user?.role); + const navItems = isManager + ? [...baseNavItems, { to: "/users", label: "用户管理", icon: Users }] + : baseNavItems; + + return ( + + ); +} diff --git a/frontend/src/components/layout/TopBar.tsx b/frontend/src/components/layout/TopBar.tsx new file mode 100644 index 00000000..d9a81565 --- /dev/null +++ b/frontend/src/components/layout/TopBar.tsx @@ -0,0 +1,55 @@ +import { Bell, LogOut, User } from "lucide-react"; +import { Link } from "react-router-dom"; +import { useAuthStore } from "@/stores/auth"; +import { Button } from "@/components/ui/button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; + +export function TopBar() { + const { user, logout } = useAuthStore(); + + return ( +
+
+ PMFlow +
+
+ + + + + + +
+

{user?.name || user?.username || "用户"}

+

{user?.email || user?.username}

+
+ + + + + 个人中心 + + + + + + 退出登录 + +
+
+
+
+ ); +} diff --git a/frontend/src/components/model-capability/CostOptimizationPanel.tsx b/frontend/src/components/model-capability/CostOptimizationPanel.tsx new file mode 100644 index 00000000..9eb8f065 --- /dev/null +++ b/frontend/src/components/model-capability/CostOptimizationPanel.tsx @@ -0,0 +1,96 @@ +import { useState } from "react"; +import { useMutation, useQuery } from "@tanstack/react-query"; +import { modelCapabilityApi } from "@/api/modelCapability"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; + +interface Props { + projectId: string; +} + +export function CostOptimizationPanel({ projectId }: Props) { + const [truthNodeId, setTruthNodeId] = useState(""); + const [advancedInputMode, setAdvancedInputMode] = useState(false); + + const truthNodesQuery = useQuery({ + queryKey: ["project-truth-nodes", projectId], + queryFn: () => modelCapabilityApi.listProjectTruthNodes(Number(projectId)), + enabled: !!projectId, + }); + + const analyzeMutation = useMutation({ + mutationFn: () => + modelCapabilityApi.analyzeCostOptimization({ + truth_node_id: Number(truthNodeId), + project_id: Number(projectId), + period: "weekly", + }), + }); + + return ( + + + 成本优化分析 + 生成月度节省空间与优化动作建议 + + +
+ {advancedInputMode ? ( + setTruthNodeId(e.target.value)} + /> + ) : ( + + )} +
+ +
+
+ setAdvancedInputMode(e.target.checked)} + /> + +
+ + {analyzeMutation.data ? ( +
+

Monthly Cost: ${analyzeMutation.data.monthly_cost}

+

Potential Savings: {analyzeMutation.data.total_potential_savings_percent}%

+

Estimated Savings: ${analyzeMutation.data.estimated_monthly_savings_usd}

+ {analyzeMutation.data.recommendations?.length ? ( +
    + {analyzeMutation.data.recommendations.map((r, idx) => ( +
  • + [{r.priority}] {r.description} ({r.estimated_savings_percent}%) +
  • + ))} +
+ ) : null} +
+ ) : null} + + + ); +} diff --git a/frontend/src/components/model-capability/ExperimentSyncPanel.tsx b/frontend/src/components/model-capability/ExperimentSyncPanel.tsx new file mode 100644 index 00000000..142d96f8 --- /dev/null +++ b/frontend/src/components/model-capability/ExperimentSyncPanel.tsx @@ -0,0 +1,169 @@ +import { useState } from "react"; +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { modelCapabilityApi } from "@/api/modelCapability"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +interface Props { + projectId: string; +} + +export function ExperimentSyncPanel({ projectId }: Props) { + const queryClient = useQueryClient(); + const [experimentId, setExperimentId] = useState(""); + const [truthNodeId, setTruthNodeId] = useState(""); + const [advancedInputMode, setAdvancedInputMode] = useState(false); + + const truthNodesQuery = useQuery({ + queryKey: ["project-truth-nodes", projectId], + queryFn: () => modelCapabilityApi.listProjectTruthNodes(Number(projectId)), + enabled: !!projectId, + }); + + const experimentsQuery = useQuery({ + queryKey: ["project-experiments", projectId], + queryFn: () => modelCapabilityApi.listProjectExperiments(Number(projectId)), + enabled: !!projectId, + }); + + const syncListQuery = useQuery({ + queryKey: ["experiment-sync-list"], + queryFn: () => modelCapabilityApi.listExperimentSync({ limit: 20 }), + }); + + const createSyncMutation = useMutation({ + mutationFn: () => + modelCapabilityApi.createExperimentSync({ + experiment_id: Number(experimentId), + truth_node_id: Number(truthNodeId), + project_id: Number(projectId), + sync_type: "result_sync", + auto_apply_threshold: 0.8, + }), + onSuccess: () => queryClient.invalidateQueries({ queryKey: ["experiment-sync-list"] }), + }); + + const reviewMutation = useMutation({ + mutationFn: (input: { syncId: number; action: "approve" | "reject" }) => + modelCapabilityApi.reviewExperimentSync(input.syncId, { action: input.action }), + onSuccess: () => queryClient.invalidateQueries({ queryKey: ["experiment-sync-list"] }), + }); + + const rollbackMutation = useMutation({ + mutationFn: (syncId: number) => modelCapabilityApi.rollbackExperimentSync(syncId), + onSuccess: () => queryClient.invalidateQueries({ queryKey: ["experiment-sync-list"] }), + }); + + return ( + + + 实验结果同步 + 支持自动同步、人工审核和回滚 + + +
+ {advancedInputMode ? ( + setExperimentId(e.target.value)} + /> + ) : ( + + )} + {advancedInputMode ? ( + setTruthNodeId(e.target.value)} + /> + ) : ( + + )} + +
+
+ setAdvancedInputMode(e.target.checked)} + /> + +
+ +
+ {syncListQuery.data?.items?.length ? ( + syncListQuery.data.items.map((item) => ( +
+

+ Sync #{item.id} · exp {item.experiment_id} → truth {item.truth_node_id} +

+

+ {item.apply_status} · confidence {item.confidence_score} · auto{" "} + {item.auto_applied ? "yes" : "no"} +

+
+ + + +
+
+ )) + ) : ( +

暂无同步记录

+ )} +
+
+
+ ); +} diff --git a/frontend/src/components/model-capability/ModelCapabilityMatrix.tsx b/frontend/src/components/model-capability/ModelCapabilityMatrix.tsx new file mode 100644 index 00000000..9e0da2df --- /dev/null +++ b/frontend/src/components/model-capability/ModelCapabilityMatrix.tsx @@ -0,0 +1,292 @@ +import { useState } from "react"; +import { useMutation, useQuery } from "@tanstack/react-query"; +import { AlertTriangle, CheckCircle2 } from "lucide-react"; +import { modelCapabilityApi } from "@/api/modelCapability"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { ModelUpdateImpactPanel } from "@/components/model-capability/ModelUpdateImpactPanel"; +import { ExperimentSyncPanel } from "@/components/model-capability/ExperimentSyncPanel"; +import { CostOptimizationPanel } from "@/components/model-capability/CostOptimizationPanel"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; + +interface Props { + projectId: string; +} + +export function ModelCapabilityMatrix({ projectId }: Props) { + const [truthNodeId, setTruthNodeId] = useState(""); + const [modelVersionId, setModelVersionId] = useState(""); + const [costTruthNodeId, setCostTruthNodeId] = useState(""); + const [advancedInputMode, setAdvancedInputMode] = useState(false); + + const truthNodesQuery = useQuery({ + queryKey: ["project-truth-nodes", projectId], + queryFn: () => modelCapabilityApi.listProjectTruthNodes(Number(projectId)), + enabled: !!projectId, + }); + + const gapsQuery = useQuery({ + queryKey: ["capability-gaps", projectId], + queryFn: () => modelCapabilityApi.listCapabilityGaps({ limit: 20 }), + }); + + const validateMutation = useMutation({ + mutationFn: (payload: { + truth_node_id: number; + model_version_id: number; + project_id?: number; + }) => + modelCapabilityApi.validateMatch(payload), + }); + + const costTrackingMutation = useMutation({ + mutationFn: (nodeId: number) => modelCapabilityApi.getCostTracking(nodeId), + }); + + const costOptimizationMutation = useMutation({ + mutationFn: (nodeId: number) => modelCapabilityApi.getCostOptimization(nodeId), + }); + + const validate = () => { + const truthId = Number(truthNodeId); + const modelId = Number(modelVersionId); + if (!truthId || !modelId) return; + validateMutation.mutate({ + truth_node_id: truthId, + model_version_id: modelId, + project_id: Number(projectId), + }); + }; + + const fetchCostData = () => { + const nodeId = Number(costTruthNodeId); + if (!nodeId) return; + costTrackingMutation.mutate(nodeId); + costOptimizationMutation.mutate(nodeId); + }; + + const validateData = validateMutation.data as + | { + compatibility_score?: number; + risk_hints?: string[]; + recommendations?: string[]; + } + | undefined; + + const compatibilityScore = Number(validateData?.compatibility_score || 0); + const scoreColor = + compatibilityScore >= 80 + ? "bg-emerald-500" + : compatibilityScore >= 60 + ? "bg-amber-500" + : "bg-red-500"; + + const trackingData = costTrackingMutation.data; + const optimizationData = costOptimizationMutation.data; + + return ( +
+ + + 模型-需求匹配校验 + 输入宪章 ID 与模型版本 ID,评估兼容度与风险 + + +
+ {advancedInputMode ? ( + setTruthNodeId(e.target.value)} + /> + ) : ( + + )} + setModelVersionId(e.target.value)} + /> + +
+
+ setAdvancedInputMode(e.target.checked)} + /> + +
+ + {validateMutation.data && ( +
+
+ 匹配度 + {compatibilityScore}/100 +
+
+
+
+ + {Array.isArray(validateData?.risk_hints) && validateData.risk_hints.length > 0 && ( +
+
+ + 风险提示 +
+
    + {validateData.risk_hints.map((hint, idx) => ( +
  • - {hint}
  • + ))} +
+
+ )} + + {Array.isArray(validateData?.recommendations) && + validateData.recommendations.length > 0 && ( +
+
+ + 建议动作 +
+
    + {validateData.recommendations.map((item, idx) => ( +
  • - {item}
  • + ))} +
+
+ )} +
+ )} + + + + + + 能力差距预警 + 来自后端 model-capability/capability-gaps(最近 20 条) + + + {gapsQuery.isLoading ? ( +

加载中...

+ ) : !gapsQuery.data?.gaps?.length ? ( +

暂无差距预警

+ ) : ( + + + + 类型 + 严重级别 + 状态 + 描述 + + + + {gapsQuery.data.gaps.map((gap) => ( + + {gap.gap_type} + {gap.severity} + {gap.status} + {gap.description} + + ))} + +
+ )} +
+
+ + + + 成本与 ROI 看板 + 输入宪章 ID 拉取成本跟踪与优化建议 + + +
+ {advancedInputMode ? ( + setCostTruthNodeId(e.target.value)} + /> + ) : ( + + )} +
+ +
+ + {trackingData && ( +
+
+

实际 Token

+

{trackingData.actual_tokens ?? 0}

+
+
+

实际成本(USD)

+

{trackingData.actual_cost_usd ?? 0}

+
+
+

估算成本(USD)

+

{trackingData.estimated_cost_usd ?? 0}

+
+
+

ROI 评分

+

{trackingData.roi_score ?? "-"}

+
+
+ )} + + {optimizationData?.optimization_suggestions && ( +
+

优化建议

+
+                {JSON.stringify(optimizationData.optimization_suggestions, null, 2)}
+              
+
+ )} + + + + + + +
+ ); +} + diff --git a/frontend/src/components/model-capability/ModelUpdateImpactPanel.tsx b/frontend/src/components/model-capability/ModelUpdateImpactPanel.tsx new file mode 100644 index 00000000..92dcb69a --- /dev/null +++ b/frontend/src/components/model-capability/ModelUpdateImpactPanel.tsx @@ -0,0 +1,108 @@ +import { useState } from "react"; +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { modelCapabilityApi } from "@/api/modelCapability"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; + +export function ModelUpdateImpactPanel() { + const queryClient = useQueryClient(); + const [oldModelVersionId, setOldModelVersionId] = useState(""); + const [newModelVersionId, setNewModelVersionId] = useState(""); + const [selectedImpactId, setSelectedImpactId] = useState(null); + + const impactsQuery = useQuery({ + queryKey: ["model-lifecycle-impacts"], + queryFn: () => modelCapabilityApi.listLifecycleImpacts(20), + }); + + const assessMutation = useMutation({ + mutationFn: () => + modelCapabilityApi.assessLifecycleImpact({ + old_model_version_id: Number(oldModelVersionId), + new_model_version_id: Number(newModelVersionId), + }), + onSuccess: (data) => { + setSelectedImpactId(data.impact_id); + queryClient.invalidateQueries({ queryKey: ["model-lifecycle-impacts"] }); + }, + }); + + const migrationMutation = useMutation({ + mutationFn: (impactId: number) => modelCapabilityApi.generateMigrationTasks(impactId, 5), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ["model-lifecycle-impacts"] }); + }, + }); + + return ( + + + 模型生命周期影响评估 + 对比旧/新模型版本,生成影响评估与迁移任务 + + +
+ setOldModelVersionId(e.target.value)} + /> + setNewModelVersionId(e.target.value)} + /> + +
+ + {assessMutation.data && ( +
+

Recommendation: {assessMutation.data.recommendation}

+

Cost Change: {assessMutation.data.cost_change_percentage}%

+

Affected Charters: {Object.keys(assessMutation.data.affected_truth_nodes || {}).length}

+ + {migrationMutation.data?.migration_tasks?.tasks?.length ? ( +
    + {migrationMutation.data.migration_tasks.tasks.map((task, idx) => ( +
  • {task.title}
  • + ))} +
+ ) : null} +
+ )} + +
+

最近影响评估

+ {impactsQuery.data?.items?.length ? ( + impactsQuery.data.items.map((item) => ( +
+

#{item.id} {item.old_model_version_id} → {item.new_model_version_id}

+

{item.recommendation} · {item.status} · cost {item.cost_change_percentage}%

+
+ )) + ) : ( +

暂无记录

+ )} +
+
+
+ ); +} diff --git a/frontend/src/components/sstc/SSTCChainView.tsx b/frontend/src/components/sstc/SSTCChainView.tsx new file mode 100644 index 00000000..6bedabe6 --- /dev/null +++ b/frontend/src/components/sstc/SSTCChainView.tsx @@ -0,0 +1,124 @@ +/** + * SSTC 链路可视化组件 + * 信号 → 宪章 → 任务 → 执行 + */ + +import { Link } from "react-router-dom"; +import { Radio, FileText, ListTodo } from "lucide-react"; +import type { SSTCChain, SSTCSignal, SSTCCharter, SSTCTask } from "@/api/sstc"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { toZhPriority, toZhStatus } from "@/lib/display"; + +interface SSTCChainViewProps { + chain: SSTCChain; + projectId: string; +} + +const NodeSignal = ({ s }: { s: SSTCSignal }) => ( +
+
+ + {s.source} · {toZhPriority(s.priority)} +
+

{s.content}

+
+); + +const NodeCharter = ({ + c, + projectId, + taskCount, +}: { + c: SSTCCharter; + projectId: string; + taskCount: number; +}) => ( + +
+
+ + 宪章 · v{c.version} · {taskCount} 任务 +
+

{c.title}

+
+ +); + +const NodeTask = ({ t }: { t: SSTCTask }) => ( +
+ + {t.title} + + {toZhStatus(t.status)} + +
+); + +export function SSTCChainView({ chain, projectId }: SSTCChainViewProps) { + const { project, signals, charters, tasks_by_charter } = chain; + + return ( + + + + + SSTC 唯一事实链路 + + {project.title} + +

+ 信号源 → 需求宪章 → 任务拆解 → 执行落地 +

+
+ + {/* 1. 信号源 */} +
+

+ + 信号源 ({signals.length}) +

+
+ {signals.map((s) => ( + + ))} +
+
+ + {/* 2. 宪章 → 任务 */} +
+

+ + 需求宪章 ({charters.length}) +

+
+ {charters.map((c) => { + const tasks = tasks_by_charter[c.id] || []; + return ( +
+ + {tasks.length > 0 && ( +
+ {tasks.map((t) => ( + + ))} +
+ )} +
+ ); + })} +
+
+
+
+ ); +} diff --git a/frontend/src/components/sstc/SSTCGlobalHeader.tsx b/frontend/src/components/sstc/SSTCGlobalHeader.tsx new file mode 100644 index 00000000..ed26b565 --- /dev/null +++ b/frontend/src/components/sstc/SSTCGlobalHeader.tsx @@ -0,0 +1,176 @@ +import { Download, Settings, Sparkles, Users } from "lucide-react"; +import { Pie, PieChart, ResponsiveContainer, Cell } from "recharts"; +import type { SSTCOverview } from "@/api/sstc"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Badge } from "@/components/ui/badge"; +import { compactTitle } from "@/lib/title"; +import { toZhStatus } from "@/lib/display"; + +interface SSTCGlobalHeaderProps { + overview: SSTCOverview; + onOpenAi: () => void; + onOpenSettings: () => void; + onExport: () => void; + onOpenWorkloads: () => void; +} + +function statusVariant(status: string): "default" | "secondary" | "destructive" | "outline" { + const v = (status || "").toLowerCase(); + if (v.includes("active") || v.includes("进行")) return "default"; + if (v.includes("paused")) return "secondary"; + if (v.includes("completed") || v.includes("done")) return "outline"; + return "secondary"; +} + +function scoreColor(score: number): string { + if (score < 60) return "#dc2626"; + if (score < 80) return "#ca8a04"; + return "#16a34a"; +} + +function ratioColor(ratio: number): string { + if (ratio > 1.0) return "#dc2626"; + if (ratio >= 0.7) return "#ca8a04"; + return "#16a34a"; +} + +export function SSTCGlobalHeader({ + overview, + onOpenAi, + onOpenSettings, + onExport, + onOpenWorkloads, +}: SSTCGlobalHeaderProps) { + const alignmentColor = scoreColor(overview.alignment_score || 0); + const progress = overview.task_progress.progress || 0; + const ratio = overview.workload_health.avg_ratio || 0; + const compactProjectTitle = compactTitle(overview.project.title, 24); + + return ( +
+ + + + {compactProjectTitle} + +
+ + {toZhStatus(overview.project.status)} + + + 链路 ID: {overview.chain_id || "-"} + +
+
+ +

项目描述:{overview.project.description || "暂无"}

+

创建时间:{overview.project.created_at?.slice(0, 19).replace("T", " ") || "-"}

+

任务总数:{overview.project.task_count}

+
+
+ +
+ + + 全局认知对齐度 + + +
+ + + + + + + + +
+

+ {Math.round(overview.alignment_score || 0)}% +

+

+ 未确认节点 {overview.pending_alignment_nodes} | 冲突 {overview.unresolved_conflicts} +

+
+
+ + + + 项目整体进度 + + +

{Math.round(progress)}%

+
+
+
+

+ 已完成 {overview.task_progress.done}/{overview.task_progress.total} +

+

+ 延期 {overview.task_progress.overdue} | 阻塞 {overview.task_progress.blocked} | 今日完成 {overview.task_progress.today_done} +

+ + + + + + 团队负载健康度 + + +

+ {(ratio * 100).toFixed(0)}% +

+
+
+
+

+ 过载 {overview.workload_health.overloaded_count} 人 | 空闲 {overview.workload_health.idle_count} 人 +

+

+ + 覆盖成员 {overview.workload_health.member_count} 人 +

+ + +
+ + + + 核心操作 + + + + + + + +
+ ); +} diff --git a/frontend/src/components/sstc/SSTCRiskFloatPanel.tsx b/frontend/src/components/sstc/SSTCRiskFloatPanel.tsx new file mode 100644 index 00000000..29ecada0 --- /dev/null +++ b/frontend/src/components/sstc/SSTCRiskFloatPanel.tsx @@ -0,0 +1,110 @@ +import { useMemo, useState } from "react"; +import { AlertTriangle, Brain, Minimize2, Maximize2 } from "lucide-react"; +import type { SSTCRisks } from "@/api/sstc"; +import { Button } from "@/components/ui/button"; +import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"; + +interface SSTCRiskFloatPanelProps { + risks: SSTCRisks; + onJump?: (entityId: string) => void; +} + +export function SSTCRiskFloatPanel({ risks, onJump }: SSTCRiskFloatPanelProps) { + const [minimized, setMinimized] = useState(true); + const total = useMemo( + () => (risks.summary.conflict_count || 0) + (risks.summary.risk_count || 0), + [risks] + ); + + if (minimized) { + return ( +
+ +
+ ); + } + + return ( +
+
+

项目预警中心

+
+ + {total} + + +
+
+
+ + + 认知冲突 + 风险预警 + + + {risks.conflicts.length === 0 ? ( +

暂无未解决冲突

+ ) : ( + risks.conflicts.map((item) => ( +
+

{item.title}

+
+ +
+
+ )) + )} +
+ + {risks.risks.length === 0 ? ( +

暂无风险预警

+ ) : ( + risks.risks.map((item) => ( +
+

{item.title}

+
+ +
+
+ )) + )} +
+
+ +
+
+ ); +} diff --git a/frontend/src/components/sstc/SSTCStageNav.tsx b/frontend/src/components/sstc/SSTCStageNav.tsx new file mode 100644 index 00000000..ad504b5c --- /dev/null +++ b/frontend/src/components/sstc/SSTCStageNav.tsx @@ -0,0 +1,63 @@ +import { ChevronRight } from "lucide-react"; +import type { StageKey, SSTCStageNode } from "@/api/sstc"; +import { Badge } from "@/components/ui/badge"; +import { toZhStatus } from "@/lib/display"; +import { cn } from "@/lib/utils"; + +interface SSTCStageNavProps { + stages: SSTCStageNode[]; + activeStage: StageKey; + onChange: (key: StageKey) => void; +} + +function statusClass(status: string): string { + const value = status.toLowerCase(); + if (value.includes("已对齐") || value.includes("已完成") || value.includes("已验证") || value.includes("已归档") || value.includes("已同步")) { + return "bg-green-100 text-green-700 border-green-200 dark:bg-green-900/40 dark:text-green-300"; + } + if (value.includes("进行") || value.includes("待") || value.includes("对齐中")) { + return "bg-amber-100 text-amber-700 border-amber-200 dark:bg-amber-900/40 dark:text-amber-300"; + } + if (value.includes("未解锁") || value.includes("阻塞") || value.includes("未对齐")) { + return "bg-red-100 text-red-700 border-red-200 dark:bg-red-900/40 dark:text-red-300"; + } + if (value.includes("已上线")) { + return "bg-blue-100 text-blue-700 border-blue-200 dark:bg-blue-900/40 dark:text-blue-300"; + } + return "bg-muted text-muted-foreground border-border"; +} + +export function SSTCStageNav({ stages, activeStage, onChange }: SSTCStageNavProps) { + return ( +
+
+ {stages.map((stage, idx) => { + const displayStatus = toZhStatus(stage.status); + return ( +
+ + {idx < stages.length - 1 && } +
+ ); + })} +
+
+ ); +} diff --git a/frontend/src/components/sstc/SSTCWorkspace.tsx b/frontend/src/components/sstc/SSTCWorkspace.tsx new file mode 100644 index 00000000..17c5d987 --- /dev/null +++ b/frontend/src/components/sstc/SSTCWorkspace.tsx @@ -0,0 +1,999 @@ +import { type DragEvent, useMemo, useState } from "react"; +import { useMutation, useQuery } from "@tanstack/react-query"; +import { + Bot, + CheckCircle2, + PlayCircle, + Plus, + RefreshCcw, + Sparkles, + Workflow, +} from "lucide-react"; +import { getUsers, type User } from "@/api/users"; +import type { + StageKey, + SSTCCharter, + SSTCRelease, + SSTCReview, + SSTCSignal, + SSTCStageNode, + SSTCTask, + SSTCTaskRecommendation, +} from "@/api/sstc"; +import { sstcApi } from "@/api/sstc"; +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { Input } from "@/components/ui/input"; +import { Textarea } from "@/components/ui/textarea"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { toZhPriority, toZhSignalType, toZhStatus } from "@/lib/display"; +import { compactTitle } from "@/lib/title"; + +interface SSTCWorkspaceProps { + projectId: string; + activeStage: StageKey; + stages: SSTCStageNode[]; + signals: SSTCSignal[]; + charters: SSTCCharter[]; + tasks: SSTCTask[]; + releases: SSTCRelease[]; + reviews: SSTCReview[]; + selectedCharterId: string | null; + onSelectCharter: (charterId: string) => void; + onRefresh: () => void; +} + +function priorityBadgeClass(priority?: string): string { + const p = (priority || "").toLowerCase(); + if (p === "p0" || p === "high") return "bg-red-100 text-red-700 border-red-200"; + if (p === "p1" || p === "medium") return "bg-amber-100 text-amber-700 border-amber-200"; + return "bg-slate-100 text-slate-700 border-slate-200"; +} + +function statusBadgeClass(status?: string): string { + const s = (status || "").toLowerCase(); + if (s.includes("done") || s.includes("completed") || s.includes("已") || s.includes("verified")) { + return "bg-green-100 text-green-700 border-green-200"; + } + if (s.includes("progress") || s.includes("review") || s.includes("pending") || s.includes("对齐")) { + return "bg-amber-100 text-amber-700 border-amber-200"; + } + if (s.includes("blocked") || s.includes("未解锁")) { + return "bg-red-100 text-red-700 border-red-200"; + } + return "bg-muted text-muted-foreground border-border"; +} + +function normalizeLane(status: string): "todo" | "in_progress" | "blocked" | "review" | "done" { + const s = (status || "").toLowerCase(); + if (s === "completed") return "done"; + if (s === "in_progress") return "in_progress"; + if (s === "blocked") return "blocked"; + if (s === "review") return "review"; + if (s === "done") return "done"; + return "todo"; +} + +const EXECUTION_LANES: Array<{ key: "todo" | "in_progress" | "blocked" | "review" | "done"; label: string }> = [ + { key: "todo", label: "待办" }, + { key: "in_progress", label: "进行中" }, + { key: "blocked", label: "已阻塞" }, + { key: "review", label: "评审中" }, + { key: "done", label: "已完成" }, +]; + +export function SSTCWorkspace({ + projectId, + activeStage, + stages, + signals, + charters, + tasks, + releases, + reviews, + selectedCharterId, + onSelectCharter, + onRefresh, +}: SSTCWorkspaceProps) { + const activeMeta = stages.find((s) => s.key === activeStage); + const stageLocked = !!activeMeta?.locked; + + const [newTaskOpen, setNewTaskOpen] = useState(false); + const [newTaskTitle, setNewTaskTitle] = useState(""); + const [newTaskDesc, setNewTaskDesc] = useState(""); + const [newTaskPriority, setNewTaskPriority] = useState("medium"); + const [newTaskHours, setNewTaskHours] = useState(""); + const [newTaskDueDate, setNewTaskDueDate] = useState(""); + + const [newReleaseOpen, setNewReleaseOpen] = useState(false); + const [newReleaseTitle, setNewReleaseTitle] = useState(""); + const [releaseCharterId, setReleaseCharterId] = useState(""); + const [releaseTaskIds, setReleaseTaskIds] = useState([]); + const [releasePlannedAt, setReleasePlannedAt] = useState(""); + + const [newReviewOpen, setNewReviewOpen] = useState(false); + const [newReviewTitle, setNewReviewTitle] = useState(""); + const [reviewReleaseId, setReviewReleaseId] = useState(""); + const [reviewContent, setReviewContent] = useState(""); + + const [charterDraftTitle, setCharterDraftTitle] = useState(""); + const [charterDraftContent, setCharterDraftContent] = useState(""); + const [taskRecommendations, setTaskRecommendations] = useState>({}); + + const selectedCharter = useMemo( + () => charters.find((c) => c.id === selectedCharterId) || charters[0] || null, + [charters, selectedCharterId] + ); + + const { data: charterDetail } = useQuery({ + queryKey: ["sstc-charter-detail", projectId, selectedCharter?.id], + queryFn: () => sstcApi.getCharterDetail(projectId, selectedCharter!.id), + enabled: !!selectedCharter?.id, + }); + + const { data: projectUsersResponse } = useQuery({ + queryKey: ["project-users-for-task", projectId], + queryFn: () => getUsers({ page: 1, page_size: 100, project_id: Number(projectId) }), + enabled: !!projectId, + }); + const projectUsers: User[] = projectUsersResponse?.items ?? []; + + const archiveSignalMutation = useMutation({ + mutationFn: (signalId: string) => sstcApi.archiveSignal(projectId, signalId), + onSuccess: onRefresh, + }); + + const startAlignmentMutation = useMutation({ + mutationFn: (charterId: string) => sstcApi.startAlignment(projectId, charterId), + onSuccess: onRefresh, + }); + + const confirmAlignmentMutation = useMutation({ + mutationFn: (charterId: string) => + sstcApi.confirmAlignment(projectId, charterId, 90, true, "已确认对齐"), + onSuccess: onRefresh, + }); + + const updateCharterMutation = useMutation({ + mutationFn: (payload: { charterId: string; title: string; content: Record }) => + sstcApi.updateCharter(projectId, payload.charterId, { + title: payload.title, + content: payload.content, + force_new_version: true, + }), + onSuccess: onRefresh, + }); + + const createTaskMutation = useMutation({ + mutationFn: () => + sstcApi.createTask(projectId, selectedCharter!.id, { + title: newTaskTitle, + description: newTaskDesc || undefined, + priority: newTaskPriority, + estimated_hours: newTaskHours ? Number(newTaskHours) : undefined, + due_date: newTaskDueDate || undefined, + }), + onSuccess: () => { + setNewTaskOpen(false); + setNewTaskTitle(""); + setNewTaskDesc(""); + setNewTaskHours(""); + setNewTaskDueDate(""); + onRefresh(); + }, + }); + + const aiBreakdownMutation = useMutation({ + mutationFn: () => sstcApi.aiBreakdownTasks(projectId, selectedCharter!.id), + onSuccess: onRefresh, + }); + + const patchTaskStatusMutation = useMutation({ + mutationFn: ({ taskId, status }: { taskId: string; status: SSTCTask["status"] }) => + sstcApi.patchTaskStatus(projectId, taskId, status), + onSuccess: onRefresh, + }); + + const patchTaskMutation = useMutation({ + mutationFn: ({ + taskId, + payload, + }: { + taskId: string; + payload: { + assignee_id?: number | null; + estimated_hours?: number; + priority?: string; + }; + }) => sstcApi.patchTask(projectId, taskId, payload), + onSuccess: onRefresh, + }); + + const recommendAssigneeMutation = useMutation({ + mutationFn: (taskId: string) => sstcApi.recommendTaskAssignee(projectId, taskId), + onSuccess: (data) => { + setTaskRecommendations((prev) => ({ ...prev, [data.task_id]: data.recommendations || [] })); + }, + }); + + const optimizeWorkloadMutation = useMutation({ + mutationFn: () => sstcApi.optimizeWorkload(projectId), + onSuccess: onRefresh, + }); + + const createReleaseMutation = useMutation({ + mutationFn: () => + sstcApi.createRelease(projectId, { + title: newReleaseTitle, + charter_id: Number(releaseCharterId), + task_ids: releaseTaskIds.map((id) => Number(id)), + planned_at: releasePlannedAt || undefined, + }), + onSuccess: () => { + setNewReleaseOpen(false); + setNewReleaseTitle(""); + setReleaseTaskIds([]); + setReleasePlannedAt(""); + onRefresh(); + }, + }); + + const patchReleaseStatusMutation = useMutation({ + mutationFn: ({ releaseNodeId, status }: { releaseNodeId: string; status: string }) => + sstcApi.patchReleaseStatus(projectId, releaseNodeId, status), + onSuccess: onRefresh, + }); + + const genVerificationMutation = useMutation({ + mutationFn: (releaseNodeId: string) => sstcApi.generateReleaseVerification(projectId, releaseNodeId), + onSuccess: onRefresh, + }); + + const completeVerificationMutation = useMutation({ + mutationFn: (releaseNodeId: string) => sstcApi.completeReleaseVerification(projectId, releaseNodeId), + onSuccess: onRefresh, + }); + + const createReviewMutation = useMutation({ + mutationFn: () => + sstcApi.createReview(projectId, { + title: newReviewTitle, + release_node_id: Number(reviewReleaseId), + content: reviewContent ? { summary: reviewContent } : {}, + }), + onSuccess: () => { + setNewReviewOpen(false); + setNewReviewTitle(""); + setReviewContent(""); + onRefresh(); + }, + }); + + const archiveReviewMutation = useMutation({ + mutationFn: (reviewId: string) => sstcApi.archiveReview(projectId, reviewId, true), + onSuccess: onRefresh, + }); + + const doneTasks = useMemo( + () => tasks.filter((t) => ["done", "completed"].includes((t.status || "").toLowerCase())), + [tasks] + ); + + const executionLanes = useMemo(() => { + const grouped: Record = { + todo: [], + in_progress: [], + blocked: [], + review: [], + done: [], + }; + for (const t of tasks) { + grouped[normalizeLane(t.status || "todo")].push(t); + } + return grouped; + }, [tasks]); + + const handleDropTask = (targetStatus: SSTCTask["status"], ev: DragEvent) => { + ev.preventDefault(); + const taskId = ev.dataTransfer.getData("taskId"); + if (!taskId) return; + patchTaskStatusMutation.mutate({ taskId, status: targetStatus }); + }; + + const renderSignalStage = () => ( + + +
+ 项目信号源 +

+ 市场/竞品/用户反馈统一入口,支持 AI 预处理 +

+
+
+ + +
+
+ + + + + 优先级 + 信号标题 + 类型 + 来源 + 处理状态 + 创建时间 + 操作 + + + + {signals.map((s) => ( + + + {toZhPriority(s.priority)} + + {s.title || s.content} + {toZhSignalType(s.signal_type || s.source || "other")} + {s.source || "-"} + + {toZhStatus(s.status)} + + {s.created_at?.slice(0, 19).replace("T", " ") || "-"} + + + + + + ))} + {signals.length === 0 && ( + + + 暂无信号数据 + + + )} + +
+
+
+ ); + + const renderCharterStage = () => ( +
+ + + 宪章列表 + + + {charters.map((c) => ( + + ))} + {charters.length === 0 &&

暂无宪章

} +
+
+ + + +
+ + {compactTitle(selectedCharter?.title || "未选择宪章", 24)} + +

+ 版本 v{selectedCharter?.version || 0} · 状态 {toZhStatus(selectedCharter?.status)} +

+
+
+ + +
+
+ + setCharterDraftTitle(e.target.value)} + placeholder="宪章标题(自动精简)" + /> +