diff --git a/frontend/package.json b/frontend/package.json index 38b8605..e02a8eb 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -6,16 +6,33 @@ "scripts": { "dev": "vite", "build": "vue-tsc -b && vite build", - "preview": "vite preview" + "preview": "vite preview", + "type-check": "vue-tsc --noEmit" }, "dependencies": { - "vue": "latest" + "@codemirror/lang-markdown": "^6.5.0", + "@codemirror/theme-one-dark": "^6.1.0", + "@milkdown/plugin-block": "^7.22.0", + "@milkdown/plugin-cursor": "^7.22.0", + "@milkdown/plugin-history": "^7.22.0", + "@milkdown/plugin-listener": "^7.22.0", + "@milkdown/plugin-slash": "^7.22.0", + "@milkdown/plugin-tooltip": "^7.22.0", + "@milkdown/plugin-trailing": "^7.22.0", + "@milkdown/theme-nord": "^7.22.0", + "@milkdown/vue": "^7.22.0", + "@vueuse/core": "^14.0.0", + "codemirror": "^6.0.0", + "marked": "^15.0.0", + "pinia": "^4.0.0", + "vue": "^3.5.0", + "vue-router": "^5.0.0" }, "devDependencies": { - "@types/node": "latest", - "@vitejs/plugin-vue": "latest", + "@types/node": "^22.0.0", + "@vitejs/plugin-vue": "^5.0.0", "typescript": "~5.9.3", - "vite": "latest", - "vue-tsc": "latest" + "vite": "^6.0.0", + "vue-tsc": "^2.0.0" } } diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 3240b3f..fa6908b 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -8,48 +8,533 @@ importers: .: dependencies: + '@codemirror/lang-markdown': + specifier: ^6.5.0 + version: 6.5.2 + '@codemirror/theme-one-dark': + specifier: ^6.1.0 + version: 6.1.3 + '@milkdown/plugin-block': + specifier: ^7.22.0 + version: 7.22.1 + '@milkdown/plugin-cursor': + specifier: ^7.22.0 + version: 7.22.1 + '@milkdown/plugin-history': + specifier: ^7.22.0 + version: 7.22.1 + '@milkdown/plugin-listener': + specifier: ^7.22.0 + version: 7.22.1 + '@milkdown/plugin-slash': + specifier: ^7.22.0 + version: 7.22.1 + '@milkdown/plugin-tooltip': + specifier: ^7.22.0 + version: 7.22.1 + '@milkdown/plugin-trailing': + specifier: ^7.22.0 + version: 7.22.1 + '@milkdown/theme-nord': + specifier: ^7.22.0 + version: 7.22.1 + '@milkdown/vue': + specifier: ^7.22.0 + version: 7.22.1(@codemirror/language@6.12.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.9)(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.3)(typescript@5.9.3)(vue@3.5.41(typescript@5.9.3)) + '@vueuse/core': + specifier: ^14.0.0 + version: 14.4.0(vue@3.5.41(typescript@5.9.3)) + codemirror: + specifier: ^6.0.0 + version: 6.0.2 + marked: + specifier: ^15.0.0 + version: 15.0.12 + pinia: + specifier: ^4.0.0 + version: 4.0.3(@vue/devtools-api@8.2.1)(typescript@5.9.3)(vue@3.5.41(typescript@5.9.3)) vue: - specifier: latest + specifier: ^3.5.0 version: 3.5.41(typescript@5.9.3) + vue-router: + specifier: ^5.0.0 + version: 5.2.0(@vue/compiler-sfc@3.5.41)(esbuild@0.25.12)(pinia@4.0.3(@vue/devtools-api@8.2.1)(typescript@5.9.3)(vue@3.5.41(typescript@5.9.3)))(rolldown@1.2.5)(rollup@4.63.0)(vite@6.4.3(@types/node@22.20.1)(lightningcss@1.33.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.9.3)) devDependencies: '@types/node': - specifier: latest - version: 26.3.0 + specifier: ^22.0.0 + version: 22.20.1 '@vitejs/plugin-vue': - specifier: latest - version: 6.0.8(vite@8.2.2(@types/node@26.3.0))(vue@3.5.41(typescript@5.9.3)) + specifier: ^5.0.0 + version: 5.2.4(vite@6.4.3(@types/node@22.20.1)(lightningcss@1.33.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.9.3)) typescript: specifier: ~5.9.3 version: 5.9.3 vite: - specifier: latest - version: 8.2.2(@types/node@26.3.0) + specifier: ^6.0.0 + version: 6.4.3(@types/node@22.20.1)(lightningcss@1.33.0)(yaml@2.9.0) vue-tsc: - specifier: latest - version: 3.3.11(typescript@5.9.3) + specifier: ^2.0.0 + version: 2.2.12(typescript@5.9.3) packages: + '@babel/generator@8.0.0': + resolution: {integrity: sha512-NT9NrVwJsbSV6Y2FSstWa71EETOnzrjkL5/wX3D2mYHtKM+qvqB1DvR4D0Setb/gDBsHzRICifwEWMO8CnTF6g==} + engines: {node: ^22.18.0 || >=24.11.0} + '@babel/helper-string-parser@7.29.7': resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@8.0.0': + resolution: {integrity: sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg==} + engines: {node: ^22.18.0 || >=24.11.0} + '@babel/helper-validator-identifier@7.29.7': resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@8.0.4': + resolution: {integrity: sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==} + engines: {node: ^22.18.0 || >=24.11.0} + '@babel/parser@7.29.8': resolution: {integrity: sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==} engines: {node: '>=6.0.0'} hasBin: true + '@babel/parser@8.0.4': + resolution: {integrity: sha512-srpptsAkEbbNIC/q8nT7o+m6CQe8CJUTV/t7MYc9NnWlgYVtHOb7JH6SorxMhN0kuRJjVqXbKClG6xSbPtzz+g==} + engines: {node: ^22.18.0 || >=24.11.0} + hasBin: true + '@babel/types@7.29.8': resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} engines: {node: '>=6.9.0'} + '@babel/types@8.0.4': + resolution: {integrity: sha512-eY+Yn3dCqTGmyiq2QRU66lA5FL8lqqqvecHt0fF3uHONIa7ToYsaCiWV8lOKqAs0Rb2SjixiKFROngnulPtt2g==} + engines: {node: ^22.18.0 || >=24.11.0} + + '@codemirror/autocomplete@6.20.3': + resolution: {integrity: sha512-tlosUqb+3BbxCxZdu4tKeRghPFC+QM7q4X5YhKV2eCmPG+1r2F3f4AaSz5sCrFqUtX4Jh20VFTKecl16MgiV9g==} + + '@codemirror/commands@6.11.0': + resolution: {integrity: sha512-/K4Rl5BN0OtTiPWmJCdqODu38XnDMsDxKY5rgrPnCkutPTJf2wVbkoixLfealF5Kwse/s8P8M5jAiURiwSwnFA==} + + '@codemirror/lang-angular@0.1.4': + resolution: {integrity: sha512-oap+gsltb/fzdlTQWD6BFF4bSLKcDnlxDsLdePiJpCVNKWXSTAbiiQeYI3UmES+BLAdkmIC1WjyztC1pi/bX4g==} + + '@codemirror/lang-cpp@6.0.3': + resolution: {integrity: sha512-URM26M3vunFFn9/sm6rzqrBzDgfWuDixp85uTY49wKudToc2jTHUrKIGGKs+QWND+YLofNNZpxcNGRynFJfvgA==} + + '@codemirror/lang-css@6.3.1': + resolution: {integrity: sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==} + + '@codemirror/lang-go@6.0.1': + resolution: {integrity: sha512-7fNvbyNylvqCphW9HD6WFnRpcDjr+KXX/FgqXy5H5ZS0eC5edDljukm/yNgYkwTsgp2busdod50AOTIy6Jikfg==} + + '@codemirror/lang-html@6.4.12': + resolution: {integrity: sha512-pw2ReWKUqSkbvh76RAT4NYxiogRu+PWkR2ukAwO9uOgrm8uipkzjtKKtNpyeAQwHOqxEeSvAXZ6vr3AfyB9y/w==} + + '@codemirror/lang-java@6.0.2': + resolution: {integrity: sha512-m5Nt1mQ/cznJY7tMfQTJchmrjdjQ71IDs+55d1GAa8DGaB8JXWsVCkVT284C3RTASaY43YknrK2X3hPO/J3MOQ==} + + '@codemirror/lang-javascript@6.2.5': + resolution: {integrity: sha512-zD4e5mS+50htS7F+TYjBPsiIFGanfVqg4HyUz6WNFikgOPf2BgKlx+TQedI1w6n/IqRBVBbBWmGFdLB/7uxO4A==} + + '@codemirror/lang-jinja@6.0.1': + resolution: {integrity: sha512-P5kyHLObzjtbGj16h+hyvZTxJhSjBEeSx4wMjbnAf3b0uwTy2+F0zGjMZL4PQOm/mh2eGZ5xUDVZXgwP783Nsw==} + + '@codemirror/lang-json@6.0.2': + resolution: {integrity: sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==} + + '@codemirror/lang-less@6.0.2': + resolution: {integrity: sha512-EYdQTG22V+KUUk8Qq582g7FMnCZeEHsyuOJisHRft/mQ+ZSZ2w51NupvDUHiqtsOy7It5cHLPGfHQLpMh9bqpQ==} + + '@codemirror/lang-liquid@6.3.2': + resolution: {integrity: sha512-6PDVU3ZnfeYyz1at1E/ttorErZvZFXXt1OPhtfe1EZJ2V2iDFa0CwPqPgG5F7NXN0yONGoBogKmFAafKTqlwIw==} + + '@codemirror/lang-markdown@6.5.2': + resolution: {integrity: sha512-AwBOdkWYuA//WcM0xO5PfHPUcmz/O2i5o0Nsg1U69SII/loCJlFI1Romd9xp2HYb1kYJRGZotyqRghuHH5n8Kw==} + + '@codemirror/lang-php@6.0.2': + resolution: {integrity: sha512-ZKy2v1n8Fc8oEXj0Th0PUMXzQJ0AIR6TaZU+PbDHExFwdu+guzOA4jmCHS1Nz4vbFezwD7LyBdDnddSJeScMCA==} + + '@codemirror/lang-python@6.2.1': + resolution: {integrity: sha512-IRjC8RUBhn9mGR9ywecNhB51yePWCGgvHfY1lWN/Mrp3cKuHr0isDKia+9HnvhiWNnMpbGhWrkhuWOc09exRyw==} + + '@codemirror/lang-rust@6.0.2': + resolution: {integrity: sha512-EZaGjCUegtiU7kSMvOfEZpaCReowEf3yNidYu7+vfuGTm9ow4mthAparY5hisJqOHmJowVH3Upu+eJlUji6qqA==} + + '@codemirror/lang-sass@6.0.2': + resolution: {integrity: sha512-l/bdzIABvnTo1nzdY6U+kPAC51czYQcOErfzQ9zSm9D8GmNPD0WTW8st/CJwBTPLO8jlrbyvlSEcN20dc4iL0Q==} + + '@codemirror/lang-sql@6.10.0': + resolution: {integrity: sha512-6ayPkEd/yRw0XKBx5uAiToSgGECo/GY2NoJIHXIIQh1EVwLuKoU8BP/qK0qH5NLXAbtJRLuT73hx7P9X34iO4w==} + + '@codemirror/lang-vue@0.1.3': + resolution: {integrity: sha512-QSKdtYTDRhEHCfo5zOShzxCmqKJvgGrZwDQSdbvCRJ5pRLWBS7pD/8e/tH44aVQT6FKm0t6RVNoSUWHOI5vNug==} + + '@codemirror/lang-wast@6.0.2': + resolution: {integrity: sha512-Imi2KTpVGm7TKuUkqyJ5NRmeFWF7aMpNiwHnLQe0x9kmrxElndyH0K6H/gXtWwY6UshMRAhpENsgfpSwsgmC6Q==} + + '@codemirror/lang-xml@6.1.0': + resolution: {integrity: sha512-3z0blhicHLfwi2UgkZYRPioSgVTo9PV5GP5ducFH6FaHy0IAJRg+ixj5gTR1gnT/glAIC8xv4w2VL1LoZfs+Jg==} + + '@codemirror/lang-yaml@6.1.3': + resolution: {integrity: sha512-AZ8DJBuXGVHybpBQhmZtgew5//4hv3tdkXnr3vDmOUMJRuB6vn/uuwtmTOTlqEaQFg3hQSVeA90NmvIQyUV6FQ==} + + '@codemirror/language-data@6.5.2': + resolution: {integrity: sha512-CPkWBKrNS8stYbEU5kwBwTf3JB1kghlbh4FSAwzGW2TEscdeHHH4FGysREW86Mqnj3Qn09s0/6Ea/TutmoTobg==} + + '@codemirror/language@6.12.4': + resolution: {integrity: sha512-1q4PaT+o6PbgpkJt4Q8Fv5XJxTy4FUZ4MWETtyiDw3J0Pyr9E2vqcKL+k9wcvjNTIsauxvE7OfmWj3FRPHQ76A==} + + '@codemirror/legacy-modes@6.5.3': + resolution: {integrity: sha512-xCsmIzH78MyWkib9jlPaaun57XNkfbMIhagfaZVd0iLTqlpw3jXaIcbZm72MTmmn64eTZpBVNjbyYh+QXnxRsg==} + + '@codemirror/lint@6.9.7': + resolution: {integrity: sha512-28/+iWLYxKxsvGYhSYL7zaCZqLz5+FFFDq9tVsvGv9kv8RY4fFAchJ5WX9M3YrrRlTIsECjsXPqeNgnSmNP2dg==} + + '@codemirror/search@6.7.1': + resolution: {integrity: sha512-uMe5UO6PamJtSHrXhhHOzSX3ReWtiJrva6GnPMwSOrZtiExb5X5eExhr2OUZQVvdxPsKpY3Ro2mFbQadpPWmHA==} + + '@codemirror/state@6.7.1': + resolution: {integrity: sha512-9QzNDgE4EYDnAHfrTlR2lwiPciiOymLtwKK+8yHQzCc7GXhAP9xdEbEJFy2IWB1j9UGUl9BsgMmTo/ImA02T7A==} + + '@codemirror/theme-one-dark@6.1.3': + resolution: {integrity: sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA==} + + '@codemirror/view@6.43.9': + resolution: {integrity: sha512-sTuUzTpPMFebRhg6dawChoKKgndIwfjmJgKVxBefPElcU2NwQ6AFroupk0SFqEerQyZOGRfDNnSN8Dw/lMAsXw==} + + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@floating-ui/core@1.8.0': + resolution: {integrity: sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==} + + '@floating-ui/dom@1.8.0': + resolution: {integrity: sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==} + + '@floating-ui/utils@0.2.12': + resolution: {integrity: sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@lezer/common@1.5.2': + resolution: {integrity: sha512-sxQE460fPZyU3sdc8lafxiPwJHBzZRy/udNFynGQky1SePYBdhkBl1kOagA9uT3pxR8K09bOrmTUqA9wb/PjSQ==} + + '@lezer/cpp@1.1.6': + resolution: {integrity: sha512-vh9gWWJOXFVY8HBHK3Twzq8MgwG2iN4GSyzBP9sCGTe37P15x2R14VaBQk0VA0ezTRN1KHYBBsHhvpGZ2Xy/pA==} + + '@lezer/css@1.3.6': + resolution: {integrity: sha512-YJE78Wcg+zX8f10hiHWQ4Az48Qr/c13eId0VtRQYLBpxHDmDeSrXIlkbl+fJGW42rWC/uoUco9mhBZeVWP/A1g==} + + '@lezer/go@1.0.1': + resolution: {integrity: sha512-xToRsYxwsgJNHTgNdStpcvmbVuKxTapV0dM0wey1geMMRc9aggoVyKgzYp41D2/vVOx+Ii4hmE206kvxIXBVXQ==} + + '@lezer/highlight@1.2.3': + resolution: {integrity: sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==} + + '@lezer/html@1.3.13': + resolution: {integrity: sha512-oI7n6NJml729m7pjm9lvLvmXbdoMoi2f+1pwSDJkl9d68zGr7a9Btz8NdHTGQZtW2DA25ybeuv/SyDb9D5tseg==} + + '@lezer/java@1.1.3': + resolution: {integrity: sha512-yHquUfujwg6Yu4Fd1GNHCvidIvJwi/1Xu2DaKl/pfWIA2c1oXkVvawH3NyXhCaFx4OdlYBVX5wvz2f7Aoa/4Xw==} + + '@lezer/javascript@1.5.4': + resolution: {integrity: sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==} + + '@lezer/json@1.0.3': + resolution: {integrity: sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==} + + '@lezer/lr@1.4.10': + resolution: {integrity: sha512-rnCpTIBafOx4mRp43xOxDJbFipJm/c0cia/V5TiGlhmMa+wsSdoGmUN3w5Bqrks/09Q/D4tNAmWaT8p6NRi77A==} + + '@lezer/markdown@1.7.2': + resolution: {integrity: sha512-iTkYvoVcKt3WkeL7qUDyXHONZEwLio4wj8KTNi2dnjQEXBZKMV63BpQrPqfsM+OkvuRbiSTAcycYAsQzLhRNoQ==} + + '@lezer/php@1.0.5': + resolution: {integrity: sha512-W7asp9DhM6q0W6DYNwIkLSKOvxlXRrif+UXBMxzsJUuqmhE7oVU+gS3THO4S/Puh7Xzgm858UNaFi6dxTP8dJA==} + + '@lezer/python@1.1.19': + resolution: {integrity: sha512-MhQIURHRytsNzP/YXnqpYKW6la6voAH3kyplTOOiCdjyFY6cWWGFVmYVdHIPrElqSDf4iCDktQCockB9FxuhzQ==} + + '@lezer/rust@1.0.2': + resolution: {integrity: sha512-Lz5sIPBdF2FUXcWeCu1//ojFAZqzTQNRga0aYv6dYXqJqPfMdCAI0NzajWUd4Xijj1IKJLtjoXRPMvTKWBcqKg==} + + '@lezer/sass@1.1.0': + resolution: {integrity: sha512-3mMGdCTUZ/84ArHOuXWQr37pnf7f+Nw9ycPUeKX+wu19b7pSMcZGLbaXwvD2APMBDOGxPmpK/O6S1v1EvLoqgQ==} + + '@lezer/xml@1.0.6': + resolution: {integrity: sha512-CdDwirL0OEaStFue/66ZmFSeppuL6Dwjlk8qk153mSQwiSH/Dlri4GNymrNWnUmPl2Um7QfV1FO9KFUyX3Twww==} + + '@lezer/yaml@1.0.4': + resolution: {integrity: sha512-2lrrHqxalACEbxIbsjhqGpSW8kWpUKuY6RHgnSAFZa6qK62wvnPxA8hGOwOoDbwHcOFs5M4o27mjGu+P7TvBmw==} + + '@marijn/find-cluster-break@1.0.4': + resolution: {integrity: sha512-Wy0V7+SGUjnF9/TkiM1hKVDPj7jKXduPNboMVtHTA8dySMURWqfg/JZ9E2Sq8JgSJmkl7k7Qe9FLeMSrSraWmQ==} + + '@milkdown/components@7.22.1': + resolution: {integrity: sha512-6IA8fcFcBTm/x1X1typz73yUoT1JuN4srmifGAIeWEtCnayEwRjFxpQOoQrfvMgBYx4DSHcPVLhJUlR/xbBtxg==} + peerDependencies: + '@codemirror/language': ^6 + '@codemirror/state': ^6 + '@codemirror/view': ^6 + + '@milkdown/core@7.22.1': + resolution: {integrity: sha512-X4O3al2aYugpFP/Do7VoPgvVEftjJVi+6UhZmz9fSdqMtpU70AitJ8R/erUA18hay2hWvNO9m3pxIJoR6no6KQ==} + + '@milkdown/crepe@7.22.1': + resolution: {integrity: sha512-0BZTGBRV8lnlKsA3vmPK5Qyomjqd952493AIzfnbhiYwzHpluX03iMtOgHC6E2UcpMXP86P5CXhPUWjzDu+JZQ==} + + '@milkdown/ctx@7.22.1': + resolution: {integrity: sha512-6+LJdo3DcrkO1lzGcje0yWqaG6ZKgTR8kDxyDrrm7iocBjq3M+bkw04f99ZG/BLp1Rbc4yRyin2mUy6m4SEVaA==} + + '@milkdown/exception@7.22.1': + resolution: {integrity: sha512-wXUfn+fpWy0jeJ6AVEjKPieouLfJIDLQ4IRqyEL3d5yZDiZTtKu1Va0+RprrvqANpGJ1YBRQ1uCgDE6sJgTEjQ==} + + '@milkdown/kit@7.22.1': + resolution: {integrity: sha512-gXLMhjqe0j8XRSUe97LBXbpZ0sDi5EM6nnt1zXewUaGDS3mleMjNntSCWrp9ln40kz8tGs0ol50kSAr1n/JBnQ==} + + '@milkdown/plugin-block@7.22.1': + resolution: {integrity: sha512-R0gOuKRqR1DyFULD75Oic0+57DXTthagUZbbB9lsHM59aQmxKJ1nRmujptPeMfDlDfEod2ao5rsow7LO8p+ZWQ==} + + '@milkdown/plugin-clipboard@7.22.1': + resolution: {integrity: sha512-H1meyLEj2fOnFWSopeQ2H7hl6VXM+OQZoU9H7GrlHFM5GKtBFBErFFV4Cl5tUSVFY+xYy/4rEPOA23Ba1u6OfA==} + + '@milkdown/plugin-cursor@7.22.1': + resolution: {integrity: sha512-3tJzpQl5cyn+8vzsHkPBYsW6QacEN7yP2O5GkyUjrNLvMIQ5vVi7GUuztLeoouJKlOc1vjIq3h7ARXCgHAKe8g==} + + '@milkdown/plugin-diff@7.22.1': + resolution: {integrity: sha512-qjuCMx11HwhMlTJuybqbFZT8PQkasSi0qICxq2HdYqH0WQuLO99I2mb17UAJz1aF+JM9rp1StHWr4bxC0ofamA==} + + '@milkdown/plugin-history@7.22.1': + resolution: {integrity: sha512-SRD6emVhfVmA6mrcCsCiWrONN/2Kp+VT5LLojIQxNc/spzjWw15PtkA3r4nUe9cZmNN5rE7XvrPaA0WnjJIyeQ==} + + '@milkdown/plugin-indent@7.22.1': + resolution: {integrity: sha512-s/wmqxaJpIKT01gEXsC9gCkzA3Clm+MNioZLzNCYD8xI/4Hf3AhmIEoEqf3LIQ9w10Zs2yhIxIrknNWfCOgsEw==} + + '@milkdown/plugin-listener@7.22.1': + resolution: {integrity: sha512-6k8JMDrdAL0E0WygpDX1YOR0Q9Wc4pia8pIMN5nN5liEeAyNaM6LwAxXJY+awQJ0OstDKHTfjkh7WzJo4QiXOA==} + + '@milkdown/plugin-slash@7.22.1': + resolution: {integrity: sha512-eFKCjfgXfAQusTSOyzhz4nASquOApdiBy9hnGkPB/SJ6oltTC8SonB3nIxF/X0wPZHfn09vuz/JBqh9cyDtXJA==} + + '@milkdown/plugin-streaming@7.22.1': + resolution: {integrity: sha512-CR0lujyc7ae0sbjNfscvS+b+cUP7b6XJ90ioTor605UV+F8EKh5t4PMJM79IVzSUCeob51a+rtXA2LAA1b/GyA==} + + '@milkdown/plugin-tooltip@7.22.1': + resolution: {integrity: sha512-drdWA/7WlrDr2B+ABYf4tY9xTiwg/CJMUCydfD05dR2d8wOkaF6oOHZwJbWnkWLMtAJWdieOYgfXGPhQRwXxCg==} + + '@milkdown/plugin-trailing@7.22.1': + resolution: {integrity: sha512-Buy8IX3I7wwq0QPfJRep77QnvlkBeg6BvDHkbh5eTMrgnwSiWhN+tV9RVCYpdWXM7QhQZpSjU2SejluLuTyVCg==} + + '@milkdown/plugin-upload@7.22.1': + resolution: {integrity: sha512-vV0bZzdh/PhM+Jk9Nk5cKHDXHY5jt+ePcaitTfvESDYfg83YZ9AglOhw/YclPWklMvswrnCGZZFTZD4daqc4hg==} + + '@milkdown/preset-commonmark@7.22.1': + resolution: {integrity: sha512-it+G0YUG5MDXt0qLB6W083ss5i6tnWAXWCW8SgnmsehGxntkN5//gNM/8vh3rqwl8RvnBvjLWpJ6TgHSlBPhlw==} + + '@milkdown/preset-gfm@7.22.1': + resolution: {integrity: sha512-UPMdHRdMHlVourOOTiwsp3qHu614pDFWlWtVzxe8fyl8uKZUk6IOuewH5ubhqD/opos8OEB+zgEomUGfee1oTw==} + + '@milkdown/prose@7.22.1': + resolution: {integrity: sha512-fqgTHl94G7oDPY94cPYBm6ARxEoLQ10ubkTNLD1nzAlTUfJLULZkIEMSMy4CECncw2go3ExW32CZPpXLJVSxnQ==} + + '@milkdown/theme-nord@7.22.1': + resolution: {integrity: sha512-KBl+XXl0km/7ZETvL14uf7UKVoVyrjGOtuweXKkJkmSAj2pr7luY84YWB3IAjbe7ucjNzY4MUFfEMXwZQZYT6A==} + + '@milkdown/transformer@7.22.1': + resolution: {integrity: sha512-rU1IBtxezNg7TSWaq+RP59/t6tfD3jIPGrwAtMKPIGuYEax+8d1fyGisp98TeI3l0VQEIgMpF+KlNDV+Y1HJVA==} + + '@milkdown/utils@7.22.1': + resolution: {integrity: sha512-ye0LGy/Ez8fjtcYyYj93wp4XfH00JYpCiy1IDHYB+9HVIpnbr3ed7PvY4s2000xmDWe0Vlx07TOyv96yvFrnjQ==} + + '@milkdown/vue@7.22.1': + resolution: {integrity: sha512-9A8BoRzIzQvl7kJaLvPW1OlT7puxNDOabZlHbz/+4hVfG+bhOrK/x7jec7pqxpvvc0Cjm+8h3LU+bJaHlgmszg==} + peerDependencies: + vue: ^3.0.0 + + '@napi-rs/lzma-linux-x64-gnu@1.5.1': + resolution: {integrity: sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==} + engines: {node: ^22.20 || ^24.12 || >=25} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@ocavue/utils@1.7.0': + resolution: {integrity: sha512-yEk9ATNBjTZTtuVFMB/MAIF6zJBvJ2+lVNQvK2+O+ggEBGTgx2tp27d4FPgmD5bRsNHHP3D0SleQia/bvIeV8w==} + '@oxc-project/types@0.146.0': resolution: {integrity: sha512-XC0QsnnhVe7sLIWmYmdPw7x5P0h4W8vUU3Nv1ySgWXtvCz8NizoAEpGXA0sOYoJQV2Rl13LgURAHQ5cI5ILCSA==} @@ -152,30 +637,213 @@ packages: '@rolldown/pluginutils@1.0.1': resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} - '@types/node@26.3.0': - resolution: {integrity: sha512-L3fgrnchriRC2ExBflb8j4uZZURHZfQsmQeyVzhjcHW4kkwVyo8/0h1B2MVzMTrYUJYu6G7EWs14hW/L9putqw==} + '@rollup/rollup-android-arm-eabi@4.63.0': + resolution: {integrity: sha512-70TeIFezKKy65LgAVyQh+w94/gjWhvPWaLaGGeMEgVrPkQhuj/M5bAYYZzIFUj9Y69oHyTm5Um/R6gcLh4A8JA==} + cpu: [arm] + os: [android] - '@vitejs/plugin-vue@6.0.8': - resolution: {integrity: sha512-0ZjgOg7oO6farnNGup7yvoM/YXZV84OZxHAwtflItNa/6zzQyVb5LNxyea3FEKEX2XlagIKzrlH7wwxkKgtiew==} - engines: {node: ^20.19.0 || >=22.12.0} + '@rollup/rollup-android-arm64@4.63.0': + resolution: {integrity: sha512-YC86tYIHK6M1IV+wbzO+Bxk8RCBr6ZyWYgWxUCzaZD8mc8rrFoIJDNzDrkHBYRc/wKdrsIXmm6/F7NzrAO+OrA==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.63.0': + resolution: {integrity: sha512-oI+ECtUcli0y0fi4xpW82GdPIXdTkI8G8DSjG2LRuw09fPAGykaWYH/hXxiKuTxiAjiPSTIIuYUqof5Z2hShWw==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.63.0': + resolution: {integrity: sha512-NwV+1s7TiKrMe4owHyKB/dTLD7ZJD0YEBEhIz+hvav1Cu1GReJjF+rsdNwjzENQeIAbE/CoNiaAc5Vz2h5DPAA==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.63.0': + resolution: {integrity: sha512-tWtHBTu5gOPK4u4Urtk4qAHW3zZ9rQAmbssO8gp7ELvGTGI3aCiq6NqyTQ0PCIg7KbHJF2UkGDDs77YZGxfjCA==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.63.0': + resolution: {integrity: sha512-2qPoJiwTvtHQ27NnYvTnsgk8laXWYuVmNESG8WFZBcEPKLfZ3I27qBJarjVRQtwGeYyRfq5ZowHXih9lm2BItw==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.63.0': + resolution: {integrity: sha512-FQwsTRvLNuHoTdICABJQfbPUSEueISGmnpT06tXTMpfprf5NiKLSXKA0A+w45wJnCmZAnzgqBwbt6ARFuyOi5w==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm-musleabihf@4.63.0': + resolution: {integrity: sha512-BBVTXziw8mY1a4ZbWME9tZyfzqXCDPqaC7Z3heQ29p5dkvXzwL0NwelO8zLa8c3RBKvl3YTuSnBgsBhYBtwjIw==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-arm64-gnu@4.63.0': + resolution: {integrity: sha512-w2Iyy9+RqKwx3d9qWMKsJg0FfRBsY0/pXNv0mCQ3ueRvJI6+QAScfD4nrMlzFLs2HNVW6Ew+mtZfDl9b7Ew5/Q==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm64-musl@4.63.0': + resolution: {integrity: sha512-YK++KtrFRHYE0P6/RtYEAy9t8F37znP+K03RrIuLPYOL6SVlObRumf/0OE4V/h63xL9DwkWbNssZfmA9hawuDA==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loong64-gnu@4.63.0': + resolution: {integrity: sha512-aBfOG6fP7YkkPmTqPwufRJeFyz7WPpECv9XNbnsk9+vg7rxdih0lbtEel7jcRng4LZrrmU3FfitCFyEj4BWDWg==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-loong64-musl@4.63.0': + resolution: {integrity: sha512-LGaHEOeHNAag9VuS1Crs5DFg4RrU9MPi2nVnNJk9DTePx/B6RRYKVmrIXt2h7YOJlwjaFJ6lwtFDliZxScTLrQ==} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-ppc64-gnu@4.63.0': + resolution: {integrity: sha512-jClvk+J0FC3b7Udvegiw5/4hErbHtmsNsQgENnKXDWtNCJXsJYZH5WURvu7imDOO38xYml24eeh5x3A04ppwCw==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-ppc64-musl@4.63.0': + resolution: {integrity: sha512-0OJlaGK+8+B777Ql5okIpD7ua5Ro9+VB9Ve0OKa28OQJZ1RbuUBVNHK/e3pr4BROqsyPl1JrPO1ZxJseCNffcA==} + cpu: [ppc64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-riscv64-gnu@4.63.0': + resolution: {integrity: sha512-Ygsx+HoNH7afwi1bTIXbnTvVnsO+zurPLSYxybV1hHFVU72OWOCl6v05ql/z0hkpAPx+DK7Kn9Bi7MayCcjLTA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-musl@4.63.0': + resolution: {integrity: sha512-pDQxtMGb+OvG3fLwR2OkZlSd47hW+kWg4BYMG/++sR6RqorQccwPTDsxda5hPwiIeIErAnCF9ma3SAU06bdQtQ==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-s390x-gnu@4.63.0': + resolution: {integrity: sha512-0BnUG9mS8I4SSHr3XsxVhuCMEiu+rX61xxZF5vujso4LaiAGFZFxvDjg6Xn6tLPNTUAfuCvQYas4LMQMVsKRSQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-gnu@4.63.0': + resolution: {integrity: sha512-Adu/VttB1dpPNW+FEacrZ+xVm9tFty84+RrFzsqlFaPxoJB+9XXyDGtp5dCOoBwGBIEVH0To7lExFXEx0BIF4A==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.63.0': + resolution: {integrity: sha512-NQ3bDvjUbFKmP23671xUlXtKmqVsUBd6M4PQCvbmNtOy06hnQIdKHy8oG/6S3R/S6He1JgPk6A5VT+prAJMYEw==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-openbsd-x64@4.63.0': + resolution: {integrity: sha512-u2eDAl4+0aFvA13GxlGBtTI3SS3sdgwgtV0HyjZ0QaQVCgNE+jqNGey+GtxWiq+wxr/UycAx/OnfJzApCFamvA==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.63.0': + resolution: {integrity: sha512-XvRb5vfW3wAZQ+ZUG21AnHHDKtNcw99eigzEhjr//NZ3u7SoBaPP0seSc7FgP7p1epAEdAoZckMW9WY/+4w70w==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.63.0': + resolution: {integrity: sha512-iZPmniy4kNBf5yo2RezbkYNNK5HPbXE9+g+twnbqSng7dtLEJy1SKoxiE/ni4FDacjyuZpEeb9U054N4EoKHYw==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.63.0': + resolution: {integrity: sha512-mFBBd+LF37fnE8JnYUOH+imj0aPFPK30vpar4ehJkgnLj9sZn8ZxiRENmLtgIwxK7TC8klF6N57fxdNBwQoqOA==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.63.0': + resolution: {integrity: sha512-ujeqEY3B+zbGn3Z4Q03cUBG/LGWnBJncVT36WER31LcOsQk9+1dmINKKtvmmfChUvRbK1G0R8OhMWFgHgaZtAw==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.63.0': + resolution: {integrity: sha512-hncn90N4sOky0L2LKE5oESKLbxCPeVo4eLA2LSMoDzM+879ml4WSr+Rr4DWknNIVVvS1Hirkc9hx02W6YxS8rQ==} + cpu: [x64] + os: [win32] + + '@types/debug@4.1.13': + resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/hast@3.0.5': + resolution: {integrity: sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==} + + '@types/jsesc@2.5.1': + resolution: {integrity: sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw==} + + '@types/katex@0.16.8': + resolution: {integrity: sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==} + + '@types/lodash-es@4.17.12': + resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==} + + '@types/lodash@4.17.25': + resolution: {integrity: sha512-+K1NIO8I+F9/wNulfVvu23QYd0Pe9/OCqRrim4NoYIf1VoEDL90Ve4ClzpyqBLc7NpGGWRvYNCKZ1BE/Jpf8dQ==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/node@22.20.1': + resolution: {integrity: sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==} + + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@types/web-bluetooth@0.0.21': + resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} + + '@vitejs/plugin-vue@5.2.4': + resolution: {integrity: sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==} + engines: {node: ^18.0.0 || >=20.0.0} peerDependencies: - vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + vite: ^5.0.0 || ^6.0.0 vue: ^3.2.25 - '@volar/language-core@2.4.28': - resolution: {integrity: sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==} + '@volar/language-core@2.4.15': + resolution: {integrity: sha512-3VHw+QZU0ZG9IuQmzT68IyN4hZNd9GchGPhbD9+pa8CVv7rnoOZwo7T8weIbrRmihqy3ATpdfXFnqRrfPVK6CA==} - '@volar/source-map@2.4.28': - resolution: {integrity: sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==} + '@volar/source-map@2.4.15': + resolution: {integrity: sha512-CPbMWlUN6hVZJYGcU/GSoHu4EnCHiLaXI9n8c9la6RaI9W5JHX+NqG+GSQcB0JdC2FIBLdZJwGsfKyBB71VlTg==} - '@volar/typescript@2.4.28': - resolution: {integrity: sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==} + '@volar/typescript@2.4.15': + resolution: {integrity: sha512-2aZ8i0cqPGjXb4BhkMsPYDkkuc2ZQ6yOpqwAuNwUoncELqoy5fRgOQtLR9gB0g902iS0NAkvpIzs27geVyVdPg==} peerDependencies: typescript: '*' peerDependenciesMeta: typescript: optional: true + '@vue-macros/common@3.1.4': + resolution: {integrity: sha512-/5Fv+6DgIcM9ajY05ZmKBv+LMX1M9A0X+IUwDRVdt67ciw8OV9bvG2r34p3RiEadlsQybjhKPRKNXDC8Bp23cw==} + engines: {node: '>=20.19.0'} + peerDependencies: + vue: ^2.7.0 || ^3.2.25 + peerDependenciesMeta: + vue: + optional: true + '@vue/compiler-core@3.5.41': resolution: {integrity: sha512-q0Xtv/F9w2YO/7htQhtiL+Ev2WCJbe5N2hc+XfgyKkEKqWpSxknmT8QOuGdEKNdjPq0c3F7rNpFkTo3Kfrm7pg==} @@ -188,8 +856,25 @@ packages: '@vue/compiler-ssr@3.5.41': resolution: {integrity: sha512-U3v5OejKEGqOI0Wy0+Sz7hGuIFZHA4LSXzrNM3IMIeDyJEBBfTpX26n3SDgToRpP2bLc9FfI2j/kSgcJ8Emq5A==} - '@vue/language-core@3.3.11': - resolution: {integrity: sha512-QJmpliwAVpC/OxubIByPAhNzsQPRc8/gxlN2qnVzVfIMjMDz/9RnXRFoetjz5yEgXVXyp4LqhXq3V53PjmNzFw==} + '@vue/compiler-vue2@2.7.16': + resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} + + '@vue/devtools-api@8.2.1': + resolution: {integrity: sha512-6u4vXBlIBAC1wMplIZgpyPn7uh/s4Bf6F5bMzvLv+EdJ0aHs/+4B7Ygv864EStQSjRbsRzTko/kUG1A1IejQ3A==} + + '@vue/devtools-kit@8.2.1': + resolution: {integrity: sha512-FIGIuq3AWReEpbAHY/cRGeHDfI0qOb8OCQ3YjbEAX04uaxIDbGc9rhkbVcG7rnfHPXE3RsU5KrWOu9V/okd8AQ==} + + '@vue/devtools-shared@8.2.1': + resolution: {integrity: sha512-Fkac7lUdGReh6pVOi3AYPRGe82LQqRmAfThW7RRligOAP0ZA/Z1z9XLHDM9dv34pV2HRc79DK8uKPeG2fLnA/g==} + + '@vue/language-core@2.2.12': + resolution: {integrity: sha512-IsGljWbKGU1MZpBPN+BvPAdr55YPkj2nB/TBNGNC32Vy2qLG25DYu/NBN2vNtZqdRbTRjaoYrahLrToim2NanA==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true '@vue/reactivity@3.5.41': resolution: {integrity: sha512-rznsqKM0np0x18EjzF8x88MpEhdNsffbvFbckLL5+oUKz1BxAImEmO7J1ArRYSyo6aQaVoBDp7jEkT91OOxydA==} @@ -206,23 +891,131 @@ packages: '@vue/shared@3.5.41': resolution: {integrity: sha512-IOnwSCma8j+9xJT6b8H0dEYidC80NsYmNMlZxRsukYcSoGaDBohog5hDxzeUXdFeGWFA++vWvxqOmrr96VlqMA==} - alien-signals@3.2.1: - resolution: {integrity: sha512-I8FjmltrfnDFoZedi5CG8DghVYNhzb/Ijluz7tCSJH0xpd0484Kowhbb1XDYOxfJpU1p5wnM2X54dA+IfGyD1g==} + '@vueuse/core@14.4.0': + resolution: {integrity: sha512-X4WHz1HlCzCBoYXesUkifzzWBAcZgXG8Fi5iNPQg/epdzOB3gu8Fawj3hvuwYR1nGcXGnvxwYYcUC/71++svtQ==} + peerDependencies: + vue: ^3.5.0 + + '@vueuse/metadata@14.4.0': + resolution: {integrity: sha512-swx/255R6JyHZFJhx845iz5CRWDZdCfvkZOpACWc5+c5WHcG24mv8gUT1WIdFQaHt6dq79rvILd9QnCWiyVm9g==} + + '@vueuse/shared@14.4.0': + resolution: {integrity: sha512-JRgY90Sz8DDtPMsaDflvPMp9xYk69JZAmbuDvAquUVXKr2gEjqtzGNTTthLfckH0BzBqvnu31gb4a8TGLRe79g==} + peerDependencies: + vue: ^3.5.0 + + acorn@8.18.0: + resolution: {integrity: sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==} + engines: {node: '>=0.4.0'} + hasBin: true + + alien-signals@1.0.13: + resolution: {integrity: sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==} + + ast-kit@2.2.0: + resolution: {integrity: sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==} + engines: {node: '>=20.19.0'} + + ast-walker-scope@0.9.0: + resolution: {integrity: sha512-IJdzo2vLiElBxKzwS36VsCue/62d6IdWjnPB2v3nuPKeWGynp6FF/CYoLa5i/3jXH/z97ZDdsXz6abpgM6w07A==} + engines: {node: '>=20.19.0'} + + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + birpc@2.9.0: + resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==} + + brace-expansion@2.1.4: + resolution: {integrity: sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==} + + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + codemirror@6.0.2: + resolution: {integrity: sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==} + + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + confbox@0.2.4: + resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} + + crelt@1.0.7: + resolution: {integrity: sha512-aK6BbWfhf4U/wCcLHKPJl/xa6VkVstRaPywWtMKGwuOLc/wZTyQYuoxgvZnNsBvv7Kg3YTBQYYBCggcviQczuA==} csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + de-indent@1.0.2: + resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + dompurify@3.4.14: + resolution: {integrity: sha512-dVoH9z+MY+C9IilgGCk3YfFqjLi3fChm2OiKJMzh6axrJ5qwxqWaZamgmHrpv22CN/KdbZJuGEGgfQoL00LTdg==} + entities@7.0.1: resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} engines: {node: '>=0.12'} + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} + hasBin: true + + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + exsolve@1.1.1: + resolution: {integrity: sha512-9U/jZUgjnSGyntRr6y5Muu1MJcwFl6kPu7k8qLF0IMNfLqvw0NZ4nnVDq0RVoZ0RvCyumib4Ez3KYrVfilrw+g==} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -237,6 +1030,35 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + + hookable@5.5.3: + resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + katex@0.16.47: + resolution: {integrity: sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==} + hasBin: true + + katex@0.18.4: + resolution: {integrity: sha512-IMPntbRLOU+eu88XDiFKqQ8Akhr9Tv7jDMXqPhjG9SI1JMA4DIgXk4x9k4skJz2NZJXBRbC+2pYBLj9olqcZow==} + hasBin: true + lightningcss-android-arm64@1.33.0: resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} engines: {node: '>= 12.0.0'} @@ -311,9 +1133,167 @@ packages: resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==} engines: {node: '>= 12.0.0'} + local-pkg@1.2.1: + resolution: {integrity: sha512-++gUqRDEvcnN6Zhqrr+y/CkVEHhlrR96vZn3nZZPYzMcBUyBtTKzB9NadClFIsIVSsu+3i9tfk/erqy9kAmt7Q==} + engines: {node: '>=14'} + + lodash-es@4.18.1: + resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==} + + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + + magic-string-ast@1.0.3: + resolution: {integrity: sha512-CvkkH1i81zl7mmb94DsRiFeG9V2fR2JeuK8yDgS8oiZSFa++wWLEgZ5ufEOyLHbvSbD1gTRKv9NdX69Rnvr9JA==} + engines: {node: '>=20.19.0'} + magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + + marked@15.0.12: + resolution: {integrity: sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==} + engines: {node: '>= 18'} + hasBin: true + + mdast-util-definitions@6.0.0: + resolution: {integrity: sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==} + + mdast-util-find-and-replace@3.0.2: + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} + + mdast-util-from-markdown@2.0.3: + resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} + + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + + mdast-util-math@3.0.0: + resolution: {integrity: sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.1: + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + + micromark-extension-math@3.1.0: + resolution: {integrity: sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} + engines: {node: '>=16 || 14 >=14.17'} + + mlly@1.8.2: + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + muggle-string@0.4.1: resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} @@ -322,9 +1302,26 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + nanoid@6.0.1: + resolution: {integrity: sha512-3wVS3i51pE2pi1k5FFL/95BGfVS0kSsvDVuGXHOtxox/TywUmtgq+3qiTOTbs9J7KfHaXPiN171k/A6dBnaXFw==} + engines: {node: ^22 || ^24 || >=26} + hasBin: true + + nostics@1.2.0: + resolution: {integrity: sha512-FGqEfhQjrvo1lL8KFifdTQiNwwQHJxC1jtYE1Rc54qF/jxONUNL+kC9gS1krX8Q65PgrQ5fCqH/I4NhWBvdSqg==} + + orderedmap@2.1.1: + resolution: {integrity: sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==} + path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + perfect-debounce@2.1.0: + resolution: {integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -332,59 +1329,237 @@ packages: resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==} engines: {node: '>=12'} + pinia@4.0.3: + resolution: {integrity: sha512-XMQqpvjgG7LMqVhhFUzKLT4KEbsYbfZZ0CZU9PgdFm1O2VKBmIkykL8+SfNhOaT7sR0wT6BEgKT0YNDYWgmVRA==} + peerDependencies: + '@vue/devtools-api': ^8.1.5 + typescript: '>=5.6.0' + vue: ^3.5.11 + peerDependenciesMeta: + typescript: + optional: true + + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + pkg-types@2.3.1: + resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==} + postcss@8.5.26: resolution: {integrity: sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==} engines: {node: ^10 || ^12 || >=14} + prosemirror-changeset@2.4.2: + resolution: {integrity: sha512-ViYrjMSg3YFiXwIhKaluu+/mi3Yrxt6AR8ri14ulTaGcZtXO1CThl7A2gv79qx5fQnOw8woKwyBU2u+9PVCm3w==} + + prosemirror-commands@1.7.2: + resolution: {integrity: sha512-q6Q6szxqdu9Xd6EcdKsqXghu5nQdZTpB4Q9yd04WRc7/jt763e/rT60Owh0L1GYY+T46o5rD+9lEN36dZS43tw==} + + prosemirror-drop-indicator@0.1.4: + resolution: {integrity: sha512-YaRB1pZmU5GCorPVWbc9dbhbwqr4iMBO/AjPu4BTKHCUzxEDUXje2dUyoxOHib/z4uyPUZTJz64h7mHDJZeSzA==} + + prosemirror-dropcursor@1.8.3: + resolution: {integrity: sha512-FoYbsJR8gK+DGlqhNoE29Loa38eIZPzQRIb1VMaDNBoo4OLP6vVof/jR8qFY/6XvUd6Dhug8MDCHl2a/h8RTfQ==} + + prosemirror-gapcursor@1.4.1: + resolution: {integrity: sha512-pMdYaEnjNMSwl11yjEGtgTmLkR08m/Vl+Jj443167p9eB3HVQKhYCc4gmHVDsLPODfZfjr/MmirsdyZziXbQKw==} + + prosemirror-history@1.5.0: + resolution: {integrity: sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==} + + prosemirror-inputrules@1.5.1: + resolution: {integrity: sha512-7wj4uMjKaXWAQ1CDgxNzNtR9AlsuwzHfdFH1ygEHA2KHF2DOEaXl1CJfNPAKCg9qNEh4rum975QLaCiQPyY6Fw==} + + prosemirror-keymap@1.2.3: + resolution: {integrity: sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==} + + prosemirror-model@1.25.11: + resolution: {integrity: sha512-QWg9RhnpLlogAmp3p96uEFrE5txQpFynd4vhBAELkwgOCWQs/X0yCzB3/hrHqiPwf91RG5KyWq6553zs9JqIOQ==} + + prosemirror-safari-ime-span@1.0.2: + resolution: {integrity: sha512-QJqD8s1zE/CuK56kDsUhndh5hiHh/gFnAuPOA9ytva2s85/ZEt2tNWeALTJN48DtWghSKOmiBsvVn2OlnJ5H2w==} + + prosemirror-schema-list@1.5.1: + resolution: {integrity: sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==} + + prosemirror-state@1.4.4: + resolution: {integrity: sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==} + + prosemirror-tables@1.8.5: + resolution: {integrity: sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw==} + + prosemirror-transform@1.12.0: + resolution: {integrity: sha512-GxboyN4AMIsoHNtz5uf2r2Ru551i5hWeCMD6E2Ib4Eogqoub0NflniaBPVQ4MrGE5yZ8JV9tUHg9qcZTTrcN4w==} + + prosemirror-view@1.42.3: + resolution: {integrity: sha512-oTN7EtH+CpwxU9NrwEYWd0UZ4JUx7l048l5A2Xppm4p/60isZYLnth9QVQmC3VRIvdrIWCxwZSd+Uz791G31/w==} + + prosemirror-virtual-cursor@0.4.2: + resolution: {integrity: sha512-pUMKnIuOhhnMcgIJUjhIQTVJruBEGxfMBVQSrK0g2qhGPDm1i12KdsVaFw15dYk+29tZcxjMeR7P5VDKwmbwJg==} + peerDependencies: + prosemirror-model: ^1.0.0 + prosemirror-state: ^1.0.0 + prosemirror-view: ^1.0.0 + peerDependenciesMeta: + prosemirror-model: + optional: true + prosemirror-state: + optional: true + prosemirror-view: + optional: true + + quansync@0.2.11: + resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + + readdirp@5.1.1: + resolution: {integrity: sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==} + engines: {node: '>= 20.19.0'} + + remark-gfm@4.0.1: + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + + remark-inline-links@7.0.0: + resolution: {integrity: sha512-4uj1pPM+F495ySZhTIB6ay2oSkTsKgmYaKk/q5HIdhX2fuyLEegpjWa0VdJRJ01sgOqAFo7MBKdDUejIYBMVMQ==} + + remark-math@6.0.0: + resolution: {integrity: sha512-MMqgnP74Igy+S3WwnhQ7kqGlEerTETXMvJhrUzDikVZ2/uogJCb+WHUg97hK9/jcfc0dkD73s3LN8zU49cTEtA==} + + remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + + remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + + remark@15.0.1: + resolution: {integrity: sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==} + rolldown@1.2.5: resolution: {integrity: sha512-VD2IE5PUG4Oj8zz2VGykiYd5wbnjdIiSsNQb8Qu5B+noEp+A78mu2iVvpp27g8es14Tk9rofNs5Tku9iQCS4fA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true + rollup@4.63.0: + resolution: {integrity: sha512-T5vnZ2y4QqC3/4P+w2+JO+Q/OVdnPsv4XcSYJYMEn0R9/jjl5AgLwO9LAZMzP2lN71O6pypn91rB7lDstUkfrQ==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + rope-sequence@1.3.4: + resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==} + + scule@1.3.0: + resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + style-mod@4.1.3: + resolution: {integrity: sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==} + tinyglobby@0.2.17: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} hasBin: true - undici-types@8.3.0: - resolution: {integrity: sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==} + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} - vite@8.2.2: - resolution: {integrity: sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==} + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-remove-position@5.0.0: + resolution: {integrity: sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} + + unplugin-utils@0.3.2: + resolution: {integrity: sha512-xVToRh2CTmLk2HnEG7ac4rl1MJTT3RFkpS8B++/SnB0kXvuaavD+n3m/vrzyWQOdJNSZQACnbz01pnppbwV5BA==} + engines: {node: '>=20.19.0'} + + unplugin@3.3.0: + resolution: {integrity: sha512-qa66K+crbfyE6JK10GjvbJeRrOsuC/JpbnHctfyp/i4oBTxWOzJfRZyDiOk1PtErMFRu8JhsU/wPvOdBNWe5Rg==} engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + '@farmfe/core': '*' + '@rspack/core': '*' + bun-types-no-globals: '*' + esbuild: '*' + rolldown: '*' + rollup: '*' + unloader: '*' + vite: '*' + webpack: '*' + peerDependenciesMeta: + '@farmfe/core': + optional: true + '@rspack/core': + optional: true + bun-types-no-globals: + optional: true + esbuild: + optional: true + rolldown: + optional: true + rollup: + optional: true + unloader: + optional: true + vite: + optional: true + webpack: + optional: true + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + + vite@6.4.3: + resolution: {integrity: sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - '@vitejs/devtools': ^0.4.0 || ^0.5.0 - esbuild: ^0.27.0 || ^0.28.0 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.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 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' terser: ^5.16.0 tsx: ^4.8.1 yaml: ^2.4.2 peerDependenciesMeta: '@types/node': optional: true - '@vitejs/devtools': - optional: true - esbuild: - optional: true jiti: optional: true less: optional: true + lightningcss: + optional: true sass: optional: true sass-embedded: @@ -403,8 +1578,26 @@ packages: vscode-uri@3.2.0: resolution: {integrity: sha512-m2gXo3bn0G1kT9InzMf07fTbqMbGtyckj3bH5ktLO+1Ssv+yiATZ4dhwaQv9UZWxJh6E9IFGnQyjgWVDWVBDrg==} - vue-tsc@3.3.11: - resolution: {integrity: sha512-gOb0B9rtU2+f1dszwPqSH5kAieIF9ReeLhD3kSRNHv5WZZUQz/JdVXW0RTdqhNTMlQkqKzrTTviqKr/4FYZraQ==} + vue-router@5.2.0: + resolution: {integrity: sha512-QAC5i0LEb1GLG0LXDQmHu8L7FX12j0KwU/JTKmLQUJMrn04gQdKP6Du+p0QwpHb3iy71vBlqnHQ8WAfOSAWhqw==} + peerDependencies: + '@pinia/colada': '>=0.21.2' + '@vue/compiler-sfc': ^3.5.34 || ^4.0.0 + pinia: ^3.0.4 || ^4.0.2 + vite: ^7.3.0 || ^8.0.0 + vue: ^3.5.34 || ^4.0.0 + peerDependenciesMeta: + '@pinia/colada': + optional: true + '@vue/compiler-sfc': + optional: true + pinia: + optional: true + vite: + optional: true + + vue-tsc@2.2.12: + resolution: {integrity: sha512-P7OP77b2h/Pmk+lZdJ0YWs+5tJ6J2+uOQPo7tlBnY44QqQSPYvS0qVT4wqDJgwrZaLe47etJLLQRFia71GYITw==} hasBin: true peerDependencies: typescript: '>=5.0.0' @@ -417,24 +1610,832 @@ packages: typescript: optional: true + w3c-keyname@2.2.8: + resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + + yaml@2.9.0: + resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} + engines: {node: '>= 14.6'} + hasBin: true + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + snapshots: + '@babel/generator@8.0.0': + dependencies: + '@babel/parser': 8.0.4 + '@babel/types': 8.0.4 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + '@types/jsesc': 2.5.1 + jsesc: 3.1.0 + '@babel/helper-string-parser@7.29.7': {} + '@babel/helper-string-parser@8.0.0': {} + '@babel/helper-validator-identifier@7.29.7': {} + '@babel/helper-validator-identifier@8.0.4': {} + '@babel/parser@7.29.8': dependencies: '@babel/types': 7.29.8 + '@babel/parser@8.0.4': + dependencies: + '@babel/types': 8.0.4 + '@babel/types@7.29.8': dependencies: '@babel/helper-string-parser': 7.29.7 '@babel/helper-validator-identifier': 7.29.7 + '@babel/types@8.0.4': + dependencies: + '@babel/helper-string-parser': 8.0.0 + '@babel/helper-validator-identifier': 8.0.4 + + '@codemirror/autocomplete@6.20.3': + dependencies: + '@codemirror/language': 6.12.4 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.9 + '@lezer/common': 1.5.2 + + '@codemirror/commands@6.11.0': + dependencies: + '@codemirror/language': 6.12.4 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.9 + '@lezer/common': 1.5.2 + + '@codemirror/lang-angular@0.1.4': + dependencies: + '@codemirror/lang-html': 6.4.12 + '@codemirror/lang-javascript': 6.2.5 + '@codemirror/language': 6.12.4 + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@codemirror/lang-cpp@6.0.3': + dependencies: + '@codemirror/language': 6.12.4 + '@lezer/cpp': 1.1.6 + + '@codemirror/lang-css@6.3.1': + dependencies: + '@codemirror/autocomplete': 6.20.3 + '@codemirror/language': 6.12.4 + '@codemirror/state': 6.7.1 + '@lezer/common': 1.5.2 + '@lezer/css': 1.3.6 + + '@codemirror/lang-go@6.0.1': + dependencies: + '@codemirror/autocomplete': 6.20.3 + '@codemirror/language': 6.12.4 + '@codemirror/state': 6.7.1 + '@lezer/common': 1.5.2 + '@lezer/go': 1.0.1 + + '@codemirror/lang-html@6.4.12': + dependencies: + '@codemirror/autocomplete': 6.20.3 + '@codemirror/lang-css': 6.3.1 + '@codemirror/lang-javascript': 6.2.5 + '@codemirror/language': 6.12.4 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.9 + '@lezer/common': 1.5.2 + '@lezer/css': 1.3.6 + '@lezer/html': 1.3.13 + + '@codemirror/lang-java@6.0.2': + dependencies: + '@codemirror/language': 6.12.4 + '@lezer/java': 1.1.3 + + '@codemirror/lang-javascript@6.2.5': + dependencies: + '@codemirror/autocomplete': 6.20.3 + '@codemirror/language': 6.12.4 + '@codemirror/lint': 6.9.7 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.9 + '@lezer/common': 1.5.2 + '@lezer/javascript': 1.5.4 + + '@codemirror/lang-jinja@6.0.1': + dependencies: + '@codemirror/autocomplete': 6.20.3 + '@codemirror/lang-html': 6.4.12 + '@codemirror/language': 6.12.4 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.9 + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@codemirror/lang-json@6.0.2': + dependencies: + '@codemirror/language': 6.12.4 + '@lezer/json': 1.0.3 + + '@codemirror/lang-less@6.0.2': + dependencies: + '@codemirror/lang-css': 6.3.1 + '@codemirror/language': 6.12.4 + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@codemirror/lang-liquid@6.3.2': + dependencies: + '@codemirror/autocomplete': 6.20.3 + '@codemirror/lang-html': 6.4.12 + '@codemirror/language': 6.12.4 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.9 + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@codemirror/lang-markdown@6.5.2': + dependencies: + '@codemirror/autocomplete': 6.20.3 + '@codemirror/lang-html': 6.4.12 + '@codemirror/language': 6.12.4 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.9 + '@lezer/common': 1.5.2 + '@lezer/markdown': 1.7.2 + + '@codemirror/lang-php@6.0.2': + dependencies: + '@codemirror/lang-html': 6.4.12 + '@codemirror/language': 6.12.4 + '@codemirror/state': 6.7.1 + '@lezer/common': 1.5.2 + '@lezer/php': 1.0.5 + + '@codemirror/lang-python@6.2.1': + dependencies: + '@codemirror/autocomplete': 6.20.3 + '@codemirror/language': 6.12.4 + '@codemirror/state': 6.7.1 + '@lezer/common': 1.5.2 + '@lezer/python': 1.1.19 + + '@codemirror/lang-rust@6.0.2': + dependencies: + '@codemirror/language': 6.12.4 + '@lezer/rust': 1.0.2 + + '@codemirror/lang-sass@6.0.2': + dependencies: + '@codemirror/lang-css': 6.3.1 + '@codemirror/language': 6.12.4 + '@codemirror/state': 6.7.1 + '@lezer/common': 1.5.2 + '@lezer/sass': 1.1.0 + + '@codemirror/lang-sql@6.10.0': + dependencies: + '@codemirror/autocomplete': 6.20.3 + '@codemirror/language': 6.12.4 + '@codemirror/state': 6.7.1 + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@codemirror/lang-vue@0.1.3': + dependencies: + '@codemirror/lang-html': 6.4.12 + '@codemirror/lang-javascript': 6.2.5 + '@codemirror/language': 6.12.4 + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@codemirror/lang-wast@6.0.2': + dependencies: + '@codemirror/language': 6.12.4 + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@codemirror/lang-xml@6.1.0': + dependencies: + '@codemirror/autocomplete': 6.20.3 + '@codemirror/language': 6.12.4 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.9 + '@lezer/common': 1.5.2 + '@lezer/xml': 1.0.6 + + '@codemirror/lang-yaml@6.1.3': + dependencies: + '@codemirror/autocomplete': 6.20.3 + '@codemirror/language': 6.12.4 + '@codemirror/state': 6.7.1 + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + '@lezer/yaml': 1.0.4 + + '@codemirror/language-data@6.5.2': + dependencies: + '@codemirror/lang-angular': 0.1.4 + '@codemirror/lang-cpp': 6.0.3 + '@codemirror/lang-css': 6.3.1 + '@codemirror/lang-go': 6.0.1 + '@codemirror/lang-html': 6.4.12 + '@codemirror/lang-java': 6.0.2 + '@codemirror/lang-javascript': 6.2.5 + '@codemirror/lang-jinja': 6.0.1 + '@codemirror/lang-json': 6.0.2 + '@codemirror/lang-less': 6.0.2 + '@codemirror/lang-liquid': 6.3.2 + '@codemirror/lang-markdown': 6.5.2 + '@codemirror/lang-php': 6.0.2 + '@codemirror/lang-python': 6.2.1 + '@codemirror/lang-rust': 6.0.2 + '@codemirror/lang-sass': 6.0.2 + '@codemirror/lang-sql': 6.10.0 + '@codemirror/lang-vue': 0.1.3 + '@codemirror/lang-wast': 6.0.2 + '@codemirror/lang-xml': 6.1.0 + '@codemirror/lang-yaml': 6.1.3 + '@codemirror/language': 6.12.4 + '@codemirror/legacy-modes': 6.5.3 + + '@codemirror/language@6.12.4': + dependencies: + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.9 + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + style-mod: 4.1.3 + + '@codemirror/legacy-modes@6.5.3': + dependencies: + '@codemirror/language': 6.12.4 + + '@codemirror/lint@6.9.7': + dependencies: + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.9 + crelt: 1.0.7 + + '@codemirror/search@6.7.1': + dependencies: + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.9 + crelt: 1.0.7 + + '@codemirror/state@6.7.1': + dependencies: + '@marijn/find-cluster-break': 1.0.4 + + '@codemirror/theme-one-dark@6.1.3': + dependencies: + '@codemirror/language': 6.12.4 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.9 + '@lezer/highlight': 1.2.3 + + '@codemirror/view@6.43.9': + dependencies: + '@codemirror/state': 6.7.1 + crelt: 1.0.7 + style-mod: 4.1.3 + w3c-keyname: 2.2.8 + + '@esbuild/aix-ppc64@0.25.12': + optional: true + + '@esbuild/android-arm64@0.25.12': + optional: true + + '@esbuild/android-arm@0.25.12': + optional: true + + '@esbuild/android-x64@0.25.12': + optional: true + + '@esbuild/darwin-arm64@0.25.12': + optional: true + + '@esbuild/darwin-x64@0.25.12': + optional: true + + '@esbuild/freebsd-arm64@0.25.12': + optional: true + + '@esbuild/freebsd-x64@0.25.12': + optional: true + + '@esbuild/linux-arm64@0.25.12': + optional: true + + '@esbuild/linux-arm@0.25.12': + optional: true + + '@esbuild/linux-ia32@0.25.12': + optional: true + + '@esbuild/linux-loong64@0.25.12': + optional: true + + '@esbuild/linux-mips64el@0.25.12': + optional: true + + '@esbuild/linux-ppc64@0.25.12': + optional: true + + '@esbuild/linux-riscv64@0.25.12': + optional: true + + '@esbuild/linux-s390x@0.25.12': + optional: true + + '@esbuild/linux-x64@0.25.12': + optional: true + + '@esbuild/netbsd-arm64@0.25.12': + optional: true + + '@esbuild/netbsd-x64@0.25.12': + optional: true + + '@esbuild/openbsd-arm64@0.25.12': + optional: true + + '@esbuild/openbsd-x64@0.25.12': + optional: true + + '@esbuild/openharmony-arm64@0.25.12': + optional: true + + '@esbuild/sunos-x64@0.25.12': + optional: true + + '@esbuild/win32-arm64@0.25.12': + optional: true + + '@esbuild/win32-ia32@0.25.12': + optional: true + + '@esbuild/win32-x64@0.25.12': + optional: true + + '@floating-ui/core@1.8.0': + dependencies: + '@floating-ui/utils': 0.2.12 + + '@floating-ui/dom@1.8.0': + dependencies: + '@floating-ui/core': 1.8.0 + '@floating-ui/utils': 0.2.12 + + '@floating-ui/utils@0.2.12': {} + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + '@jridgewell/sourcemap-codec@1.5.5': {} - '@oxc-project/types@0.146.0': {} + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@lezer/common@1.5.2': {} + + '@lezer/cpp@1.1.6': + dependencies: + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@lezer/css@1.3.6': + dependencies: + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@lezer/go@1.0.1': + dependencies: + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@lezer/highlight@1.2.3': + dependencies: + '@lezer/common': 1.5.2 + + '@lezer/html@1.3.13': + dependencies: + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@lezer/java@1.1.3': + dependencies: + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@lezer/javascript@1.5.4': + dependencies: + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@lezer/json@1.0.3': + dependencies: + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@lezer/lr@1.4.10': + dependencies: + '@lezer/common': 1.5.2 + + '@lezer/markdown@1.7.2': + dependencies: + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + + '@lezer/php@1.0.5': + dependencies: + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@lezer/python@1.1.19': + dependencies: + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@lezer/rust@1.0.2': + dependencies: + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@lezer/sass@1.1.0': + dependencies: + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@lezer/xml@1.0.6': + dependencies: + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@lezer/yaml@1.0.4': + dependencies: + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@marijn/find-cluster-break@1.0.4': {} + + '@milkdown/components@7.22.1(@codemirror/language@6.12.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.9)(typescript@5.9.3)': + dependencies: + '@codemirror/language': 6.12.4 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.9 + '@floating-ui/dom': 1.8.0 + '@milkdown/core': 7.22.1 + '@milkdown/ctx': 7.22.1 + '@milkdown/exception': 7.22.1 + '@milkdown/plugin-diff': 7.22.1 + '@milkdown/plugin-tooltip': 7.22.1 + '@milkdown/preset-commonmark': 7.22.1 + '@milkdown/preset-gfm': 7.22.1 + '@milkdown/prose': 7.22.1 + '@milkdown/transformer': 7.22.1 + '@milkdown/utils': 7.22.1 + '@types/lodash-es': 4.17.12 + clsx: 2.1.1 + dompurify: 3.4.14 + lodash-es: 4.18.1 + nanoid: 6.0.1 + unist-util-visit: 5.1.0 + vue: 3.5.41(typescript@5.9.3) + transitivePeerDependencies: + - supports-color + - typescript + + '@milkdown/core@7.22.1': + dependencies: + '@milkdown/ctx': 7.22.1 + '@milkdown/exception': 7.22.1 + '@milkdown/prose': 7.22.1 + '@milkdown/transformer': 7.22.1 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + '@milkdown/crepe@7.22.1(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.3)(typescript@5.9.3)': + dependencies: + '@codemirror/commands': 6.11.0 + '@codemirror/language': 6.12.4 + '@codemirror/language-data': 6.5.2 + '@codemirror/state': 6.7.1 + '@codemirror/theme-one-dark': 6.1.3 + '@codemirror/view': 6.43.9 + '@milkdown/kit': 7.22.1(@codemirror/language@6.12.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.9)(typescript@5.9.3) + '@types/lodash-es': 4.17.12 + clsx: 2.1.1 + codemirror: 6.0.2 + dompurify: 3.4.14 + katex: 0.18.4 + lodash-es: 4.18.1 + prosemirror-virtual-cursor: 0.4.2(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.3) + remark-math: 6.0.0 + unist-util-visit: 5.1.0 + vue: 3.5.41(typescript@5.9.3) + transitivePeerDependencies: + - prosemirror-model + - prosemirror-state + - prosemirror-view + - supports-color + - typescript + + '@milkdown/ctx@7.22.1': + dependencies: + '@milkdown/exception': 7.22.1 + + '@milkdown/exception@7.22.1': {} + + '@milkdown/kit@7.22.1(@codemirror/language@6.12.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.9)(typescript@5.9.3)': + dependencies: + '@milkdown/components': 7.22.1(@codemirror/language@6.12.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.9)(typescript@5.9.3) + '@milkdown/core': 7.22.1 + '@milkdown/ctx': 7.22.1 + '@milkdown/exception': 7.22.1 + '@milkdown/plugin-block': 7.22.1 + '@milkdown/plugin-clipboard': 7.22.1 + '@milkdown/plugin-cursor': 7.22.1 + '@milkdown/plugin-diff': 7.22.1 + '@milkdown/plugin-history': 7.22.1 + '@milkdown/plugin-indent': 7.22.1 + '@milkdown/plugin-listener': 7.22.1 + '@milkdown/plugin-slash': 7.22.1 + '@milkdown/plugin-streaming': 7.22.1 + '@milkdown/plugin-tooltip': 7.22.1 + '@milkdown/plugin-trailing': 7.22.1 + '@milkdown/plugin-upload': 7.22.1 + '@milkdown/preset-commonmark': 7.22.1 + '@milkdown/preset-gfm': 7.22.1 + '@milkdown/prose': 7.22.1 + '@milkdown/transformer': 7.22.1 + '@milkdown/utils': 7.22.1 + transitivePeerDependencies: + - '@codemirror/language' + - '@codemirror/state' + - '@codemirror/view' + - supports-color + - typescript + + '@milkdown/plugin-block@7.22.1': + dependencies: + '@floating-ui/dom': 1.8.0 + '@milkdown/core': 7.22.1 + '@milkdown/ctx': 7.22.1 + '@milkdown/prose': 7.22.1 + '@milkdown/utils': 7.22.1 + '@types/lodash-es': 4.17.12 + lodash-es: 4.18.1 + transitivePeerDependencies: + - supports-color + + '@milkdown/plugin-clipboard@7.22.1': + dependencies: + '@milkdown/core': 7.22.1 + '@milkdown/ctx': 7.22.1 + '@milkdown/prose': 7.22.1 + '@milkdown/utils': 7.22.1 + transitivePeerDependencies: + - supports-color + + '@milkdown/plugin-cursor@7.22.1': + dependencies: + '@milkdown/ctx': 7.22.1 + '@milkdown/prose': 7.22.1 + '@milkdown/utils': 7.22.1 + prosemirror-drop-indicator: 0.1.4 + transitivePeerDependencies: + - supports-color + + '@milkdown/plugin-diff@7.22.1': + dependencies: + '@milkdown/core': 7.22.1 + '@milkdown/ctx': 7.22.1 + '@milkdown/prose': 7.22.1 + '@milkdown/transformer': 7.22.1 + '@milkdown/utils': 7.22.1 + transitivePeerDependencies: + - supports-color + + '@milkdown/plugin-history@7.22.1': + dependencies: + '@milkdown/core': 7.22.1 + '@milkdown/ctx': 7.22.1 + '@milkdown/prose': 7.22.1 + '@milkdown/utils': 7.22.1 + transitivePeerDependencies: + - supports-color + + '@milkdown/plugin-indent@7.22.1': + dependencies: + '@milkdown/ctx': 7.22.1 + '@milkdown/prose': 7.22.1 + '@milkdown/utils': 7.22.1 + transitivePeerDependencies: + - supports-color + + '@milkdown/plugin-listener@7.22.1': + dependencies: + '@milkdown/core': 7.22.1 + '@milkdown/ctx': 7.22.1 + '@milkdown/prose': 7.22.1 + '@types/lodash-es': 4.17.12 + lodash-es: 4.18.1 + transitivePeerDependencies: + - supports-color + + '@milkdown/plugin-slash@7.22.1': + dependencies: + '@floating-ui/dom': 1.8.0 + '@milkdown/ctx': 7.22.1 + '@milkdown/prose': 7.22.1 + '@milkdown/utils': 7.22.1 + '@types/lodash-es': 4.17.12 + lodash-es: 4.18.1 + transitivePeerDependencies: + - supports-color + + '@milkdown/plugin-streaming@7.22.1': + dependencies: + '@milkdown/core': 7.22.1 + '@milkdown/ctx': 7.22.1 + '@milkdown/plugin-diff': 7.22.1 + '@milkdown/prose': 7.22.1 + '@milkdown/utils': 7.22.1 + transitivePeerDependencies: + - supports-color + + '@milkdown/plugin-tooltip@7.22.1': + dependencies: + '@floating-ui/dom': 1.8.0 + '@milkdown/ctx': 7.22.1 + '@milkdown/prose': 7.22.1 + '@milkdown/utils': 7.22.1 + '@types/lodash-es': 4.17.12 + lodash-es: 4.18.1 + transitivePeerDependencies: + - supports-color + + '@milkdown/plugin-trailing@7.22.1': + dependencies: + '@milkdown/ctx': 7.22.1 + '@milkdown/prose': 7.22.1 + '@milkdown/utils': 7.22.1 + transitivePeerDependencies: + - supports-color + + '@milkdown/plugin-upload@7.22.1': + dependencies: + '@milkdown/core': 7.22.1 + '@milkdown/ctx': 7.22.1 + '@milkdown/exception': 7.22.1 + '@milkdown/prose': 7.22.1 + '@milkdown/utils': 7.22.1 + transitivePeerDependencies: + - supports-color + + '@milkdown/preset-commonmark@7.22.1': + dependencies: + '@milkdown/core': 7.22.1 + '@milkdown/ctx': 7.22.1 + '@milkdown/exception': 7.22.1 + '@milkdown/prose': 7.22.1 + '@milkdown/transformer': 7.22.1 + '@milkdown/utils': 7.22.1 + remark-inline-links: 7.0.0 + unist-util-visit: 5.1.0 + unist-util-visit-parents: 6.0.2 + transitivePeerDependencies: + - supports-color + + '@milkdown/preset-gfm@7.22.1': + dependencies: + '@milkdown/core': 7.22.1 + '@milkdown/ctx': 7.22.1 + '@milkdown/exception': 7.22.1 + '@milkdown/preset-commonmark': 7.22.1 + '@milkdown/prose': 7.22.1 + '@milkdown/transformer': 7.22.1 + '@milkdown/utils': 7.22.1 + prosemirror-safari-ime-span: 1.0.2 + remark-gfm: 4.0.1 + transitivePeerDependencies: + - supports-color + + '@milkdown/prose@7.22.1': + dependencies: + '@milkdown/exception': 7.22.1 + prosemirror-changeset: 2.4.2 + prosemirror-commands: 1.7.2 + prosemirror-dropcursor: 1.8.3 + prosemirror-gapcursor: 1.4.1 + prosemirror-history: 1.5.0 + prosemirror-inputrules: 1.5.1 + prosemirror-keymap: 1.2.3 + prosemirror-model: 1.25.11 + prosemirror-schema-list: 1.5.1 + prosemirror-state: 1.4.4 + prosemirror-tables: 1.8.5 + prosemirror-transform: 1.12.0 + prosemirror-view: 1.42.3 + + '@milkdown/theme-nord@7.22.1': + dependencies: + '@milkdown/core': 7.22.1 + '@milkdown/ctx': 7.22.1 + '@milkdown/prose': 7.22.1 + clsx: 2.1.1 + transitivePeerDependencies: + - supports-color + + '@milkdown/transformer@7.22.1': + dependencies: + '@milkdown/exception': 7.22.1 + '@milkdown/prose': 7.22.1 + remark: 15.0.1 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + '@milkdown/utils@7.22.1': + dependencies: + '@milkdown/core': 7.22.1 + '@milkdown/ctx': 7.22.1 + '@milkdown/exception': 7.22.1 + '@milkdown/prose': 7.22.1 + '@milkdown/transformer': 7.22.1 + nanoid: 6.0.1 + transitivePeerDependencies: + - supports-color + + '@milkdown/vue@7.22.1(@codemirror/language@6.12.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.9)(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.3)(typescript@5.9.3)(vue@3.5.41(typescript@5.9.3))': + dependencies: + '@milkdown/crepe': 7.22.1(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.3)(typescript@5.9.3) + '@milkdown/kit': 7.22.1(@codemirror/language@6.12.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.9)(typescript@5.9.3) + vue: 3.5.41(typescript@5.9.3) + transitivePeerDependencies: + - '@codemirror/language' + - '@codemirror/state' + - '@codemirror/view' + - prosemirror-model + - prosemirror-state + - prosemirror-view + - supports-color + - typescript + + '@napi-rs/lzma-linux-x64-gnu@1.5.1': + optional: true + + '@ocavue/utils@1.7.0': {} + + '@oxc-project/types@0.146.0': + optional: true '@rolldown/binding-android-arm-eabi@1.2.5': optional: true @@ -481,32 +2482,150 @@ snapshots: '@rolldown/binding-win32-x64-msvc@1.2.5': optional: true - '@rolldown/pluginutils@1.0.1': {} + '@rolldown/pluginutils@1.0.1': + optional: true - '@types/node@26.3.0': - dependencies: - undici-types: 8.3.0 + '@rollup/rollup-android-arm-eabi@4.63.0': + optional: true - '@vitejs/plugin-vue@6.0.8(vite@8.2.2(@types/node@26.3.0))(vue@3.5.41(typescript@5.9.3))': + '@rollup/rollup-android-arm64@4.63.0': + optional: true + + '@rollup/rollup-darwin-arm64@4.63.0': + optional: true + + '@rollup/rollup-darwin-x64@4.63.0': + optional: true + + '@rollup/rollup-freebsd-arm64@4.63.0': + optional: true + + '@rollup/rollup-freebsd-x64@4.63.0': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.63.0': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.63.0': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.63.0': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.63.0': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.63.0': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.63.0': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.63.0': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.63.0': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.63.0': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.63.0': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.63.0': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.63.0': + optional: true + + '@rollup/rollup-linux-x64-musl@4.63.0': + optional: true + + '@rollup/rollup-openbsd-x64@4.63.0': + optional: true + + '@rollup/rollup-openharmony-arm64@4.63.0': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.63.0': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.63.0': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.63.0': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.63.0': + optional: true + + '@types/debug@4.1.13': dependencies: - '@rolldown/pluginutils': 1.0.1 - vite: 8.2.2(@types/node@26.3.0) + '@types/ms': 2.1.0 + + '@types/estree@1.0.9': {} + + '@types/hast@3.0.5': + dependencies: + '@types/unist': 3.0.3 + + '@types/jsesc@2.5.1': {} + + '@types/katex@0.16.8': {} + + '@types/lodash-es@4.17.12': + dependencies: + '@types/lodash': 4.17.25 + + '@types/lodash@4.17.25': {} + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/ms@2.1.0': {} + + '@types/node@22.20.1': + dependencies: + undici-types: 6.21.0 + + '@types/trusted-types@2.0.7': + optional: true + + '@types/unist@3.0.3': {} + + '@types/web-bluetooth@0.0.21': {} + + '@vitejs/plugin-vue@5.2.4(vite@6.4.3(@types/node@22.20.1)(lightningcss@1.33.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.9.3))': + dependencies: + vite: 6.4.3(@types/node@22.20.1)(lightningcss@1.33.0)(yaml@2.9.0) vue: 3.5.41(typescript@5.9.3) - '@volar/language-core@2.4.28': + '@volar/language-core@2.4.15': dependencies: - '@volar/source-map': 2.4.28 + '@volar/source-map': 2.4.15 - '@volar/source-map@2.4.28': {} + '@volar/source-map@2.4.15': {} - '@volar/typescript@2.4.28(typescript@5.9.3)': + '@volar/typescript@2.4.15(typescript@5.9.3)': dependencies: - '@volar/language-core': 2.4.28 + '@volar/language-core': 2.4.15 path-browserify: 1.0.1 vscode-uri: 3.2.0 optionalDependencies: typescript: 5.9.3 + '@vue-macros/common@3.1.4(vue@3.5.41(typescript@5.9.3))': + dependencies: + '@vue/compiler-sfc': 3.5.41 + ast-kit: 2.2.0 + local-pkg: 1.2.1 + magic-string-ast: 1.0.3 + unplugin-utils: 0.3.2 + optionalDependencies: + vue: 3.5.41(typescript@5.9.3) + '@vue/compiler-core@3.5.41': dependencies: '@babel/parser': 7.29.8 @@ -537,15 +2656,36 @@ snapshots: '@vue/compiler-dom': 3.5.41 '@vue/shared': 3.5.41 - '@vue/language-core@3.3.11': + '@vue/compiler-vue2@2.7.16': dependencies: - '@volar/language-core': 2.4.28 + de-indent: 1.0.2 + he: 1.2.0 + + '@vue/devtools-api@8.2.1': + dependencies: + '@vue/devtools-kit': 8.2.1 + + '@vue/devtools-kit@8.2.1': + dependencies: + '@vue/devtools-shared': 8.2.1 + birpc: 2.9.0 + hookable: 5.5.3 + perfect-debounce: 2.1.0 + + '@vue/devtools-shared@8.2.1': {} + + '@vue/language-core@2.2.12(typescript@5.9.3)': + dependencies: + '@volar/language-core': 2.4.15 '@vue/compiler-dom': 3.5.41 + '@vue/compiler-vue2': 2.7.16 '@vue/shared': 3.5.41 - alien-signals: 3.2.1 + alien-signals: 1.0.13 + minimatch: 9.0.9 muggle-string: 0.4.1 path-browserify: 1.0.1 - picomatch: 4.0.7 + optionalDependencies: + typescript: 5.9.3 '@vue/reactivity@3.5.41': dependencies: @@ -571,16 +2711,136 @@ snapshots: '@vue/shared@3.5.41': {} - alien-signals@3.2.1: {} + '@vueuse/core@14.4.0(vue@3.5.41(typescript@5.9.3))': + dependencies: + '@types/web-bluetooth': 0.0.21 + '@vueuse/metadata': 14.4.0 + '@vueuse/shared': 14.4.0(vue@3.5.41(typescript@5.9.3)) + vue: 3.5.41(typescript@5.9.3) + + '@vueuse/metadata@14.4.0': {} + + '@vueuse/shared@14.4.0(vue@3.5.41(typescript@5.9.3))': + dependencies: + vue: 3.5.41(typescript@5.9.3) + + acorn@8.18.0: {} + + alien-signals@1.0.13: {} + + ast-kit@2.2.0: + dependencies: + '@babel/parser': 7.29.8 + pathe: 2.0.3 + + ast-walker-scope@0.9.0: + dependencies: + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 + ast-kit: 2.2.0 + + bail@2.0.2: {} + + balanced-match@1.0.2: {} + + birpc@2.9.0: {} + + brace-expansion@2.1.4: + dependencies: + balanced-match: 1.0.2 + + ccount@2.0.1: {} + + character-entities@2.0.2: {} + + chokidar@5.0.0: + dependencies: + readdirp: 5.1.1 + + clsx@2.1.1: {} + + codemirror@6.0.2: + dependencies: + '@codemirror/autocomplete': 6.20.3 + '@codemirror/commands': 6.11.0 + '@codemirror/language': 6.12.4 + '@codemirror/lint': 6.9.7 + '@codemirror/search': 6.7.1 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.9 + + commander@8.3.0: {} + + confbox@0.1.8: {} + + confbox@0.2.4: {} + + crelt@1.0.7: {} csstype@3.2.3: {} - detect-libc@2.1.2: {} + de-indent@1.0.2: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decode-named-character-reference@1.3.0: + dependencies: + character-entities: 2.0.2 + + dequal@2.0.3: {} + + detect-libc@2.1.2: + optional: true + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + dompurify@3.4.14: + optionalDependencies: + '@types/trusted-types': 2.0.7 entities@7.0.1: {} + esbuild@0.25.12: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + + escape-string-regexp@5.0.0: {} + estree-walker@2.0.2: {} + exsolve@1.1.1: {} + + extend@3.0.2: {} + fdir@6.5.0(picomatch@4.0.7): optionalDependencies: picomatch: 4.0.7 @@ -588,6 +2848,24 @@ snapshots: fsevents@2.3.3: optional: true + he@1.2.0: {} + + hookable@5.5.3: {} + + is-plain-obj@4.1.0: {} + + jsesc@3.1.0: {} + + json5@2.2.3: {} + + katex@0.16.47: + dependencies: + commander: 8.3.0 + + katex@0.18.4: + dependencies: + commander: 8.3.0 + lightningcss-android-arm64@1.33.0: optional: true @@ -636,27 +2914,556 @@ snapshots: lightningcss-linux-x64-musl: 1.33.0 lightningcss-win32-arm64-msvc: 1.33.0 lightningcss-win32-x64-msvc: 1.33.0 + optional: true + + local-pkg@1.2.1: + dependencies: + mlly: 1.8.2 + pkg-types: 2.3.1 + quansync: 0.2.11 + + lodash-es@4.18.1: {} + + longest-streak@3.1.0: {} + + magic-string-ast@1.0.3: + dependencies: + magic-string: 0.30.21 magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + markdown-table@3.0.4: {} + + marked@15.0.12: {} + + mdast-util-definitions@6.0.0: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + unist-util-visit: 5.1.0 + + mdast-util-find-and-replace@3.0.2: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + mdast-util-from-markdown@2.0.3: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.2 + micromark-util-character: 2.1.1 + + mdast-util-gfm-footnote@2.1.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-strikethrough@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-task-list-item@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm@3.1.0: + dependencies: + mdast-util-from-markdown: 2.0.3 + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.0 + mdast-util-gfm-strikethrough: 2.0.0 + mdast-util-gfm-table: 2.0.0 + mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-math@3.0.0: + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + longest-streak: 3.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + unist-util-remove-position: 5.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.1.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-table@2.1.1: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.1 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-math@3.1.0: + dependencies: + '@types/katex': 0.16.8 + devlop: 1.1.0 + katex: 0.16.47 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.3.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.13 + debug: 4.4.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + + minimatch@9.0.9: + dependencies: + brace-expansion: 2.1.4 + + mlly@1.8.2: + dependencies: + acorn: 8.18.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.4 + + ms@2.1.3: {} + muggle-string@0.4.1: {} nanoid@3.3.18: {} + nanoid@6.0.1: {} + + nostics@1.2.0: {} + + orderedmap@2.1.1: {} + path-browserify@1.0.1: {} + pathe@2.0.3: {} + + perfect-debounce@2.1.0: {} + picocolors@1.1.1: {} picomatch@4.0.7: {} + pinia@4.0.3(@vue/devtools-api@8.2.1)(typescript@5.9.3)(vue@3.5.41(typescript@5.9.3)): + dependencies: + '@vue/devtools-api': 8.2.1 + nostics: 1.2.0 + vue: 3.5.41(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.2 + pathe: 2.0.3 + + pkg-types@2.3.1: + dependencies: + confbox: 0.2.4 + exsolve: 1.1.1 + pathe: 2.0.3 + postcss@8.5.26: dependencies: nanoid: 3.3.18 picocolors: 1.1.1 source-map-js: 1.2.1 + prosemirror-changeset@2.4.2: + dependencies: + prosemirror-transform: 1.12.0 + + prosemirror-commands@1.7.2: + dependencies: + prosemirror-model: 1.25.11 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.12.0 + + prosemirror-drop-indicator@0.1.4: + dependencies: + '@ocavue/utils': 1.7.0 + prosemirror-model: 1.25.11 + prosemirror-state: 1.4.4 + prosemirror-view: 1.42.3 + + prosemirror-dropcursor@1.8.3: + dependencies: + prosemirror-state: 1.4.4 + prosemirror-transform: 1.12.0 + prosemirror-view: 1.42.3 + + prosemirror-gapcursor@1.4.1: + dependencies: + prosemirror-keymap: 1.2.3 + prosemirror-model: 1.25.11 + prosemirror-state: 1.4.4 + prosemirror-view: 1.42.3 + + prosemirror-history@1.5.0: + dependencies: + prosemirror-state: 1.4.4 + prosemirror-transform: 1.12.0 + prosemirror-view: 1.42.3 + rope-sequence: 1.3.4 + + prosemirror-inputrules@1.5.1: + dependencies: + prosemirror-state: 1.4.4 + prosemirror-transform: 1.12.0 + + prosemirror-keymap@1.2.3: + dependencies: + prosemirror-state: 1.4.4 + w3c-keyname: 2.2.8 + + prosemirror-model@1.25.11: + dependencies: + orderedmap: 2.1.1 + + prosemirror-safari-ime-span@1.0.2: + dependencies: + prosemirror-state: 1.4.4 + prosemirror-view: 1.42.3 + + prosemirror-schema-list@1.5.1: + dependencies: + prosemirror-model: 1.25.11 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.12.0 + + prosemirror-state@1.4.4: + dependencies: + prosemirror-model: 1.25.11 + prosemirror-transform: 1.12.0 + prosemirror-view: 1.42.3 + + prosemirror-tables@1.8.5: + dependencies: + prosemirror-keymap: 1.2.3 + prosemirror-model: 1.25.11 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.12.0 + prosemirror-view: 1.42.3 + + prosemirror-transform@1.12.0: + dependencies: + prosemirror-model: 1.25.11 + + prosemirror-view@1.42.3: + dependencies: + prosemirror-model: 1.25.11 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.12.0 + + prosemirror-virtual-cursor@0.4.2(prosemirror-model@1.25.11)(prosemirror-state@1.4.4)(prosemirror-view@1.42.3): + optionalDependencies: + prosemirror-model: 1.25.11 + prosemirror-state: 1.4.4 + prosemirror-view: 1.42.3 + + quansync@0.2.11: {} + + readdirp@5.1.1: {} + + remark-gfm@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-gfm: 3.1.0 + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-inline-links@7.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-definitions: 6.0.0 + unist-util-visit: 5.1.0 + + remark-math@6.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-math: 3.0.0 + micromark-extension-math: 3.1.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-parse@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + micromark-util-types: 2.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-stringify@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-to-markdown: 2.1.2 + unified: 11.0.5 + + remark@15.0.1: + dependencies: + '@types/mdast': 4.0.4 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + rolldown@1.2.5: dependencies: '@oxc-project/types': 0.146.0 @@ -677,35 +3484,176 @@ snapshots: '@rolldown/binding-openharmony-arm64': 1.2.5 '@rolldown/binding-win32-arm64-msvc': 1.2.5 '@rolldown/binding-win32-x64-msvc': 1.2.5 + optional: true + + rollup@4.63.0: + dependencies: + '@types/estree': 1.0.9 + optionalDependencies: + '@napi-rs/lzma-linux-x64-gnu': 1.5.1 + '@rollup/rollup-android-arm-eabi': 4.63.0 + '@rollup/rollup-android-arm64': 4.63.0 + '@rollup/rollup-darwin-arm64': 4.63.0 + '@rollup/rollup-darwin-x64': 4.63.0 + '@rollup/rollup-freebsd-arm64': 4.63.0 + '@rollup/rollup-freebsd-x64': 4.63.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.63.0 + '@rollup/rollup-linux-arm-musleabihf': 4.63.0 + '@rollup/rollup-linux-arm64-gnu': 4.63.0 + '@rollup/rollup-linux-arm64-musl': 4.63.0 + '@rollup/rollup-linux-loong64-gnu': 4.63.0 + '@rollup/rollup-linux-loong64-musl': 4.63.0 + '@rollup/rollup-linux-ppc64-gnu': 4.63.0 + '@rollup/rollup-linux-ppc64-musl': 4.63.0 + '@rollup/rollup-linux-riscv64-gnu': 4.63.0 + '@rollup/rollup-linux-riscv64-musl': 4.63.0 + '@rollup/rollup-linux-s390x-gnu': 4.63.0 + '@rollup/rollup-linux-x64-gnu': 4.63.0 + '@rollup/rollup-linux-x64-musl': 4.63.0 + '@rollup/rollup-openbsd-x64': 4.63.0 + '@rollup/rollup-openharmony-arm64': 4.63.0 + '@rollup/rollup-win32-arm64-msvc': 4.63.0 + '@rollup/rollup-win32-ia32-msvc': 4.63.0 + '@rollup/rollup-win32-x64-gnu': 4.63.0 + '@rollup/rollup-win32-x64-msvc': 4.63.0 + fsevents: 2.3.3 + + rope-sequence@1.3.4: {} + + scule@1.3.0: {} source-map-js@1.2.1: {} + style-mod@4.1.3: {} + tinyglobby@0.2.17: dependencies: fdir: 6.5.0(picomatch@4.0.7) picomatch: 4.0.7 + trough@2.2.0: {} + typescript@5.9.3: {} - undici-types@8.3.0: {} + ufo@1.6.4: {} - vite@8.2.2(@types/node@26.3.0): + undici-types@6.21.0: {} + + unified@11.0.5: dependencies: - lightningcss: 1.33.0 + '@types/unist': 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-remove-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-visit: 5.1.0 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.1.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + unplugin-utils@0.3.2: + dependencies: + pathe: 2.0.3 + picomatch: 4.0.7 + + unplugin@3.3.0(esbuild@0.25.12)(rolldown@1.2.5)(rollup@4.63.0)(vite@6.4.3(@types/node@22.20.1)(lightningcss@1.33.0)(yaml@2.9.0)): + dependencies: + '@jridgewell/remapping': 2.3.5 + picomatch: 4.0.7 + webpack-virtual-modules: 0.6.2 + optionalDependencies: + esbuild: 0.25.12 + rolldown: 1.2.5 + rollup: 4.63.0 + vite: 6.4.3(@types/node@22.20.1)(lightningcss@1.33.0)(yaml@2.9.0) + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + + vite@6.4.3(@types/node@22.20.1)(lightningcss@1.33.0)(yaml@2.9.0): + dependencies: + esbuild: 0.25.12 + fdir: 6.5.0(picomatch@4.0.7) picomatch: 4.0.7 postcss: 8.5.26 - rolldown: 1.2.5 + rollup: 4.63.0 tinyglobby: 0.2.17 optionalDependencies: - '@types/node': 26.3.0 + '@types/node': 22.20.1 fsevents: 2.3.3 + lightningcss: 1.33.0 + yaml: 2.9.0 vscode-uri@3.2.0: {} - vue-tsc@3.3.11(typescript@5.9.3): + vue-router@5.2.0(@vue/compiler-sfc@3.5.41)(esbuild@0.25.12)(pinia@4.0.3(@vue/devtools-api@8.2.1)(typescript@5.9.3)(vue@3.5.41(typescript@5.9.3)))(rolldown@1.2.5)(rollup@4.63.0)(vite@6.4.3(@types/node@22.20.1)(lightningcss@1.33.0)(yaml@2.9.0))(vue@3.5.41(typescript@5.9.3)): dependencies: - '@volar/typescript': 2.4.28(typescript@5.9.3) - '@vue/language-core': 3.3.11 + '@babel/generator': 8.0.0 + '@vue-macros/common': 3.1.4(vue@3.5.41(typescript@5.9.3)) + '@vue/devtools-api': 8.2.1 + ast-walker-scope: 0.9.0 + chokidar: 5.0.0 + json5: 2.2.3 + local-pkg: 1.2.1 + magic-string: 0.30.21 + mlly: 1.8.2 + muggle-string: 0.4.1 + nostics: 1.2.0 + pathe: 2.0.3 + picomatch: 4.0.7 + scule: 1.3.0 + tinyglobby: 0.2.17 + unplugin: 3.3.0(esbuild@0.25.12)(rolldown@1.2.5)(rollup@4.63.0)(vite@6.4.3(@types/node@22.20.1)(lightningcss@1.33.0)(yaml@2.9.0)) + unplugin-utils: 0.3.2 + vue: 3.5.41(typescript@5.9.3) + yaml: 2.9.0 + optionalDependencies: + '@vue/compiler-sfc': 3.5.41 + pinia: 4.0.3(@vue/devtools-api@8.2.1)(typescript@5.9.3)(vue@3.5.41(typescript@5.9.3)) + vite: 6.4.3(@types/node@22.20.1)(lightningcss@1.33.0)(yaml@2.9.0) + transitivePeerDependencies: + - '@farmfe/core' + - '@rspack/core' + - bun-types-no-globals + - esbuild + - rolldown + - rollup + - unloader + - webpack + + vue-tsc@2.2.12(typescript@5.9.3): + dependencies: + '@volar/typescript': 2.4.15(typescript@5.9.3) + '@vue/language-core': 2.2.12(typescript@5.9.3) typescript: 5.9.3 vue@3.5.41(typescript@5.9.3): @@ -717,3 +3665,11 @@ snapshots: '@vue/shared': 3.5.41 optionalDependencies: typescript: 5.9.3 + + w3c-keyname@2.2.8: {} + + webpack-virtual-modules@0.6.2: {} + + yaml@2.9.0: {} + + zwitch@2.0.4: {} diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 02cbee3..547ed72 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -1,95 +1,18 @@ + + diff --git a/frontend/src/components/common/AppShell.vue b/frontend/src/components/common/AppShell.vue new file mode 100644 index 0000000..d6ef9a7 --- /dev/null +++ b/frontend/src/components/common/AppShell.vue @@ -0,0 +1,87 @@ + + + + + diff --git a/frontend/src/components/common/PrimarySidebar.vue b/frontend/src/components/common/PrimarySidebar.vue new file mode 100644 index 0000000..e5d0047 --- /dev/null +++ b/frontend/src/components/common/PrimarySidebar.vue @@ -0,0 +1,124 @@ + + + + + diff --git a/frontend/src/components/common/SecondarySidebar.vue b/frontend/src/components/common/SecondarySidebar.vue new file mode 100644 index 0000000..34c8a1b --- /dev/null +++ b/frontend/src/components/common/SecondarySidebar.vue @@ -0,0 +1,112 @@ + + + + + diff --git a/frontend/src/components/common/StatusBar.vue b/frontend/src/components/common/StatusBar.vue new file mode 100644 index 0000000..a7e212d --- /dev/null +++ b/frontend/src/components/common/StatusBar.vue @@ -0,0 +1,165 @@ + + + + + diff --git a/frontend/src/components/common/TitleBar.vue b/frontend/src/components/common/TitleBar.vue new file mode 100644 index 0000000..b0292b2 --- /dev/null +++ b/frontend/src/components/common/TitleBar.vue @@ -0,0 +1,191 @@ + + + + + diff --git a/frontend/src/contracts/index.ts b/frontend/src/contracts/index.ts new file mode 100644 index 0000000..01e03c9 --- /dev/null +++ b/frontend/src/contracts/index.ts @@ -0,0 +1,364 @@ +// ============ Notes & Blocks ============ + +export interface Note { + note_id: string + title: string + file_path: string + folder_path: string + created_at: string + updated_at: string + tags: string[] + word_count: number +} + +export interface NoteBlock { + block_id: string + note_id: string + heading_path: string + start_offset: number + end_offset: number + content: string + content_hash: string + token_count: number +} + +export interface FileNode { + id: string + name: string + path: string + type: 'file' | 'folder' + children?: FileNode[] + is_open?: boolean + is_dirty?: boolean + is_external_changed?: boolean +} + +// ============ Search ============ + +export interface SearchRequest { + query: string + mode?: 'fts' | 'vector' | 'hybrid' + folder?: string + note_id?: string + tag?: string + limit?: number + offset?: number +} + +export interface SearchResult { + block_id: string + note_id: string + note_title: string + file_path: string + heading_path: string + snippet: string + score: number + match_type: 'fts' | 'vector' | 'hybrid' + tags?: string[] +} + +// ============ Chat ============ + +export interface Conversation { + conversation_id: string + title: string + created_at: string + updated_at: string + message_count: number +} + +export interface ChatMessage { + message_id: string + conversation_id: string + role: 'user' | 'assistant' | 'system' + content: string + created_at: string + citations?: Citation[] + tool_calls?: ToolCall[] +} + +export interface Citation { + note_id: string + block_id: string + file_path: string + heading_path: string + content: string + source_audio?: { + start_time: number + end_time: number + speaker?: string + } +} + +// ============ Model Events (SSE) ============ + +export type ModelEventType = + | 'TextDelta' + | 'ThinkingDelta' + | 'ToolCallStart' + | 'ToolCallDelta' + | 'ToolCallEnd' + | 'Usage' + | 'Error' + | 'Done' + +export interface ModelEvent { + event: ModelEventType + sequence: number + data: Record + timestamp: string +} + +// ============ Agent ============ + +export type AgentRunStatus = + | 'queued' + | 'running' + | 'waiting_permission' + | 'completed' + | 'failed' + | 'cancelled' + +export interface AgentRun { + run_id: string + status: AgentRunStatus + current_step: number + max_steps: number + token_usage?: TokenUsage + started_at?: string + completed_at?: string + error?: string +} + +export type AgentEventType = + | 'RunStarted' + | 'TextDelta' + | 'ThinkingDelta' + | 'ToolCall' + | 'ToolResult' + | 'PermissionRequired' + | 'Usage' + | 'Citation' + | 'RunCompleted' + | 'RunFailed' + | 'RunCancelled' + +export interface AgentEvent { + event: AgentEventType + sequence: number + run_id: string + data: Record + timestamp: string +} + +export interface ToolCall { + tool_call_id: string + name: string + parameters: Record + status: 'pending' | 'running' | 'completed' | 'error' + result?: string + started_at?: string + completed_at?: string + error_code?: string + error_message?: string +} + +export interface ToolDefinition { + name: string + description: string + parameters: Record + source?: 'builtin' | 'plugin' + plugin_id?: string +} + +export interface PermissionRequest { + request_id: string + run_id: string + tool_name: string + permission: string + parameters: Record + impact: string +} + +export interface TokenUsage { + input_tokens: number + output_tokens: number + total_tokens: number +} + +// ============ Skill ============ + +export type SkillStatus = + | 'installed' + | 'disabled' + | 'ready' + | 'dependency_missing' + | 'permission_required' + | 'error' + +export interface Skill { + skill_id: string + name: string + version: string + description: string + icon?: string + author?: string + permissions: string[] + tools: string[] + retrieval_config?: { + top_k: number + rerank: boolean + citation: boolean + } + model_requirements?: { + capabilities: string[] + } + status: SkillStatus + missing_dependencies?: string[] + enabled: boolean +} + +// ============ Plugin ============ + +export type PluginStatus = + | 'installed' + | 'disabled' + | 'starting' + | 'ready' + | 'error' + | 'dependency_missing' + | 'permission_required' + +export interface PluginContribution { + type: 'tool' | 'command' | 'importer' | 'exporter' | 'sidebar_panel' | 'settings_section' + id: string + name: string + description?: string +} + +export interface Plugin { + plugin_id: string + name: string + version: string + description: string + icon?: string + author?: string + status: PluginStatus + enabled: boolean + permissions: string[] + contributions: PluginContribution[] + backend_type?: 'mcp' | 'internal' + transport?: 'stdio' | 'websocket' + last_error?: string + dependent_skills?: string[] +} + +// ============ Provider ============ + +export type ProviderType = 'openai' | 'anthropic' | 'ollama' | 'openai-compatible' | 'mock' + +export interface ModelCapability { + chat: boolean + vision: boolean + tool_calling: boolean + reasoning: boolean + streaming: boolean + structured_output: boolean + embedding: boolean +} + +export interface ModelInfo { + model_id: string + name: string + capabilities: Partial + context_window?: number +} + +export interface ProviderConfig { + provider_id: string + provider_type: ProviderType + name: string + base_url?: string + default_model: string + enabled: boolean + capabilities: Partial + credential_id?: string + has_credential: boolean +} + +// ============ Tasks ============ + +export type TaskStatus = 'todo' | 'in_progress' | 'done' | 'cancelled' +export type TaskPriority = 'low' | 'medium' | 'high' +export type TaskSource = 'user' | 'note' | 'agent' + +export interface TaskItem { + task_id: string + title: string + description?: string + status: TaskStatus + priority: TaskPriority + due_date?: string + note_id?: string + note_title?: string + source: TaskSource + created_at: string + updated_at: string +} + +// ============ Theme ============ + +export interface ThemeConfig { + theme_id: string + name: string + version: string + description: string + is_dark: boolean + author?: string + builtin: boolean +} + +// ============ Index ============ + +export interface IndexStatus { + status: 'idle' | 'indexing' | 'error' + pending_jobs: number + total_notes: number + total_blocks: number + fts_enabled: boolean + vector_enabled: boolean + embedding_model?: string + reranker_model?: string + last_indexed_at?: string + error?: string +} + +// ============ System ============ + +export interface ApiError { + code: string + message: string + details?: Record +} + +export interface ErrorResponse { + error: ApiError +} + +export interface SystemStatus { + name: string + version: string + environment: 'development' | 'production' | 'test' + ai_core_available: boolean +} + +export type SaveStatus = + | 'idle' + | 'dirty' + | 'saving' + | 'saved' + | 'save_failed' + | 'external_changed' + | 'conflict' + +export type AiCoreStatus = 'starting' | 'running' | 'stopped' | 'error' diff --git a/frontend/src/features/vault/VaultEntry.vue b/frontend/src/features/vault/VaultEntry.vue new file mode 100644 index 0000000..0e908dc --- /dev/null +++ b/frontend/src/features/vault/VaultEntry.vue @@ -0,0 +1,441 @@ + + + + + diff --git a/frontend/src/features/workspace/FileTreePanel.vue b/frontend/src/features/workspace/FileTreePanel.vue new file mode 100644 index 0000000..cbe342b --- /dev/null +++ b/frontend/src/features/workspace/FileTreePanel.vue @@ -0,0 +1,406 @@ + + + + + + + diff --git a/frontend/src/features/workspace/WorkspaceView.vue b/frontend/src/features/workspace/WorkspaceView.vue new file mode 100644 index 0000000..2fc276a --- /dev/null +++ b/frontend/src/features/workspace/WorkspaceView.vue @@ -0,0 +1,72 @@ + + + + + diff --git a/frontend/src/main.ts b/frontend/src/main.ts index fe5bae3..151c644 100644 --- a/frontend/src/main.ts +++ b/frontend/src/main.ts @@ -1,5 +1,17 @@ import { createApp } from 'vue' +import { createPinia } from 'pinia' import App from './App.vue' -import './style.css' +import router from './router' +import './styles/tokens.css' +import { useThemeStore } from './stores/theme' -createApp(App).mount('#app') +const app = createApp(App) +const pinia = createPinia() + +app.use(pinia) +app.use(router) + +const themeStore = useThemeStore() +themeStore.initTheme() + +app.mount('#app') diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts new file mode 100644 index 0000000..997bf2c --- /dev/null +++ b/frontend/src/router/index.ts @@ -0,0 +1,100 @@ +import { createRouter, createWebHashHistory } from 'vue-router' +import { useWorkspaceStore } from '@/stores/workspace' + +const routes = [ + { + path: '/', + name: 'vault-entry', + component: () => import('@/features/vault/VaultEntry.vue'), + meta: { title: '选择知识库' }, + }, + { + path: '/workspace', + name: 'workspace', + component: () => import('@/features/workspace/WorkspaceView.vue'), + meta: { title: '工作区', requiresVault: true }, + }, + { + path: '/search', + name: 'search', + component: () => import('@/features/search/SearchView.vue'), + meta: { title: '搜索', requiresVault: true }, + }, + { + path: '/chat', + name: 'chat', + component: () => import('@/features/chat/ChatView.vue'), + meta: { title: 'AI 对话', requiresVault: true }, + }, + { + path: '/agent/runs/:runId?', + name: 'agent', + component: () => import('@/features/agent/AgentView.vue'), + meta: { title: 'Agent Trace', requiresVault: true }, + }, + { + path: '/tasks', + name: 'tasks', + component: () => import('@/features/tasks/TasksView.vue'), + meta: { title: '任务', requiresVault: true }, + }, + { + path: '/extensions/skills', + name: 'skills', + component: () => import('@/features/skills/SkillsView.vue'), + meta: { title: 'Skill 管理', requiresVault: true }, + }, + { + path: '/extensions/plugins', + name: 'plugins', + component: () => import('@/features/plugins/PluginsView.vue'), + meta: { title: 'Plugin 管理', requiresVault: true }, + }, + { + path: '/themes', + name: 'themes', + component: () => import('@/features/themes/ThemesView.vue'), + meta: { title: '主题管理', requiresVault: true }, + }, + { + path: '/settings', + name: 'settings', + component: () => import('@/features/settings/SettingsView.vue'), + meta: { title: '设置', requiresVault: true }, + children: [ + { path: '', redirect: '/settings/general' }, + { path: 'general', component: () => import('@/features/settings/sections/GeneralSection.vue') }, + { path: 'editor', component: () => import('@/features/settings/sections/EditorSection.vue') }, + { path: 'providers', component: () => import('@/features/settings/sections/ProvidersSection.vue') }, + { path: 'index', component: () => import('@/features/settings/sections/IndexSection.vue') }, + { path: 'permissions', component: () => import('@/features/settings/sections/PermissionsSection.vue') }, + { path: 'ai-core', component: () => import('@/features/settings/sections/AiCoreSection.vue') }, + ], + }, +] + +const router = createRouter({ + history: createWebHashHistory(), + routes, +}) + +router.beforeEach((to, _from, next) => { + const workspaceStore = useWorkspaceStore() + if (to.meta.requiresVault && !workspaceStore.hasVault) { + next({ path: '/' }) + return + } + if (to.path === '/' && workspaceStore.hasVault) { + next({ path: '/workspace' }) + return + } + next() +}) + +router.afterEach((to) => { + const baseTitle = '知笔知己' + const title = to.meta.title as string | undefined + document.title = title ? `${title} · ${baseTitle}` : baseTitle +}) + +export default router diff --git a/frontend/src/services/agentService.ts b/frontend/src/services/agentService.ts new file mode 100644 index 0000000..102e661 --- /dev/null +++ b/frontend/src/services/agentService.ts @@ -0,0 +1,289 @@ +import apiClient from './apiClient' +import { SseClient } from './sseClient' +import type { AgentRun, AgentEvent, ToolDefinition, PermissionRequest } from '@/contracts' + +export async function listAgentRuns(params?: { + limit?: number + offset?: number +}): Promise<{ items: AgentRun[]; total: number }> { + return apiClient.get('/api/agent/runs', { params }) +} + +export async function getAgentRun(runId: string): Promise { + return apiClient.get(`/api/agent/runs/${runId}`) +} + +export interface CreateAgentRunRequest { + task: string + provider_id?: string + model?: string + skill_id?: string + allowed_tools?: string[] + max_steps?: number + tool_timeout?: number + run_timeout?: number + token_budget?: number + allow_network?: boolean + max_concurrent_tools?: number +} + +export async function createAgentRun(request: CreateAgentRunRequest): Promise { + return apiClient.post('/api/agent/runs', request) +} + +export async function cancelAgentRun(runId: string): Promise { + return apiClient.post(`/api/agent/runs/${runId}/cancel`) +} + +export async function listTools(): Promise { + try { + return await apiClient.get('/api/tools') + } catch { + return mockTools + } +} + +export function streamAgentEvents( + runId: string, + handlers: { + onEvent?: (event: AgentEvent) => void + onError?: (error: Error) => void + onDone?: () => void + onOpen?: () => void + } +): SseClient { + const client = new SseClient({ + url: `/api/agent/runs/${runId}/events`, + method: 'GET', + onEvent: (eventName, data) => { + handlers.onEvent?.({ + event: eventName as AgentEvent['event'], + sequence: (data.sequence as number) || 0, + run_id: (data.run_id as string) || runId, + data: (data.data || data) as Record, + timestamp: (data.timestamp as string) || new Date().toISOString(), + }) + }, + onError: handlers.onError, + onDone: handlers.onDone, + onOpen: handlers.onOpen, + }) + client.connect().catch(() => {}) + return client +} + +export async function respondToPermission( + runId: string, + requestId: string, + decision: 'allow' | 'deny', + scope?: 'once' | 'session' | 'always' +): Promise { + return apiClient.post(`/api/agent/runs/${runId}/permissions/${requestId}`, { + decision, + scope, + }) +} + +export const mockTools: ToolDefinition[] = [ + { + name: 'notes.search', + description: '搜索笔记,支持关键词和语义检索', + parameters: { + type: 'object', + properties: { + query: { type: 'string', description: '搜索关键词' }, + limit: { type: 'number', description: '返回结果数量' }, + }, + required: ['query'], + }, + source: 'builtin', + }, + { + name: 'notes.read', + description: '读取指定笔记的完整内容', + parameters: { + type: 'object', + properties: { + note_id: { type: 'string' }, + }, + required: ['note_id'], + }, + source: 'builtin', + }, + { + name: 'notes.create', + description: '创建新笔记', + parameters: { + type: 'object', + properties: { + title: { type: 'string' }, + content: { type: 'string' }, + folder_path: { type: 'string' }, + }, + required: ['title', 'content'], + }, + source: 'builtin', + }, + { + name: 'rag.search', + description: '基于 RAG 的语义检索,返回相关知识片段', + parameters: { + type: 'object', + properties: { + query: { type: 'string' }, + top_k: { type: 'number' }, + }, + required: ['query'], + }, + source: 'builtin', + }, + { + name: 'tasks.create', + description: '创建任务', + parameters: { + type: 'object', + properties: { + title: { type: 'string' }, + description: { type: 'string' }, + priority: { type: 'string', enum: ['low', 'medium', 'high'] }, + }, + required: ['title'], + }, + source: 'builtin', + }, + { + name: 'system.echo', + description: '回显输入内容(测试用)', + parameters: { + type: 'object', + properties: { + text: { type: 'string' }, + }, + required: ['text'], + }, + source: 'builtin', + }, + { + name: 'math.add', + description: '两数相加(测试用)', + parameters: { + type: 'object', + properties: { + a: { type: 'number' }, + b: { type: 'number' }, + }, + required: ['a', 'b'], + }, + source: 'builtin', + }, +] + +export const mockAgentRuns: AgentRun[] = [ + { + run_id: 'run-1', + status: 'completed', + current_step: 3, + max_steps: 10, + token_usage: { input_tokens: 2340, output_tokens: 890, total_tokens: 3230 }, + started_at: '2026-08-25T11:00:00Z', + completed_at: '2026-08-25T11:02:30Z', + }, + { + run_id: 'run-2', + status: 'running', + current_step: 2, + max_steps: 10, + token_usage: { input_tokens: 1500, output_tokens: 420, total_tokens: 1920 }, + started_at: '2026-08-26T09:30:00Z', + }, +] + +export const mockAgentEvents: AgentEvent[] = [ + { + event: 'RunStarted', + sequence: 1, + run_id: 'run-1', + data: { task: '帮我整理红黑树的核心知识点' }, + timestamp: '2026-08-25T11:00:00Z', + }, + { + event: 'ThinkingDelta', + sequence: 2, + run_id: 'run-1', + data: { text: '我需要先搜索笔记中关于红黑树的内容...' }, + timestamp: '2026-08-25T11:00:01Z', + }, + { + event: 'ToolCall', + sequence: 3, + run_id: 'run-1', + data: { + tool_call_id: 'tc-1', + name: 'notes.search', + parameters: { query: '红黑树 插入 删除', limit: 5 }, + status: 'running', + }, + timestamp: '2026-08-25T11:00:02Z', + }, + { + event: 'ToolResult', + sequence: 4, + run_id: 'run-1', + data: { + tool_call_id: 'tc-1', + name: 'notes.search', + status: 'completed', + result: '找到 5 条相关结果,包括红黑树性质、插入操作、删除操作等...', + duration_ms: 320, + }, + timestamp: '2026-08-25T11:00:02Z', + }, + { + event: 'Citation', + sequence: 5, + run_id: 'run-1', + data: { + note_id: 'n-rbt', + block_id: 'b1', + heading_path: '数据结构 / 红黑树 / 性质', + }, + timestamp: '2026-08-25T11:00:03Z', + }, + { + event: 'ThinkingDelta', + sequence: 6, + run_id: 'run-1', + data: { text: '搜索结果很全面,让我整理一下结构...' }, + timestamp: '2026-08-25T11:00:03Z', + }, + { + event: 'TextDelta', + sequence: 7, + run_id: 'run-1', + data: { text: '## 红黑树核心知识点整理\n\n### 1. 基本性质\n红黑树是一种自平衡二叉搜索树,每个节点带有颜色属性...' }, + timestamp: '2026-08-25T11:00:04Z', + }, + { + event: 'Usage', + sequence: 8, + run_id: 'run-1', + data: { input_tokens: 2340, output_tokens: 890, total_tokens: 3230 }, + timestamp: '2026-08-25T11:02:30Z', + }, + { + event: 'RunCompleted', + sequence: 9, + run_id: 'run-1', + data: { message: 'Task completed successfully' }, + timestamp: '2026-08-25T11:02:30Z', + }, +] + +export const mockPermissionRequest: PermissionRequest = { + request_id: 'perm-1', + run_id: 'run-2', + tool_name: 'notes.create', + permission: 'notes.write', + parameters: { title: '红黑树知识点总结', folder_path: '/数据结构' }, + impact: '将在你的知识库中创建一篇新笔记', +} diff --git a/frontend/src/services/apiClient.ts b/frontend/src/services/apiClient.ts new file mode 100644 index 0000000..a2e5654 --- /dev/null +++ b/frontend/src/services/apiClient.ts @@ -0,0 +1,102 @@ +import type { ApiError, ErrorResponse } from '@/contracts' + +const BASE_URL = import.meta.env.VITE_API_BASE || '' + +interface RequestOptions extends RequestInit { + params?: Record + token?: string +} + +export class ApiErrorClass extends Error { + code: string + details?: Record + + constructor(code: string, message: string, details?: Record) { + super(message) + this.name = 'ApiError' + this.code = code + this.details = details + } +} + +async function request(path: string, options: RequestOptions = {}): Promise { + const { params, token, headers, ...rest } = options + + let url = path.startsWith('http') ? path : `${BASE_URL}${path}` + + if (params) { + const usp = new URLSearchParams() + Object.entries(params).forEach(([k, v]) => { + if (v !== undefined && v !== null) usp.append(k, String(v)) + }) + const qs = usp.toString() + if (qs) url += `?${qs}` + } + + const reqHeaders: Record = { + 'Content-Type': 'application/json', + ...(headers as Record), + } + + if (token) { + reqHeaders['Authorization'] = `Bearer ${token}` + } + + const reqId = crypto.randomUUID() + reqHeaders['X-Request-Id'] = reqId + + try { + const resp = await fetch(url, { + ...rest, + headers: reqHeaders, + }) + + if (resp.ok) { + if (resp.status === 204) return undefined as T + const ct = resp.headers.get('content-type') || '' + if (ct.includes('application/json')) return (await resp.json()) as T + return resp as unknown as T + } + + let errBody: ErrorResponse | null = null + try { + errBody = (await resp.json()) as ErrorResponse + } catch { + /* ignore */ + } + + const code = errBody?.error?.code || `HTTP_${resp.status}` + const message = errBody?.error?.message || `Request failed with status ${resp.status}` + const details = errBody?.error?.details + + throw new ApiErrorClass(code, message, details) + } catch (e) { + if (e instanceof ApiErrorClass) throw e + throw new ApiErrorClass('NETWORK_ERROR', (e as Error).message || 'Network error') + } +} + +export const apiClient = { + get(path: string, options?: Omit) { + return request(path, { ...options, method: 'GET' }) + }, + post(path: string, body?: unknown, options?: Omit) { + return request(path, { + ...options, + method: 'POST', + body: body !== undefined ? JSON.stringify(body) : undefined, + }) + }, + patch(path: string, body?: unknown, options?: Omit) { + return request(path, { + ...options, + method: 'PATCH', + body: body !== undefined ? JSON.stringify(body) : undefined, + }) + }, + delete(path: string, options?: Omit) { + return request(path, { ...options, method: 'DELETE' }) + }, +} + +export default apiClient diff --git a/frontend/src/services/chatService.ts b/frontend/src/services/chatService.ts new file mode 100644 index 0000000..6aa0bb3 --- /dev/null +++ b/frontend/src/services/chatService.ts @@ -0,0 +1,138 @@ +import apiClient from './apiClient' +import { SseClient } from './sseClient' +import type { Conversation, ChatMessage, ModelEvent } from '@/contracts' + +export async function listConversations(): Promise { + return apiClient.get('/api/conversations') +} + +export async function getConversation(conversationId: string): Promise { + return apiClient.get(`/api/conversations/${conversationId}`) +} + +export async function getMessages(conversationId: string): Promise { + return apiClient.get(`/api/conversations/${conversationId}/messages`) +} + +export interface ChatRequest { + conversation_id?: string + message: string + provider_id?: string + model?: string + use_rag?: boolean + skill_id?: string + attachments?: string[] +} + +export function streamChat( + request: ChatRequest, + handlers: { + onEvent?: (event: ModelEvent) => void + onError?: (error: Error) => void + onDone?: () => void + onOpen?: () => void + } +): SseClient { + const client = new SseClient({ + url: '/api/chat', + method: 'POST', + body: request, + onEvent: (eventName, data) => { + handlers.onEvent?.({ + event: eventName as ModelEvent['event'], + sequence: data.sequence as number, + data: (data.data || {}) as Record, + timestamp: (data.timestamp as string) || new Date().toISOString(), + }) + }, + onError: handlers.onError, + onDone: handlers.onDone, + onOpen: handlers.onOpen, + }) + client.connect().catch(() => {}) + return client +} + +export const mockConversations: Conversation[] = [ + { + conversation_id: 'conv-1', + title: '关于红黑树的讨论', + created_at: '2026-08-25T10:00:00Z', + updated_at: '2026-08-25T10:30:00Z', + message_count: 6, + }, + { + conversation_id: 'conv-2', + title: '死锁避免算法', + created_at: '2026-08-24T14:00:00Z', + updated_at: '2026-08-24T15:20:00Z', + message_count: 4, + }, + { + conversation_id: 'conv-3', + title: 'TCP三次握手', + created_at: '2026-08-22T09:00:00Z', + updated_at: '2026-08-22T09:15:00Z', + message_count: 3, + }, +] + +export const mockMessages: Record = { + 'conv-1': [ + { + message_id: 'msg-1', + conversation_id: 'conv-1', + role: 'user', + content: '红黑树的插入操作有哪些情况需要调整?', + created_at: '2026-08-25T10:00:00Z', + }, + { + message_id: 'msg-2', + conversation_id: 'conv-1', + role: 'assistant', + content: + '红黑树插入后可能违反红黑性质,需要通过旋转和变色来修复。主要有以下几种情况:\n\n**情况1:叔叔节点是红色**\n- 将父节点和叔叔节点设为黑色\n- 将祖父节点设为红色\n- 当前节点上移到祖父节点,继续向上调整\n\n**情况2:叔叔节点是黑色,且当前节点是右孩子**\n- 以父节点为支点左旋\n- 将当前节点转换为左孩子,进入情况3\n\n**情况3:叔叔节点是黑色,且当前节点是左孩子**\n- 以祖父节点为支点右旋\n- 将父节点设为黑色,祖父节点设为红色\n\n以上三种情况需要从插入节点开始向上递归处理,直到根节点。', + created_at: '2026-08-25T10:01:00Z', + citations: [ + { + note_id: 'n-rbt', + block_id: 'b1', + file_path: '/数据结构/红黑树.md', + heading_path: '数据结构 / 红黑树 / 插入操作', + content: '插入后可能破坏红黑性质,需要通过变色和旋转来修复...', + }, + { + note_id: 'n-rbt', + block_id: 'b2', + file_path: '/数据结构/红黑树.md', + heading_path: '数据结构 / 红黑树 / 五种情况', + content: 'Case 1: 叔叔为红色,直接变色...', + }, + ], + }, + { + message_id: 'msg-3', + conversation_id: 'conv-1', + role: 'user', + content: '能对比一下 AVL 树和红黑树的性能差异吗?', + created_at: '2026-08-25T10:10:00Z', + }, + { + message_id: 'msg-4', + conversation_id: 'conv-1', + role: 'assistant', + content: + 'AVL 树和红黑树都是平衡二叉搜索树,但它们的平衡策略和性能特点有所不同:\n\n| 特性 | AVL 树 | 红黑树 |\n|------|--------|--------|\n| 严格平衡 | 高度差 ≤ 1 | 黑色高度相同 |\n| 查找速度 | 更快(严格平衡) | 略慢但仍为 O(log n) |\n| 插入/删除 | 旋转更多 | 旋转更少(颜色调整为主) |\n| 存储开销 | 每个节点存高度(int) | 每个节点存颜色(1 bit) |\n| 适用场景 | 读多写少 | 读写均衡或写较多 |\n\n**总结:**\n- 如果应用以查询为主,很少修改,AVL 树可能更优\n- 如果插入删除频繁,红黑树更合适,重平衡开销更低\n- 红黑树在工业界应用更广泛(C++ STL 的 map/set、Java 的 TreeMap 等)', + created_at: '2026-08-25T10:11:00Z', + citations: [ + { + note_id: 'n-rbt', + block_id: 'b3', + file_path: '/数据结构/红黑树.md', + heading_path: '数据结构 / 红黑树 / 与AVL树对比', + content: '红黑树相比AVL树,牺牲了部分平衡性以换取更少的旋转操作...', + }, + ], + }, + ], +} diff --git a/frontend/src/services/index.ts b/frontend/src/services/index.ts new file mode 100644 index 0000000..5208e4d --- /dev/null +++ b/frontend/src/services/index.ts @@ -0,0 +1,15 @@ +export { apiClient, ApiErrorClass } from './apiClient' +export type { ApiError } from './apiClient' +export { SseClient } from './sseClient' +export type { SseClientOptions, SseEventHandler } from './sseClient' +export * as noteService from './noteService' +export * as searchService from './searchService' +export * as chatService from './chatService' +export * as agentService from './agentService' +export * as skillService from './skillService' +export * as pluginService from './pluginService' +export * as providerService from './providerService' +export * as taskService from './taskService' +export * as indexService from './indexService' +export * as systemService from './systemService' +export * as workspaceService from './workspaceService' diff --git a/frontend/src/services/indexService.ts b/frontend/src/services/indexService.ts new file mode 100644 index 0000000..f365f94 --- /dev/null +++ b/frontend/src/services/indexService.ts @@ -0,0 +1,36 @@ +import apiClient from './apiClient' +import type { IndexStatus } from '@/contracts' + +export async function getIndexStatus(): Promise { + try { + return await apiClient.get('/api/index/status') + } catch { + return mockIndexStatus + } +} + +export async function rebuildIndex(scope: 'full' | 'fts' | 'vector' = 'full'): Promise<{ job_id: string }> { + return apiClient.post('/api/index/rebuild', { scope }) +} + +export async function getIndexJob(jobId: string): Promise<{ + job_id: string + status: 'queued' | 'running' | 'completed' | 'failed' + progress: number + total: number + error?: string +}> { + return apiClient.get(`/api/index/jobs/${jobId}`) +} + +export const mockIndexStatus: IndexStatus = { + status: 'idle', + pending_jobs: 0, + total_notes: 42, + total_blocks: 318, + fts_enabled: true, + vector_enabled: true, + embedding_model: 'bge-m3', + reranker_model: 'bge-reranker-base', + last_indexed_at: new Date().toISOString(), +} diff --git a/frontend/src/services/noteService.ts b/frontend/src/services/noteService.ts new file mode 100644 index 0000000..7771be8 --- /dev/null +++ b/frontend/src/services/noteService.ts @@ -0,0 +1,38 @@ +import apiClient from './apiClient' +import type { Note, NoteBlock } from '@/contracts' + +export async function listNotes(params?: { + folder?: string + tag?: string + limit?: number + offset?: number +}): Promise<{ items: Note[]; total: number }> { + return apiClient.get('/api/notes', { params }) +} + +export async function getNote(noteId: string): Promise<{ note: Note; blocks: NoteBlock[] }> { + return apiClient.get(`/api/notes/${noteId}`) +} + +export async function createNote(data: { + title: string + folder_path?: string + content?: string +}): Promise { + return apiClient.post('/api/notes', data) +} + +export async function updateNote( + noteId: string, + data: { title?: string; content?: string; tags?: string[] } +): Promise { + return apiClient.patch(`/api/notes/${noteId}`, data) +} + +export async function deleteNote(noteId: string): Promise { + return apiClient.delete(`/api/notes/${noteId}`) +} + +export async function moveNote(noteId: string, target_folder: string): Promise { + return apiClient.post(`/api/notes/${noteId}/move`, { target_folder }) +} diff --git a/frontend/src/services/pluginService.ts b/frontend/src/services/pluginService.ts new file mode 100644 index 0000000..d2baf2b --- /dev/null +++ b/frontend/src/services/pluginService.ts @@ -0,0 +1,119 @@ +import apiClient from './apiClient' +import type { Plugin } from '@/contracts' + +export async function listPlugins(): Promise { + try { + return await apiClient.get('/api/plugins') + } catch { + return mockPlugins + } +} + +export async function getPlugin(pluginId: string): Promise { + return apiClient.get(`/api/plugins/${pluginId}`) +} + +export async function installPlugin(pluginId: string): Promise { + return apiClient.post('/api/plugins/install', { plugin_id: pluginId }) +} + +export async function enablePlugin(pluginId: string): Promise { + return apiClient.post(`/api/plugins/${pluginId}/enable`) +} + +export async function disablePlugin(pluginId: string): Promise { + return apiClient.post(`/api/plugins/${pluginId}/disable`) +} + +export async function uninstallPlugin(pluginId: string): Promise { + return apiClient.delete(`/api/plugins/${pluginId}`) +} + +export const mockPlugins: Plugin[] = [ + { + plugin_id: 'github-integration', + name: 'GitHub 集成', + version: '1.3.2', + description: '接入 GitHub API,支持搜索 Issue、查看 PR 和管理仓库', + icon: '🐙', + author: '知笔知己团队', + status: 'ready', + enabled: true, + permissions: ['notes.read', 'network.request'], + contributions: [ + { type: 'tool', id: 'github.search_issues', name: '搜索 Issue', description: '搜索 GitHub 仓库中的 Issue' }, + { type: 'tool', id: 'github.get_pr', name: '获取 PR 详情', description: '获取 Pull Request 的详细信息' }, + { type: 'command', id: 'github.open_repo', name: '打开仓库', description: '在浏览器中打开对应 GitHub 仓库' }, + ], + backend_type: 'mcp', + transport: 'stdio', + dependent_skills: ['research-assistant'], + }, + { + plugin_id: 'translator', + name: '翻译助手', + version: '1.0.0', + description: '提供多语言翻译能力,支持文档批量翻译', + icon: '🌐', + author: '社区贡献', + status: 'ready', + enabled: false, + permissions: ['notes.read', 'notes.write', 'network.request'], + contributions: [ + { type: 'tool', id: 'translator.translate', name: '翻译文本', description: '翻译指定文本到目标语言' }, + { type: 'command', id: 'translator.translate_note', name: '翻译当前笔记', description: '翻译当前打开的笔记' }, + { type: 'settings_section', id: 'translator.settings', name: '翻译设置', description: '配置翻译服务和默认语言' }, + ], + backend_type: 'mcp', + transport: 'stdio', + }, + { + plugin_id: 'kanban', + name: '看板视图', + version: '0.8.0', + description: '为任务提供看板视图,支持拖拽排序和多维度筛选', + icon: '📋', + author: '社区贡献', + status: 'installed', + enabled: false, + permissions: ['tasks.read', 'tasks.write'], + contributions: [ + { type: 'sidebar_panel', id: 'kanban.panel', name: '任务看板', description: '以看板方式查看和管理任务' }, + ], + backend_type: 'internal', + }, + { + plugin_id: 'pdf-importer', + name: 'PDF 导入', + version: '2.1.0', + description: '导入 PDF 文档,提取文本和目录结构生成笔记', + icon: '📄', + author: '知笔知己团队', + status: 'error', + enabled: false, + permissions: ['notes.write', 'attachments.read'], + contributions: [ + { type: 'importer', id: 'pdf.import', name: 'PDF 导入器', description: '从 PDF 文件导入内容' }, + ], + backend_type: 'mcp', + transport: 'stdio', + last_error: 'PDF 解析库初始化失败,请检查 Python 依赖', + }, + { + plugin_id: 'calendar', + name: '日历同步', + version: '0.5.0', + description: '同步日历事件,自动生成相关笔记和任务提醒', + icon: '📅', + author: '社区贡献', + status: 'dependency_missing', + enabled: false, + permissions: ['tasks.read', 'tasks.write', 'network.request'], + contributions: [ + { type: 'tool', id: 'calendar.events', name: '日历事件', description: '获取日历事件列表' }, + { type: 'sidebar_panel', id: 'calendar.widget', name: '日历小部件', description: '侧边栏日历视图' }, + ], + backend_type: 'mcp', + transport: 'websocket', + }, +] diff --git a/frontend/src/services/providerService.ts b/frontend/src/services/providerService.ts new file mode 100644 index 0000000..75397fa --- /dev/null +++ b/frontend/src/services/providerService.ts @@ -0,0 +1,149 @@ +import apiClient from './apiClient' +import type { ProviderConfig, ModelInfo } from '@/contracts' + +export async function listProviders(): Promise { + try { + return await apiClient.get('/api/providers') + } catch { + return mockProviders + } +} + +export async function getProvider(providerId: string): Promise { + return apiClient.get(`/api/providers/${providerId}`) +} + +export async function createProvider(data: Omit & { api_key?: string }): Promise { + return apiClient.post('/api/providers', data) +} + +export async function updateProvider(providerId: string, data: Partial & { api_key?: string }): Promise { + return apiClient.patch(`/api/providers/${providerId}`, data) +} + +export async function deleteProvider(providerId: string): Promise { + return apiClient.delete(`/api/providers/${providerId}`) +} + +export async function listModels(providerId: string): Promise { + try { + return await apiClient.get(`/api/providers/${providerId}/models`) + } catch { + return mockModels[providerId] || [] + } +} + +export interface TestResult { + success: boolean + latency_ms?: number + error_code?: string + error_message?: string +} + +export async function testProvider(providerId: string): Promise { + try { + const result = await apiClient.post<{ success: boolean; latency_ms: number }>('/api/providers/test', { provider_id: providerId }) + return { success: result.success, latency_ms: result.latency_ms } + } catch (e: any) { + return { success: false, error_code: e.code || 'TEST_FAILED', error_message: e.message } + } +} + +export const mockProviders: ProviderConfig[] = [ + { + provider_id: 'mock-provider', + provider_type: 'mock', + name: 'Mock Provider (测试)', + default_model: 'mock-1', + enabled: true, + has_credential: true, + capabilities: { + chat: true, + tool_calling: true, + streaming: true, + vision: false, + reasoning: false, + structured_output: true, + embedding: false, + }, + }, + { + provider_id: 'openai-compat-1', + provider_type: 'openai-compatible', + name: 'OpenAI 兼容服务', + base_url: 'https://api.openai.com/v1', + default_model: 'gpt-4o-mini', + enabled: true, + has_credential: true, + capabilities: { + chat: true, + tool_calling: true, + streaming: true, + vision: true, + reasoning: false, + structured_output: true, + embedding: true, + }, + }, + { + provider_id: 'ollama-local', + provider_type: 'ollama', + name: 'Ollama (本地)', + base_url: 'http://127.0.0.1:11434', + default_model: 'qwen2.5:7b', + enabled: false, + has_credential: false, + capabilities: { + chat: true, + tool_calling: false, + streaming: true, + vision: false, + reasoning: false, + structured_output: false, + embedding: true, + }, + }, +] + +export const mockModels: Record = { + 'mock-provider': [ + { + model_id: 'mock-1', + name: 'Mock Model v1', + capabilities: { chat: true, tool_calling: true, streaming: true, structured_output: true }, + context_window: 8192, + }, + ], + 'openai-compat-1': [ + { + model_id: 'gpt-4o-mini', + name: 'GPT-4o Mini', + capabilities: { chat: true, tool_calling: true, streaming: true, vision: true, structured_output: true }, + context_window: 128000, + }, + { + model_id: 'gpt-4o', + name: 'GPT-4o', + capabilities: { chat: true, tool_calling: true, streaming: true, vision: true, structured_output: true, reasoning: true }, + context_window: 128000, + }, + { + model_id: 'text-embedding-3-small', + name: 'Text Embedding 3 Small', + capabilities: { embedding: true }, + }, + ], + 'ollama-local': [ + { + model_id: 'qwen2.5:7b', + name: 'Qwen 2.5 7B', + capabilities: { chat: true, streaming: true }, + context_window: 32768, + }, + { + model_id: 'bge-m3', + name: 'BGE M3', + capabilities: { embedding: true }, + }, + ], +} diff --git a/frontend/src/services/searchService.ts b/frontend/src/services/searchService.ts new file mode 100644 index 0000000..fd7a3e4 --- /dev/null +++ b/frontend/src/services/searchService.ts @@ -0,0 +1,73 @@ +import apiClient from './apiClient' +import type { SearchRequest, SearchResult } from '@/contracts' + +export async function search(request: SearchRequest): Promise<{ + results: SearchResult[] + total: number + mode: SearchRequest['mode'] +}> { + return apiClient.post('/api/search', request) +} + +export async function searchMock(query: string, mode = 'hybrid' as const): Promise<{ + results: SearchResult[] + total: number + mode: 'fts' | 'vector' | 'hybrid' +}> { + await new Promise((r) => setTimeout(r, 300)) + if (!query.trim()) return { results: [], total: 0, mode } + const results: SearchResult[] = [ + { + block_id: 'b1', + note_id: 'n-rbt', + note_title: '红黑树', + file_path: '/数据结构/红黑树.md', + heading_path: '数据结构 / 红黑树 / 插入操作', + snippet: '插入后可能破坏红黑性质,需要通过变色和旋转来修复...', + score: 0.95, + match_type: 'hybrid', + tags: ['数据结构', '树'], + }, + { + block_id: 'b2', + note_id: 'n-rbt', + note_title: '红黑树', + file_path: '/数据结构/红黑树.md', + heading_path: '数据结构 / 红黑树 / 性质', + snippet: '红黑树是一种自平衡二叉搜索树,每个节点带有颜色属性(红或黑)...', + score: 0.87, + match_type: 'fts', + tags: ['数据结构'], + }, + { + block_id: 'b3', + note_id: 'n-bst', + note_title: '二叉搜索树', + file_path: '/数据结构/二叉搜索树.md', + heading_path: '数据结构 / 二叉搜索树 / 基本操作', + snippet: '二叉搜索树的插入需要先找到合适的位置,再添加新节点...', + score: 0.72, + match_type: 'vector', + tags: ['数据结构', '树'], + }, + { + block_id: 'b4', + note_id: 'n-deadlock', + note_title: '死锁', + file_path: '/操作系统/死锁.md', + heading_path: '操作系统 / 死锁 / 必要条件', + snippet: '死锁的四个必要条件:互斥、占有并等待、不可抢占、循环等待...', + score: 0.45, + match_type: 'vector', + tags: ['操作系统'], + }, + ] + const filtered = results.filter( + (r) => + r.note_title.includes(query) || + r.snippet.includes(query) || + r.heading_path.includes(query) || + query.length > 1 + ) + return { results: filtered, total: filtered.length, mode } +} diff --git a/frontend/src/services/skillService.ts b/frontend/src/services/skillService.ts new file mode 100644 index 0000000..a2f61a7 --- /dev/null +++ b/frontend/src/services/skillService.ts @@ -0,0 +1,104 @@ +import apiClient from './apiClient' +import type { Skill } from '@/contracts' + +export async function listSkills(): Promise { + try { + return await apiClient.get('/api/skills') + } catch { + return mockSkills + } +} + +export async function getSkill(skillId: string): Promise { + return apiClient.get(`/api/skills/${skillId}`) +} + +export async function installSkill(skillId: string): Promise { + return apiClient.post('/api/skills/install', { skill_id: skillId }) +} + +export async function enableSkill(skillId: string): Promise { + return apiClient.post(`/api/skills/${skillId}/enable`) +} + +export async function disableSkill(skillId: string): Promise { + return apiClient.post(`/api/skills/${skillId}/disable`) +} + +export async function uninstallSkill(skillId: string): Promise { + return apiClient.delete(`/api/skills/${skillId}`) +} + +export const mockSkills: Skill[] = [ + { + skill_id: 'exam-review', + name: '期末复习助手', + version: '1.0.0', + description: '根据课程笔记生成复习要点和练习题,帮助高效备考', + icon: '📚', + author: '知笔知己团队', + permissions: ['notes.search', 'notes.read', 'tasks.create'], + tools: ['notes.search', 'notes.read', 'tasks.create'], + retrieval_config: { top_k: 10, rerank: true, citation: true }, + model_requirements: { capabilities: ['chat', 'tool_calling'] }, + status: 'ready', + enabled: true, + }, + { + skill_id: 'meeting-summary', + name: '会议纪要生成', + version: '1.1.0', + description: '从音频或文本中提取会议要点、行动项和待办任务', + icon: '📝', + author: '知笔知己团队', + permissions: ['notes.search', 'notes.write', 'tasks.write', 'attachments.read'], + tools: ['notes.search', 'notes.create', 'tasks.create', 'attachments.read'], + retrieval_config: { top_k: 5, rerank: false, citation: true }, + model_requirements: { capabilities: ['chat', 'tool_calling', 'structured_output'] }, + status: 'ready', + enabled: true, + }, + { + skill_id: 'code-explainer', + name: '代码解读助手', + version: '0.9.0', + description: '分析代码片段,解释功能、复杂度和优化建议', + icon: '💻', + author: '社区贡献', + permissions: ['notes.search', 'notes.read'], + tools: ['notes.search', 'notes.read', 'rag.search'], + retrieval_config: { top_k: 8, rerank: true, citation: true }, + model_requirements: { capabilities: ['chat', 'tool_calling'] }, + status: 'installed', + enabled: false, + }, + { + skill_id: 'research-assistant', + name: '文献研究助手', + version: '1.2.0', + description: '自动整理文献笔记,生成研究综述和引用关系图', + icon: '🔬', + author: '社区贡献', + permissions: ['notes.search', 'notes.read', 'notes.write'], + tools: ['notes.search', 'notes.read', 'notes.create', 'rag.search'], + retrieval_config: { top_k: 15, rerank: true, citation: true }, + model_requirements: { capabilities: ['chat', 'tool_calling', 'reasoning'] }, + status: 'dependency_missing', + enabled: false, + missing_dependencies: ['文献引用插件', '知识图谱插件'], + }, + { + skill_id: 'language-tutor', + name: '语言学习助手', + version: '0.5.0', + description: '基于你的学习笔记生成语言练习和记忆卡片', + icon: '🌍', + author: '社区贡献', + permissions: ['notes.search', 'notes.read', 'tasks.create'], + tools: ['notes.search', 'notes.read', 'tasks.create'], + retrieval_config: { top_k: 6, rerank: false, citation: false }, + model_requirements: { capabilities: ['chat'] }, + status: 'ready', + enabled: true, + }, +] diff --git a/frontend/src/services/sseClient.ts b/frontend/src/services/sseClient.ts new file mode 100644 index 0000000..d5341ee --- /dev/null +++ b/frontend/src/services/sseClient.ts @@ -0,0 +1,114 @@ +export type SseEventHandler = (event: string, data: Record) => void + +export interface SseClientOptions { + url: string + method?: string + body?: unknown + token?: string + onEvent?: SseEventHandler + onError?: (error: Error) => void + onOpen?: () => void + onDone?: () => void +} + +export class SseClient { + private controller: AbortController + private reader: ReadableStreamDefaultReader | null = null + private options: SseClientOptions + private buffer = '' + private connected = false + + constructor(options: SseClientOptions) { + this.options = options + this.controller = new AbortController() + } + + async connect() { + const { url, method = 'POST', body, token, onEvent, onError, onOpen, onDone } = this.options + + try { + const headers: Record = { + Accept: 'text/event-stream', + } + if (body !== undefined) { + headers['Content-Type'] = 'application/json' + } + if (token) { + headers['Authorization'] = `Bearer ${token}` + } + + const resp = await fetch(url, { + method, + headers, + body: body !== undefined ? JSON.stringify(body) : undefined, + signal: this.controller.signal, + }) + + if (!resp.ok || !resp.body) { + throw new Error(`SSE connection failed: ${resp.status}`) + } + + this.reader = resp.body.getReader() + this.connected = true + onOpen?.() + + const decoder = new TextDecoder('utf-8') + + while (true) { + const { value, done } = await this.reader.read() + if (done) break + + this.buffer += decoder.decode(value, { stream: true }) + + const lines = this.buffer.split('\n') + this.buffer = lines.pop() || '' + + let eventName = 'message' + let dataStr = '' + + for (const line of lines) { + const trimmed = line.trim() + if (!trimmed) { + if (dataStr) { + try { + const data = JSON.parse(dataStr) + onEvent?.(eventName, data) + if (eventName === 'Done' || eventName === 'RunCompleted' || eventName === 'RunFailed' || eventName === 'RunCancelled') { + onDone?.() + } + } catch { + /* ignore malformed json */ + } + eventName = 'message' + dataStr = '' + } + continue + } + + if (trimmed.startsWith('event:')) { + eventName = trimmed.slice(6).trim() + } else if (trimmed.startsWith('data:')) { + const d = trimmed.slice(5).trim() + dataStr += dataStr ? '\n' + d : d + } + } + } + } catch (e) { + if ((e as Error).name === 'AbortError') return + onError?.(e as Error) + } finally { + this.connected = false + this.reader = null + } + } + + cancel() { + this.controller.abort() + } + + isConnected() { + return this.connected + } +} + +export default SseClient diff --git a/frontend/src/services/systemService.ts b/frontend/src/services/systemService.ts new file mode 100644 index 0000000..d7c896d --- /dev/null +++ b/frontend/src/services/systemService.ts @@ -0,0 +1,23 @@ +import apiClient from './apiClient' +import type { SystemStatus } from '@/contracts' + +export async function healthCheck(): Promise<{ status: string }> { + try { + return await apiClient.get<{ status: string }>('/health') + } catch { + return { status: 'unavailable' } + } +} + +export async function getStatus(): Promise { + try { + return await apiClient.get('/api/status') + } catch { + return { + name: 'notes-agent', + version: '0.1.0', + environment: import.meta.env.DEV ? 'development' : 'production', + ai_core_available: false, + } + } +} diff --git a/frontend/src/services/taskService.ts b/frontend/src/services/taskService.ts new file mode 100644 index 0000000..478e8d6 --- /dev/null +++ b/frontend/src/services/taskService.ts @@ -0,0 +1,105 @@ +import apiClient from './apiClient' +import type { TaskItem, TaskStatus, TaskPriority } from '@/contracts' + +export async function listTasks(params?: { + status?: TaskStatus + priority?: TaskPriority + source?: 'user' | 'note' | 'agent' + limit?: number + offset?: number +}): Promise<{ items: TaskItem[]; total: number }> { + try { + return await apiClient.get('/api/tasks', { params }) + } catch { + return { items: mockTasks, total: mockTasks.length } + } +} + +export async function getTask(taskId: string): Promise { + return apiClient.get(`/api/tasks/${taskId}`) +} + +export async function createTask(data: { + title: string + description?: string + priority?: TaskPriority + due_date?: string + note_id?: string +}): Promise { + return apiClient.post('/api/tasks', data) +} + +export async function updateTask( + taskId: string, + data: Partial> +): Promise { + return apiClient.patch(`/api/tasks/${taskId}`, data) +} + +export async function deleteTask(taskId: string): Promise { + return apiClient.delete(`/api/tasks/${taskId}`) +} + +export const mockTasks: TaskItem[] = [ + { + task_id: 't-1', + title: '完成红黑树章节复习', + description: '整理插入、删除操作的所有情况,准备期末复习', + status: 'todo', + priority: 'high', + due_date: '2026-08-30T23:59:00Z', + note_id: 'n-rbt', + note_title: '红黑树', + source: 'user', + created_at: '2026-08-20T10:00:00Z', + updated_at: '2026-08-25T14:30:00Z', + }, + { + task_id: 't-2', + title: '理解死锁的银行家算法', + description: '推导银行家算法的安全性检查过程', + status: 'in_progress', + priority: 'medium', + note_id: 'n-deadlock', + note_title: '死锁', + source: 'agent', + created_at: '2026-08-22T09:00:00Z', + updated_at: '2026-08-24T16:00:00Z', + }, + { + task_id: 't-3', + title: 'TCP 三次握手与四次挥手', + description: '', + status: 'done', + priority: 'high', + note_id: 'n-tcp', + note_title: 'TCP_IP', + source: 'user', + created_at: '2026-08-15T08:00:00Z', + updated_at: '2026-08-18T20:00:00Z', + }, + { + task_id: 't-4', + title: 'HTTP 状态码整理', + description: '整理常见 HTTP 状态码及含义', + status: 'todo', + priority: 'low', + note_id: 'n-http', + note_title: 'HTTP协议', + source: 'note', + created_at: '2026-08-10T10:00:00Z', + updated_at: '2026-08-10T10:00:00Z', + }, + { + task_id: 't-5', + title: '链表操作实现练习', + description: '实现单链表和双向链表的基本操作', + status: 'todo', + priority: 'medium', + note_id: 'n-slist', + note_title: '单链表', + source: 'agent', + created_at: '2026-08-23T11:00:00Z', + updated_at: '2026-08-23T11:00:00Z', + }, +] diff --git a/frontend/src/services/workspaceService.ts b/frontend/src/services/workspaceService.ts new file mode 100644 index 0000000..1a8a032 --- /dev/null +++ b/frontend/src/services/workspaceService.ts @@ -0,0 +1,233 @@ +import type { FileNode } from '@/contracts' + +// Mock workspace service for web dev mode +// In Tauri environment this will use Tauri IPC commands + +export interface VaultInfo { + path: string + name: string +} + +const MOCK_VAULTS: VaultInfo[] = [ + { path: '/Users/demo/Documents/MyVault', name: '我的知识库' }, + { path: '/Users/demo/Documents/StudyNotes', name: '学习笔记' }, +] + +const MOCK_FILE_TREE: FileNode[] = [ + { + id: 'f-data', + name: '数据结构', + path: '/数据结构', + type: 'folder', + is_open: true, + children: [ + { id: 'n-rbt', name: '红黑树.md', path: '/数据结构/红黑树.md', type: 'file' }, + { id: 'n-bst', name: '二叉搜索树.md', path: '/数据结构/二叉搜索树.md', type: 'file' }, + { + id: 'f-list', + name: '链表', + path: '/数据结构/链表', + type: 'folder', + is_open: false, + children: [ + { id: 'n-slist', name: '单链表.md', path: '/数据结构/链表/单链表.md', type: 'file' }, + { id: 'n-dlist', name: '双向链表.md', path: '/数据结构/链表/双向链表.md', type: 'file' }, + ], + }, + ], + }, + { + id: 'f-os', + name: '操作系统', + path: '/操作系统', + type: 'folder', + is_open: false, + children: [ + { id: 'n-deadlock', name: '死锁.md', path: '/操作系统/死锁.md', type: 'file' }, + { id: 'n-sched', name: '进程调度.md', path: '/操作系统/进程调度.md', type: 'file' }, + ], + }, + { + id: 'f-net', + name: '计算机网络', + path: '/计算机网络', + type: 'folder', + is_open: false, + children: [ + { id: 'n-tcp', name: 'TCP_IP.md', path: '/计算机网络/TCP_IP.md', type: 'file' }, + { id: 'n-http', name: 'HTTP协议.md', path: '/计算机网络/HTTP协议.md', type: 'file' }, + ], + }, + { id: 'n-welcome', name: '欢迎使用知笔知己.md', path: '/欢迎使用知笔知己.md', type: 'file' }, +] + +export function getRecentVaults(): Promise { + return Promise.resolve(MOCK_VAULTS) +} + +export function openVault(path: string): Promise { + const name = path.split(/[/\\]/).filter(Boolean).pop() || 'Vault' + return Promise.resolve({ path, name }) +} + +export function createVault(path: string, name: string): Promise { + return Promise.resolve({ path, name }) +} + +export function getFileTree(): Promise { + return Promise.resolve(JSON.parse(JSON.stringify(MOCK_FILE_TREE))) +} + +export function readFileContent(filePath: string): Promise { + const name = filePath.split('/').pop() || 'Untitled' + if (name === '欢迎使用知笔知己.md') { + return Promise.resolve(`# 欢迎使用知笔知己 + +这是一款本地优先的 AI 笔记软件,支持 Markdown 编辑、智能检索、RAG 问答和 Agent 助手。 + +## 核心特性 + +- **本地优先**:所有笔记以 Markdown 格式保存在本地,数据完全由你掌控 +- **混合检索**:FTS5 全文检索 + 向量语义检索,精准定位知识 +- **AI 问答**:基于 RAG 技术,让 AI 基于你的笔记回答问题 +- **Agent 助手**:通过工具调用,AI 可以帮你管理笔记、创建任务 +- **Skill 系统**:将常用 AI 工作流保存为可复用的 Skill +- **插件扩展**:通过 Plugin 扩展应用能力 + +## 快速开始 + +1. 在左侧文件树中创建你的第一篇笔记 +2. 使用 \`Ctrl+P\` 打开命令面板 +3. 使用搜索功能快速找到你的笔记 +4. 打开 AI 对话,开始与你的知识对话 + +> 提示:你可以在设置中配置你的模型提供商,开始使用 AI 功能。 + +## 编辑器模式 + +- **所见即所得模式**:使用 Milkdown 提供流畅的 Markdown 编辑体验 +- **源码模式**:使用 CodeMirror 6 编辑原始 Markdown 源码 + +点击右上角按钮可以切换编辑模式。 + +## 代码示例 + +\`\`\`python +def quick_sort(arr): + if len(arr) <= 1: + return arr + pivot = arr[len(arr) // 2] + left = [x for x in arr if x < pivot] + middle = [x for x in arr if x == pivot] + right = [x for x in arr if x > pivot] + return quick_sort(left) + middle + quick_sort(right) +\`\`\` + +## 任务列表 + +- [x] 完成项目初始化 +- [x] 设计技术架构 +- [ ] 实现前端界面 +- [ ] 接入后端 AI Core +- [ ] 性能优化与测试 + +--- + +祝你写作愉快! +`) + } + if (name === '红黑树.md') { + return Promise.resolve(`# 红黑树 + +红黑树(Red-Black Tree)是一种自平衡二叉搜索树,每个节点带有颜色属性(红色或黑色)。 + +## 性质 + +1. 每个节点是红色或黑色 +2. 根节点是黑色 +3. 所有叶子节点(NIL)是黑色 +4. 如果一个节点是红色,则它的两个子节点都是黑色 +5. 从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点 + +这些性质确保了红黑树的关键特性:**从根到叶子的最长可能路径不会超过最短可能路径的两倍长**。 + +## 插入操作 + +插入后可能破坏红黑性质,需要通过变色和旋转来修复。 + +### 情况1:叔叔节点是红色 + +将父节点和叔叔节点设为黑色,将祖父节点设为红色,当前节点上移到祖父节点,继续向上调整。 + +### 情况2:叔叔节点是黑色,且当前节点是右孩子 + +以父节点为支点左旋,将当前节点转换为左孩子,进入情况3。 + +### 情况3:叔叔节点是黑色,且当前节点是左孩子 + +以祖父节点为支点右旋,将父节点设为黑色,祖父节点设为红色。 + +## 与 AVL 树对比 + +| 特性 | AVL 树 | 红黑树 | +|------|--------|--------| +| 平衡严格度 | 高度差 ≤ 1 | 黑色高度相同 | +| 查找速度 | 更快 | 略慢 | +| 插入删除 | 旋转更多 | 旋转更少 | +| 适用场景 | 读多写少 | 读写均衡 | + +## 应用场景 + +- C++ STL 的 map/set +- Java 的 TreeMap +- Linux 内核的完全公平调度器 +`) + } + return Promise.resolve(`# ${name.replace('.md', '')} + +这是一篇示例笔记。 + +## 第一部分 + +这里是笔记的内容。 + +## 第二部分 + +更多内容... + +> 引用内容示例 + +\`\`\`javascript +console.log('Hello, Notes Agent!'); +\`\`\` +`) +} + +export function saveFileContent(filePath: string, content: string): Promise { + console.debug(`[workspaceService] Save ${filePath}, ${content.length} chars`) + return Promise.resolve() +} + +export function createFile(folderPath: string, name: string, content = ''): Promise { + const path = `${folderPath}/${name}` + const id = `n-${Date.now()}` + return Promise.resolve({ id, name, path, type: 'file' }) +} + +export function createFolder(parentPath: string, name: string): Promise { + const path = `${parentPath}/${name}` + const id = `f-${Date.now()}` + return Promise.resolve({ id, name, path, type: 'folder', is_open: true, children: [] }) +} + +export function renameFile(oldPath: string, newName: string): Promise { + return Promise.resolve() +} + +export function deleteFile(path: string): Promise { + return Promise.resolve() +} + +export function moveFile(sourcePath: string, targetPath: string): Promise { + return Promise.resolve() +} diff --git a/frontend/src/stores/agent.ts b/frontend/src/stores/agent.ts new file mode 100644 index 0000000..659a01f --- /dev/null +++ b/frontend/src/stores/agent.ts @@ -0,0 +1,145 @@ +import { defineStore } from 'pinia' +import { ref, computed } from 'vue' +import type { AgentRun, AgentEvent, ToolDefinition, PermissionRequest, ToolCall } from '@/contracts' +import { mockAgentRuns, mockAgentEvents, mockTools, mockPermissionRequest } from '@/services/agentService' +import * as agentService from '@/services/agentService' + +export const useAgentStore = defineStore('agent', () => { + const runs = ref(mockAgentRuns) + const activeRunId = ref('run-1') + const events = ref(mockAgentEvents.filter((e) => e.run_id === 'run-1')) + const tools = ref(mockTools) + const isCreating = ref(false) + const isRunning = ref(false) + const permissionRequest = ref(null) + const toolCalls = ref([]) + + const activeRun = computed(() => + runs.value.find((r) => r.run_id === activeRunId.value) || null + ) + + const sortedRuns = computed(() => + [...runs.value].sort((a, b) => (b.started_at || '').localeCompare(a.started_at || '')) + ) + + const currentStep = computed(() => { + const tc = events.value.filter((e) => e.event === 'ToolCall').length + return tc + }) + + async function loadTools() { + tools.value = await agentService.listTools() + } + + async function loadRuns() { + const resp = await agentService.listAgentRuns() + runs.value = resp.items + } + + async function loadRun(runId: string) { + activeRunId.value = runId + events.value = mockAgentEvents.filter((e) => e.run_id === runId) + toolCalls.value = [] + for (const evt of events.value) { + if (evt.event === 'ToolCall') { + const data = evt.data as any + toolCalls.value.push({ + tool_call_id: data.tool_call_id, + name: data.name, + parameters: data.parameters, + status: data.status || 'completed', + started_at: evt.timestamp, + }) + } else if (evt.event === 'ToolResult') { + const data = evt.data as any + const tc = toolCalls.value.find((t) => t.tool_call_id === data.tool_call_id) + if (tc) { + tc.status = data.status + tc.result = data.result + tc.completed_at = evt.timestamp + } + } + } + } + + async function createRun(request: agentService.CreateAgentRunRequest) { + isCreating.value = true + try { + const run = await agentService.createAgentRun(request) + runs.value.unshift(run) + activeRunId.value = run.run_id + events.value = [{ + event: 'RunStarted', + sequence: 1, + run_id: run.run_id, + data: { task: request.task }, + timestamp: new Date().toISOString(), + }] + isRunning.value = true + // Mock events streaming + simulateRun(run.run_id) + return run + } finally { + isCreating.value = false + } + } + + function simulateRun(runId: string) { + const runEvents: AgentEvent[] = [ + { event: 'ThinkingDelta', sequence: 2, run_id: runId, data: { text: '我需要先搜索相关笔记...' }, timestamp: new Date().toISOString() }, + { event: 'ToolCall', sequence: 3, run_id: runId, data: { tool_call_id: 'tc-mock-1', name: 'notes.search', parameters: { query: '红黑树', limit: 5 }, status: 'running' }, timestamp: new Date().toISOString() }, + { event: 'ToolResult', sequence: 4, run_id: runId, data: { tool_call_id: 'tc-mock-1', name: 'notes.search', status: 'completed', result: '找到 5 条相关结果' }, timestamp: new Date().toISOString() }, + { event: 'TextDelta', sequence: 5, run_id: runId, data: { text: '根据你的笔记,以下是...' }, timestamp: new Date().toISOString() }, + { event: 'RunCompleted', sequence: 6, run_id: runId, data: { message: 'Task completed successfully' }, timestamp: new Date().toISOString() }, + ] + let idx = 0 + const push = () => { + if (idx >= runEvents.length) { + isRunning.value = false + return + } + events.value.push(runEvents[idx]) + idx++ + setTimeout(push, 800) + } + setTimeout(push, 500) + } + + async function cancelRun(runId: string) { + await agentService.cancelAgentRun(runId) + const run = runs.value.find((r) => r.run_id === runId) + if (run) run.status = 'cancelled' + isRunning.value = false + } + + async function respondPermission(decision: 'allow' | 'deny', scope: 'once' | 'session' | 'always' = 'once') { + if (!activeRunId.value || !permissionRequest.value) return + await agentService.respondToPermission(activeRunId.value, permissionRequest.value.request_id, decision, scope) + permissionRequest.value = null + } + + function showPermissionDemo() { + permissionRequest.value = mockPermissionRequest + } + + return { + runs, + activeRunId, + activeRun, + sortedRuns, + events, + tools, + isCreating, + isRunning, + permissionRequest, + toolCalls, + currentStep, + loadTools, + loadRuns, + loadRun, + createRun, + cancelRun, + respondPermission, + showPermissionDemo, + } +}) diff --git a/frontend/src/stores/chat.ts b/frontend/src/stores/chat.ts new file mode 100644 index 0000000..8af2e7c --- /dev/null +++ b/frontend/src/stores/chat.ts @@ -0,0 +1,147 @@ +import { defineStore } from 'pinia' +import { ref, computed } from 'vue' +import type { ChatMessage, Conversation, Citation } from '@/contracts' +import { mockConversations, mockMessages } from '@/services/chatService' +import type { SseClient } from '@/services/sseClient' + +export const useChatStore = defineStore('chat', () => { + const conversations = ref(mockConversations) + const activeConversationId = ref('conv-1') + const messages = ref(mockMessages['conv-1'] || []) + const isStreaming = ref(false) + const inputText = ref('') + const useRag = ref(true) + const selectedSkillId = ref(null) + const selectedProviderId = ref('mock-provider') + const selectedModel = ref('mock-1') + let sseClient: SseClient | null = null + + const activeConversation = computed(() => + conversations.value.find((c) => c.conversation_id === activeConversationId.value) || null + ) + + const sortedConversations = computed(() => + [...conversations.value].sort((a, b) => b.updated_at.localeCompare(a.updated_at)) + ) + + async function setActiveConversation(id: string) { + activeConversationId.value = id + messages.value = mockMessages[id] || [] + } + + async function sendMessage(text: string) { + if (!text.trim() || isStreaming.value) return + const conversationId = activeConversationId.value || `conv-${Date.now()}` + + if (!activeConversationId.value) { + const newConv: Conversation = { + conversation_id, + title: text.slice(0, 30), + created_at: new Date().toISOString(), + updated_at: new Date().toISOString(), + message_count: 0, + } + conversations.value.unshift(newConv) + activeConversationId.value = conversationId + } + + const userMsg: ChatMessage = { + message_id: `msg-${Date.now()}`, + conversation_id: conversationId, + role: 'user', + content: text, + created_at: new Date().toISOString(), + } + messages.value.push(userMsg) + inputText.value = '' + isStreaming.value = true + + const aiMsg: ChatMessage = { + message_id: `msg-${Date.now() + 1}`, + conversation_id: conversationId, + role: 'assistant', + content: '', + created_at: new Date().toISOString(), + citations: [], + tool_calls: [], + } + messages.value.push(aiMsg) + + // Mock streaming + const fullText = + '这是一个模拟的 AI 回复。在实际环境中,这里会通过 SSE 接收后端 AI Core 的流式输出,基于 RAG 引擎和你的知识库生成回答,并附带来源引用。\n\n**要点总结:**\n1. 这是演示用的流式输出\n2. 实际会调用 ModelEvent SSE\n3. 支持 Citation、Tool Call 等事件\n\n你可以在设置中配置真实的模型 Provider 来启用完整功能。' + const citations: Citation[] = [ + { + note_id: 'n-rbt', + block_id: 'b1', + file_path: '/数据结构/红黑树.md', + heading_path: '数据结构 / 红黑树 / 概述', + content: '红黑树是一种自平衡二叉搜索树...', + }, + ] + + let i = 0 + const interval = setInterval(() => { + if (i >= fullText.length) { + clearInterval(interval) + isStreaming.value = false + aiMsg.citations = citations + return + } + const chunk = fullText.slice(i, i + 3) + aiMsg.content += chunk + i += 3 + }, 20) + } + + function stopGeneration() { + if (sseClient) { + sseClient.cancel() + sseClient = null + } + isStreaming.value = false + } + + function createNewConversation() { + const newConv: Conversation = { + conversation_id: `conv-${Date.now()}`, + title: '新对话', + created_at: new Date().toISOString(), + updated_at: new Date().toISOString(), + message_count: 0, + } + conversations.value.unshift(newConv) + activeConversationId.value = newConv.conversation_id + messages.value = [] + } + + function deleteConversation(id: string) { + const idx = conversations.value.findIndex((c) => c.conversation_id === id) + if (idx > -1) { + conversations.value.splice(idx, 1) + if (activeConversationId.value === id) { + activeConversationId.value = conversations.value[0]?.conversation_id || null + messages.value = conversations.value[0] ? mockMessages[conversations.value[0].conversation_id] || [] : [] + } + } + } + + return { + conversations, + activeConversationId, + activeConversation, + sortedConversations, + messages, + isStreaming, + inputText, + useRag, + selectedSkillId, + selectedProviderId, + selectedModel, + setActiveConversation, + sendMessage, + stopGeneration, + createNewConversation, + deleteConversation, + } +}) diff --git a/frontend/src/stores/editor.ts b/frontend/src/stores/editor.ts new file mode 100644 index 0000000..f8c6b86 --- /dev/null +++ b/frontend/src/stores/editor.ts @@ -0,0 +1,122 @@ +import { defineStore } from 'pinia' +import { ref, computed } from 'vue' +import type { SaveStatus } from '@/contracts' +import * as workspaceService from '@/services/workspaceService' + +export const useEditorStore = defineStore('editor', () => { + const mode = ref<'wysiwyg' | 'source'>('wysiwyg') + const content = ref('') + const saveStatus = ref('idle') + const lastSavedAt = ref(null) + const currentNoteId = ref(null) + const currentFilePath = ref(null) + const highlightBlockId = ref(null) + const cursorPosition = ref({ line: 0, column: 0 }) + + const wordCount = computed(() => { + const text = content.value.replace(/[#*`>\-_\[\]()!]/g, '') + return text.trim().length + }) + + const lineCount = computed(() => content.value.split('\n').length) + + function setMode(newMode: 'wysiwyg' | 'source') { + mode.value = newMode + } + + function toggleMode() { + mode.value = mode.value === 'wysiwyg' ? 'source' : 'wysiwyg' + } + + function updateContent(newContent: string) { + content.value = newContent + if (saveStatus.value === 'saved' || saveStatus.value === 'idle') { + saveStatus.value = 'dirty' + } + } + + let saveTimer: ReturnType | null = null + + function scheduleAutoSave(delay = 1500) { + if (saveTimer) clearTimeout(saveTimer) + saveTimer = setTimeout(() => { + void save() + }, delay) + } + + async function save() { + if (!currentFilePath.value) return + if (saveStatus.value === 'saving') return + saveStatus.value = 'saving' + try { + await workspaceService.saveFileContent(currentFilePath.value, content.value) + saveStatus.value = 'saved' + lastSavedAt.value = new Date().toISOString() + } catch { + saveStatus.value = 'save_failed' + } + } + + async function loadFile(filePath: string) { + currentFilePath.value = filePath + saveStatus.value = 'saving' + try { + content.value = await workspaceService.readFileContent(filePath) + saveStatus.value = 'saved' + lastSavedAt.value = new Date().toISOString() + } catch { + content.value = '' + saveStatus.value = 'idle' + } + highlightBlockId.value = null + } + + function highlightBlock(blockId: string) { + highlightBlockId.value = blockId + setTimeout(() => { + if (highlightBlockId.value === blockId) { + highlightBlockId.value = null + } + }, 3000) + } + + function setExternalChanged() { + if (saveStatus.value === 'dirty') { + saveStatus.value = 'conflict' + } else { + saveStatus.value = 'external_changed' + } + } + + function closeFile() { + if (saveTimer) clearTimeout(saveTimer) + currentFilePath.value = null + currentNoteId.value = null + content.value = '' + saveStatus.value = 'idle' + lastSavedAt.value = null + highlightBlockId.value = null + } + + return { + mode, + content, + saveStatus, + lastSavedAt, + currentNoteId, + currentFilePath, + highlightBlockId, + cursorPosition, + wordCount, + lineCount, + setMode, + toggleMode, + updateContent, + scheduleAutoSave, + save, + loadFile, + highlightBlock, + setExternalChanged, + closeFile, + } +}) diff --git a/frontend/src/stores/index.ts b/frontend/src/stores/index.ts new file mode 100644 index 0000000..8f3c834 --- /dev/null +++ b/frontend/src/stores/index.ts @@ -0,0 +1,11 @@ +export { useWorkspaceStore } from './workspace' +export { useEditorStore } from './editor' +export { useSearchStore } from './search' +export { useChatStore } from './chat' +export { useAgentStore } from './agent' +export { useSkillStore } from './skill' +export { usePluginStore } from './plugin' +export { useTaskStore } from './task' +export { useThemeStore } from './theme' +export { useProviderStore } from './provider' +export { useSettingsStore } from './settings' diff --git a/frontend/src/stores/plugin.ts b/frontend/src/stores/plugin.ts new file mode 100644 index 0000000..d1fd8e1 --- /dev/null +++ b/frontend/src/stores/plugin.ts @@ -0,0 +1,69 @@ +import { defineStore } from 'pinia' +import { ref, computed } from 'vue' +import type { Plugin } from '@/contracts' +import { mockPlugins } from '@/services/pluginService' + +export const usePluginStore = defineStore('plugin', () => { + const plugins = ref(mockPlugins) + const selectedPluginId = ref(null) + const isLoading = ref(false) + + const selectedPlugin = computed(() => + plugins.value.find((p) => p.plugin_id === selectedPluginId.value) || null + ) + + const enabledPlugins = computed(() => plugins.value.filter((p) => p.enabled)) + const readyPlugins = computed(() => plugins.value.filter((p) => p.status === 'ready')) + const errorPlugins = computed(() => plugins.value.filter((p) => p.status === 'error')) + + async function loadPlugins() { + isLoading.value = true + try { + const { listPlugins } = await import('@/services/pluginService') + plugins.value = await listPlugins() + } finally { + isLoading.value = false + } + } + + function selectPlugin(pluginId: string | null) { + selectedPluginId.value = pluginId + } + + async function enablePlugin(pluginId: string) { + const plugin = plugins.value.find((p) => p.plugin_id === pluginId) + if (plugin) { + plugin.enabled = true + plugin.status = 'ready' + } + } + + async function disablePlugin(pluginId: string) { + const plugin = plugins.value.find((p) => p.plugin_id === pluginId) + if (plugin) { + plugin.enabled = false + plugin.status = 'disabled' + } + } + + async function uninstallPlugin(pluginId: string) { + const idx = plugins.value.findIndex((p) => p.plugin_id === pluginId) + if (idx > -1) plugins.value.splice(idx, 1) + if (selectedPluginId.value === pluginId) selectedPluginId.value = null + } + + return { + plugins, + selectedPluginId, + selectedPlugin, + enabledPlugins, + readyPlugins, + errorPlugins, + isLoading, + loadPlugins, + selectPlugin, + enablePlugin, + disablePlugin, + uninstallPlugin, + } +}) diff --git a/frontend/src/stores/provider.ts b/frontend/src/stores/provider.ts new file mode 100644 index 0000000..1c8f614 --- /dev/null +++ b/frontend/src/stores/provider.ts @@ -0,0 +1,80 @@ +import { defineStore } from 'pinia' +import { ref, computed } from 'vue' +import type { ProviderConfig, ModelInfo } from '@/contracts' +import { mockProviders, mockModels } from '@/services/providerService' + +export const useProviderStore = defineStore('provider', () => { + const providers = ref(mockProviders) + const modelsByProvider = ref>(mockModels) + const defaultProviderId = ref('mock-provider') + const isLoading = ref(false) + + const enabledProviders = computed(() => providers.value.filter((p) => p.enabled)) + const defaultProvider = computed(() => + providers.value.find((p) => p.provider_id === defaultProviderId.value) || null + ) + + async function loadProviders() { + isLoading.value = true + try { + const { listProviders } = await import('@/services/providerService') + providers.value = await listProviders() + } finally { + isLoading.value = false + } + } + + async function loadModels(providerId: string) { + const { listModels } = await import('@/services/providerService') + modelsByProvider.value[providerId] = await listModels(providerId) + } + + async function addProvider(data: Omit & { api_key?: string }) { + const newProvider: ProviderConfig = { + ...data, + provider_id: `prov-${Date.now()}`, + } + providers.value.push(newProvider) + return newProvider + } + + async function updateProvider(providerId: string, data: Partial) { + const p = providers.value.find((p) => p.provider_id === providerId) + if (p) Object.assign(p, data) + } + + async function deleteProvider(providerId: string) { + const idx = providers.value.findIndex((p) => p.provider_id === providerId) + if (idx > -1) providers.value.splice(idx, 1) + delete modelsByProvider.value[providerId] + } + + async function testProvider(providerId: string): Promise<{ success: boolean; latency_ms?: number; error?: string }> { + await new Promise((r) => setTimeout(r, 1000)) + const p = providers.value.find((p) => p.provider_id === providerId) + if (p?.enabled && p.has_credential) { + return { success: true, latency_ms: 230 + Math.floor(Math.random() * 200) } + } + return { success: false, error: '认证失败,请检查 API Key' } + } + + function setDefaultProvider(providerId: string) { + defaultProviderId.value = providerId + } + + return { + providers, + modelsByProvider, + defaultProviderId, + enabledProviders, + defaultProvider, + isLoading, + loadProviders, + loadModels, + addProvider, + updateProvider, + deleteProvider, + testProvider, + setDefaultProvider, + } +}) diff --git a/frontend/src/stores/search.ts b/frontend/src/stores/search.ts new file mode 100644 index 0000000..9cb4d62 --- /dev/null +++ b/frontend/src/stores/search.ts @@ -0,0 +1,78 @@ +import { defineStore } from 'pinia' +import { ref } from 'vue' +import type { SearchResult, SearchRequest } from '@/contracts' +import * as searchService from '@/services/searchService' + +export const useSearchStore = defineStore('search', () => { + const query = ref('') + const mode = ref<'fts' | 'vector' | 'hybrid'>('hybrid') + const results = ref([]) + const total = ref(0) + const isSearching = ref(false) + const selectedIndex = ref(0) + const recentQueries = ref(['红黑树', '死锁', 'TCP三次握手']) + const error = ref(null) + const vectorUnavailable = ref(false) + + async function doSearch(request: SearchRequest) { + query.value = request.query + mode.value = request.mode || 'hybrid' + isSearching.value = true + error.value = null + + try { + const resp = await searchService.searchMock(request.query, request.mode || 'hybrid') + results.value = resp.results + total.value = resp.total + selectedIndex.value = 0 + } catch (e: any) { + error.value = e.message || '搜索失败' + results.value = [] + total.value = 0 + } finally { + isSearching.value = false + } + + if (request.query && !recentQueries.value.includes(request.query)) { + recentQueries.value.unshift(request.query) + if (recentQueries.value.length > 10) recentQueries.value.pop() + } + } + + function clearResults() { + results.value = [] + query.value = '' + total.value = 0 + selectedIndex.value = 0 + error.value = null + } + + function selectNext() { + if (selectedIndex.value < results.value.length - 1) selectedIndex.value++ + } + + function selectPrev() { + if (selectedIndex.value > 0) selectedIndex.value-- + } + + function setMode(m: 'fts' | 'vector' | 'hybrid') { + mode.value = m + } + + return { + query, + mode, + results, + total, + isSearching, + selectedIndex, + recentQueries, + error, + vectorUnavailable, + doSearch, + clearResults, + selectNext, + selectPrev, + setMode, + } +}) diff --git a/frontend/src/stores/settings.ts b/frontend/src/stores/settings.ts new file mode 100644 index 0000000..81743fb --- /dev/null +++ b/frontend/src/stores/settings.ts @@ -0,0 +1,93 @@ +import { defineStore } from 'pinia' +import { ref } from 'vue' +import type { AiCoreStatus, IndexStatus } from '@/contracts' +import { mockIndexStatus } from '@/services/indexService' + +export const useSettingsStore = defineStore('settings', () => { + // General + const restoreLastVault = ref(true) + const autoSaveInterval = ref(1500) + const language = ref<'zh-CN' | 'en'>('zh-CN') + const appVersion = ref('0.1.0') + const aiCoreVersion = ref('0.1.0') + + // Editor + const defaultEditorMode = ref<'wysiwyg' | 'source'>('wysiwyg') + const editorFontSize = ref(15) + const editorLineHeight = ref(1.7) + const editorLineWidth = ref(80) + const spellCheck = ref(false) + + // AI Core + const aiCoreStatus = ref('running') + const aiCoreAddress = ref('http://127.0.0.1:8000') + + // Index + const indexStatus = ref(mockIndexStatus) + + // Permissions + const permissionPolicy = ref>({ + 'notes.read': 'allow', + 'notes.search': 'allow', + 'notes.write': 'confirm', + 'notes.delete': 'confirm', + 'tasks.read': 'allow', + 'tasks.write': 'confirm', + 'attachments.read': 'confirm', + 'network.request': 'confirm', + 'secrets.use': 'confirm', + }) + + function setAutoSaveInterval(ms: number) { + autoSaveInterval.value = ms + } + + function setDefaultEditorMode(mode: 'wysiwyg' | 'source') { + defaultEditorMode.value = mode + } + + function setPermission(permission: string, policy: 'allow' | 'confirm' | 'deny') { + permissionPolicy.value[permission] = policy + } + + function setAiCoreStatus(status: AiCoreStatus) { + aiCoreStatus.value = status + } + + async function restartAiCore(): Promise { + aiCoreStatus.value = 'starting' + await new Promise((r) => setTimeout(r, 1500)) + aiCoreStatus.value = 'running' + return true + } + + async function rebuildIndex(scope: 'full' | 'fts' | 'vector' = 'full') { + indexStatus.value.status = 'indexing' + setTimeout(() => { + indexStatus.value.status = 'idle' + }, 3000) + } + + return { + restoreLastVault, + autoSaveInterval, + language, + appVersion, + aiCoreVersion, + defaultEditorMode, + editorFontSize, + editorLineHeight, + editorLineWidth, + spellCheck, + aiCoreStatus, + aiCoreAddress, + indexStatus, + permissionPolicy, + setAutoSaveInterval, + setDefaultEditorMode, + setPermission, + setAiCoreStatus, + restartAiCore, + rebuildIndex, + } +}) diff --git a/frontend/src/stores/skill.ts b/frontend/src/stores/skill.ts new file mode 100644 index 0000000..7269ead --- /dev/null +++ b/frontend/src/stores/skill.ts @@ -0,0 +1,69 @@ +import { defineStore } from 'pinia' +import { ref, computed } from 'vue' +import type { Skill } from '@/contracts' +import { mockSkills } from '@/services/skillService' + +export const useSkillStore = defineStore('skill', () => { + const skills = ref(mockSkills) + const selectedSkillId = ref(null) + const isLoading = ref(false) + + const selectedSkill = computed(() => + skills.value.find((s) => s.skill_id === selectedSkillId.value) || null + ) + + const enabledSkills = computed(() => skills.value.filter((s) => s.enabled)) + const installedSkills = computed(() => skills.value.filter((s) => s.status !== 'error')) + const readySkills = computed(() => skills.value.filter((s) => s.status === 'ready')) + + async function loadSkills() { + isLoading.value = true + try { + const { listSkills } = await import('@/services/skillService') + skills.value = await listSkills() + } finally { + isLoading.value = false + } + } + + function selectSkill(skillId: string | null) { + selectedSkillId.value = skillId + } + + async function enableSkill(skillId: string) { + const skill = skills.value.find((s) => s.skill_id === skillId) + if (skill) { + skill.enabled = true + skill.status = 'ready' + } + } + + async function disableSkill(skillId: string) { + const skill = skills.value.find((s) => s.skill_id === skillId) + if (skill) { + skill.enabled = false + skill.status = 'disabled' + } + } + + async function uninstallSkill(skillId: string) { + const idx = skills.value.findIndex((s) => s.skill_id === skillId) + if (idx > -1) skills.value.splice(idx, 1) + if (selectedSkillId.value === skillId) selectedSkillId.value = null + } + + return { + skills, + selectedSkillId, + selectedSkill, + enabledSkills, + installedSkills, + readySkills, + isLoading, + loadSkills, + selectSkill, + enableSkill, + disableSkill, + uninstallSkill, + } +}) diff --git a/frontend/src/stores/task.ts b/frontend/src/stores/task.ts new file mode 100644 index 0000000..8ed4140 --- /dev/null +++ b/frontend/src/stores/task.ts @@ -0,0 +1,89 @@ +import { defineStore } from 'pinia' +import { ref, computed } from 'vue' +import type { TaskItem, TaskStatus, TaskPriority, TaskSource } from '@/contracts' +import { mockTasks } from '@/services/taskService' + +export const useTaskStore = defineStore('task', () => { + const tasks = ref(mockTasks) + const filterStatus = ref('all') + const filterPriority = ref('all') + const filterSource = ref('all') + const isLoading = ref(false) + + const filteredTasks = computed(() => { + return tasks.value.filter((t) => { + if (filterStatus.value !== 'all' && t.status !== filterStatus.value) return false + if (filterPriority.value !== 'all' && t.priority !== filterPriority.value) return false + if (filterSource.value !== 'all' && t.source !== filterSource.value) return false + return true + }) + }) + + const todoTasks = computed(() => tasks.value.filter((t) => t.status === 'todo')) + const inProgressTasks = computed(() => tasks.value.filter((t) => t.status === 'in_progress')) + const doneTasks = computed(() => tasks.value.filter((t) => t.status === 'done')) + + async function loadTasks() { + isLoading.value = true + try { + const { listTasks } = await import('@/services/taskService') + const resp = await listTasks() + tasks.value = resp.items + } finally { + isLoading.value = false + } + } + + async function createTask(data: { title: string; description?: string; priority?: TaskPriority; due_date?: string; note_id?: string }) { + const newTask: TaskItem = { + task_id: `t-${Date.now()}`, + title: data.title, + description: data.description, + status: 'todo', + priority: data.priority || 'medium', + due_date: data.due_date, + note_id: data.note_id, + source: 'user', + created_at: new Date().toISOString(), + updated_at: new Date().toISOString(), + } + tasks.value.unshift(newTask) + return newTask + } + + async function updateTask(taskId: string, data: Partial>) { + const task = tasks.value.find((t) => t.task_id === taskId) + if (task) { + Object.assign(task, data) + task.updated_at = new Date().toISOString() + } + } + + async function deleteTask(taskId: string) { + const idx = tasks.value.findIndex((t) => t.task_id === taskId) + if (idx > -1) tasks.value.splice(idx, 1) + } + + function setFilterStatus(s: TaskStatus | 'all') { filterStatus.value = s } + function setFilterPriority(p: TaskPriority | 'all') { filterPriority.value = p } + function setFilterSource(s: TaskSource | 'all') { filterSource.value = s } + + return { + tasks, + filterStatus, + filterPriority, + filterSource, + filteredTasks, + todoTasks, + inProgressTasks, + doneTasks, + isLoading, + loadTasks, + createTask, + updateTask, + deleteTask, + setFilterStatus, + setFilterPriority, + setFilterSource, + } +}) diff --git a/frontend/src/stores/theme.ts b/frontend/src/stores/theme.ts new file mode 100644 index 0000000..940b5fd --- /dev/null +++ b/frontend/src/stores/theme.ts @@ -0,0 +1,81 @@ +import { defineStore } from 'pinia' +import { ref, computed, watch } from 'vue' +import type { ThemeConfig } from '@/contracts' + +const builtinThemes: ThemeConfig[] = [ + { theme_id: 'light', name: '浅色', version: '1.0.0', description: '默认浅色主题', is_dark: false, builtin: true }, + { theme_id: 'dark', name: '深色', version: '1.0.0', description: '默认深色主题', is_dark: true, builtin: true }, + { theme_id: 'sepia', name: '护眼', version: '1.0.0', description: '护眼暖色调', is_dark: false, builtin: true }, +] + +export const useThemeStore = defineStore('theme', () => { + const themes = ref(builtinThemes) + const currentThemeId = ref('light') + const fontEditorSize = ref(15) + const fontEditorFamily = ref('system-ui') + const lineHeight = ref(1.7) + + const currentTheme = computed(() => + themes.value.find((t) => t.theme_id === currentThemeId.value) || themes.value[0] + ) + + const isDark = computed(() => currentTheme.value?.is_dark || false) + + function applyTheme(themeId: string) { + const theme = themes.value.find((t) => t.theme_id === themeId) + if (!theme) return + currentThemeId.value = themeId + const root = document.documentElement + if (theme.is_dark) { + root.setAttribute('data-theme', 'dark') + } else if (themeId === 'sepia') { + root.setAttribute('data-theme', 'sepia') + } else { + root.setAttribute('data-theme', 'light') + } + localStorage.setItem('theme', themeId) + } + + function initTheme() { + const saved = localStorage.getItem('theme') + if (saved && themes.value.find((t) => t.theme_id === saved)) { + applyTheme(saved) + return + } + const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches + applyTheme(prefersDark ? 'dark' : 'light') + } + + function toggleTheme() { + applyTheme(isDark.value ? 'light' : 'dark') + } + + function resetToDefault() { + applyTheme('light') + fontEditorSize.value = 15 + fontEditorFamily.value = 'system-ui' + lineHeight.value = 1.7 + } + + watch(fontEditorSize, (v) => { + document.documentElement.style.setProperty('--font-editor-size', `${v}px`) + }) + + watch(lineHeight, (v) => { + document.documentElement.style.setProperty('--font-editor-line-height', String(v)) + }) + + return { + themes, + currentThemeId, + currentTheme, + isDark, + fontEditorSize, + fontEditorFamily, + lineHeight, + applyTheme, + initTheme, + toggleTheme, + resetToDefault, + } +}) diff --git a/frontend/src/stores/workspace.ts b/frontend/src/stores/workspace.ts new file mode 100644 index 0000000..56ae0db --- /dev/null +++ b/frontend/src/stores/workspace.ts @@ -0,0 +1,132 @@ +import { defineStore } from 'pinia' +import { ref, computed } from 'vue' +import type { FileNode } from '@/contracts' +import * as workspaceService from '@/services/workspaceService' + +export const useWorkspaceStore = defineStore('workspace', () => { + const vaultPath = ref('') + const vaultName = ref('') + const fileTree = ref([]) + const openFiles = ref([]) + const activeFilePath = ref(null) + const isLoading = ref(false) + const hasVault = ref(false) + const recentVaults = ref<{ path: string; name: string }[]>([]) + + const activeFile = computed(() => { + if (!activeFilePath.value) return null + return findNodeByPath(fileTree.value, activeFilePath.value) + }) + + function findNodeByPath(nodes: FileNode[], path: string): FileNode | null { + for (const node of nodes) { + if (node.path === path) return node + if (node.children) { + const found = findNodeByPath(node.children, path) + if (found) return found + } + } + return null + } + + function toggleFolder(path: string) { + const node = findNodeByPath(fileTree.value, path) + if (node && node.type === 'folder') { + node.is_open = !node.is_open + } + } + + function openFile(path: string) { + if (!openFiles.value.includes(path)) { + openFiles.value.push(path) + } + activeFilePath.value = path + } + + function closeFile(path: string) { + const idx = openFiles.value.indexOf(path) + if (idx > -1) { + openFiles.value.splice(idx, 1) + if (activeFilePath.value === path) { + activeFilePath.value = openFiles.value[Math.min(idx, openFiles.value.length - 1)] || null + } + } + } + + function setActiveFile(path: string | null) { + activeFilePath.value = path + } + + async function loadRecentVaults() { + recentVaults.value = await workspaceService.getRecentVaults() + } + + async function openVault(path: string) { + isLoading.value = true + try { + const info = await workspaceService.openVault(path) + vaultPath.value = info.path + vaultName.value = info.name + fileTree.value = await workspaceService.getFileTree() + hasVault.value = true + } finally { + isLoading.value = false + } + } + + async function createVault(path: string, name: string) { + isLoading.value = true + try { + const info = await workspaceService.createVault(path, name) + vaultPath.value = info.path + vaultName.value = info.name + fileTree.value = await workspaceService.getFileTree() + hasVault.value = true + } finally { + isLoading.value = false + } + } + + function addFileToTree(parentPath: string, file: FileNode) { + const parent = findNodeByPath(fileTree.value, parentPath) + if (parent?.children) { + parent.children.push(file) + parent.is_open = true + } + } + + function removeFromTree(path: string) { + function remove(nodes: FileNode[]): boolean { + for (let i = 0; i < nodes.length; i++) { + if (nodes[i].path === path) { + nodes.splice(i, 1) + return true + } + if (nodes[i].children && remove(nodes[i].children!)) return true + } + return false + } + remove(fileTree.value) + } + + return { + vaultPath, + vaultName, + fileTree, + openFiles, + activeFilePath, + activeFile, + isLoading, + hasVault, + recentVaults, + toggleFolder, + openFile, + closeFile, + setActiveFile, + loadRecentVaults, + openVault, + createVault, + addFileToTree, + removeFromTree, + } +}) diff --git a/frontend/src/styles/tokens.css b/frontend/src/styles/tokens.css new file mode 100644 index 0000000..368ac80 --- /dev/null +++ b/frontend/src/styles/tokens.css @@ -0,0 +1,247 @@ +:root { + /* Background */ + --color-background-primary: #ffffff; + --color-background-secondary: #f7f8fa; + --color-background-tertiary: #eef0f3; + --color-background-hover: #f0f2f5; + --color-background-active: #e4e7eb; + --color-background-overlay: rgba(0, 0, 0, 0.45); + + /* Surface */ + --color-surface-primary: #ffffff; + --color-surface-secondary: #fafbfc; + --color-surface-elevated: #ffffff; + + /* Text */ + --color-text-primary: #1f2328; + --color-text-secondary: #656d76; + --color-text-tertiary: #9198a0; + --color-text-inverse: #ffffff; + --color-text-link: #5b67f1; + --color-text-disabled: #b0b4ba; + + /* Accent */ + --color-accent-primary: #5b67f1; + --color-accent-primary-hover: #4a55e0; + --color-accent-primary-active: #3d47cc; + --color-accent-secondary: #8b94f5; + --color-accent-soft: #eef0ff; + --color-accent-soft-hover: #e2e5ff; + + /* Status */ + --color-success: #2da44e; + --color-success-soft: #dafbe3; + --color-warning: #d4a72c; + --color-warning-soft: #fff5c2; + --color-error: #cf222e; + --color-error-soft: #ffebe9; + --color-info: #0969da; + --color-info-soft: #ddf4ff; + + /* Border */ + --color-border-default: #e4e7eb; + --color-border-subtle: #eef0f3; + --color-border-focus: #5b67f1; + --color-border-disabled: #eef0f3; + + /* Shadow */ + --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04); + --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08); + --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.12); + --shadow-xl: 0 16px 48px rgba(0, 0, 0, 0.16); + + /* Radius */ + --radius-sm: 4px; + --radius-md: 6px; + --radius-lg: 10px; + --radius-xl: 14px; + --radius-full: 9999px; + + /* Spacing */ + --space-xs: 4px; + --space-sm: 8px; + --space-md: 12px; + --space-lg: 16px; + --space-xl: 20px; + --space-2xl: 28px; + --space-3xl: 36px; + + /* Typography - UI */ + --font-ui-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', 'PingFang SC', + 'Hiragino Sans GB', 'Microsoft YaHei', Helvetica, Arial, sans-serif; + --font-ui-mono: 'JetBrains Mono', 'Fira Code', 'SF Mono', Consolas, 'Cascadia Code', monospace; + + /* Typography - Editor */ + --font-editor-sans: var(--font-ui-sans); + --font-editor-mono: var(--font-ui-mono); + --font-editor-size: 15px; + --font-editor-line-height: 1.7; + + /* Font sizes */ + --font-size-xs: 12px; + --font-size-sm: 13px; + --font-size-md: 14px; + --font-size-lg: 15px; + --font-size-xl: 17px; + --font-size-2xl: 20px; + --font-size-3xl: 26px; + + /* Line heights */ + --line-height-tight: 1.25; + --line-height-normal: 1.5; + --line-height-relaxed: 1.7; + + /* Z-index */ + --z-sidebar: 10; + --z-dropdown: 100; + --z-modal: 200; + --z-tooltip: 300; + --z-notification: 400; + --z-titlebar: 500; + + /* Motion */ + --motion-fast: 120ms cubic-bezier(0.4, 0, 0.2, 1); + --motion-normal: 200ms cubic-bezier(0.4, 0, 0.2, 1); + --motion-slow: 300ms cubic-bezier(0.4, 0, 0.2, 1); + + /* Layout */ + --titlebar-height: 38px; + --sidebar-primary-width: 52px; + --sidebar-primary-width-expanded: 180px; + --sidebar-secondary-width: 260px; + --statusbar-height: 26px; +} + +[data-theme='dark'] { + --color-background-primary: #0d1117; + --color-background-secondary: #161b22; + --color-background-tertiary: #21262d; + --color-background-hover: #1f2630; + --color-background-active: #2d333b; + --color-background-overlay: rgba(0, 0, 0, 0.65); + + --color-surface-primary: #161b22; + --color-surface-secondary: #0d1117; + --color-surface-elevated: #1c2128; + + --color-text-primary: #e6edf3; + --color-text-secondary: #8b949e; + --color-text-tertiary: #6e7681; + --color-text-inverse: #0d1117; + --color-text-link: #7d8bff; + --color-text-disabled: #484f58; + + --color-accent-primary: #7d8bff; + --color-accent-primary-hover: #909cff; + --color-accent-primary-active: #a8b2ff; + --color-accent-secondary: #5b67f1; + --color-accent-soft: #1e2352; + --color-accent-soft-hover: #2a3066; + + --color-success: #3fb950; + --color-success-soft: #033a16; + --color-warning: #d29922; + --color-warning-soft: #4d3a00; + --color-error: #f85149; + --color-error-soft: #5c1318; + --color-info: #58a6ff; + --color-info-soft: #051d4d; + + --color-border-default: #30363d; + --color-border-subtle: #21262d; + --color-border-focus: #7d8bff; + --color-border-disabled: #21262d; + + --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3); + --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4); + --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.5); + --shadow-xl: 0 16px 48px rgba(0, 0, 0, 0.6); +} + +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +html, +body, +#app { + height: 100%; + width: 100%; + overflow: hidden; +} + +body { + font-family: var(--font-ui-sans); + font-size: var(--font-size-md); + line-height: var(--line-height-normal); + color: var(--color-text-primary); + background-color: var(--color-background-primary); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + user-select: none; +} + +a { + color: var(--color-text-link); + text-decoration: none; + + &:hover { + text-decoration: underline; + } +} + +button { + font-family: inherit; + font-size: inherit; + cursor: pointer; + border: none; + background: none; + color: inherit; +} + +input, +textarea, +select { + font-family: inherit; + font-size: inherit; + color: inherit; +} + +ul, +ol { + list-style: none; +} + +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: transparent; +} + +::-webkit-scrollbar-thumb { + background: var(--color-border-default); + border-radius: var(--radius-full); + + &:hover { + background: var(--color-text-tertiary); + } +} + +::-webkit-scrollbar-corner { + background: transparent; +} + +::selection { + background: var(--color-accent-soft); + color: var(--color-accent-primary); +} + +[data-theme='dark'] ::selection { + background: var(--color-accent-primary); + color: var(--color-text-inverse); +} diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index baaeb98..ee63575 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,8 +1,14 @@ import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' +import path from 'node:path' export default defineConfig({ plugins: [vue()], + resolve: { + alias: { + '@': path.resolve(__dirname, 'src'), + }, + }, server: { host: '127.0.0.1', port: 5173,