diff --git a/.storybook/main.ts b/.storybook/main.ts index 897094adedf..af23c6db3f3 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -7,7 +7,7 @@ import type { InlineConfig } from 'vite' const config: StorybookConfig = { stories: ['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'], - addons: ['@storybook/addon-docs'], + addons: ['@storybook/addon-docs', '@storybook/addon-mcp'], framework: { name: '@storybook/vue3-vite', options: {} diff --git a/AGENTS.md b/AGENTS.md index ca0985a7efa..b68246d4fd8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -122,7 +122,10 @@ The project uses **Nx** for build orchestration and task management - Prefer reactive props destructuring to `const props = defineProps<...>` - Do not use `withDefaults` or runtime props declaration - Do not import Vue macros unnecessarily - - Prefer `useModel` to separately defining a prop and emit + - Prefer `defineModel` to separately defining a prop and emit for v-model bindings + - Define slots via template usage, not `defineSlots` + - Use same-name shorthand for slot prop bindings: `:isExpanded` instead of `:is-expanded="isExpanded"` + - Derive component types using `vue-component-type-helpers` (`ComponentProps`, `ComponentSlots`) instead of separate type files - Be judicious with addition of new refs or other state - If it's possible to accomplish the design goals with just a prop, don't add a `ref` - If it's possible to use the `ref` or prop directly, don't add a `computed` @@ -271,6 +274,8 @@ When referencing Comfy-Org repos: - Use `cn()` inline in the template when feasible instead of creating a `computed` to hold the value - NEVER use `!important` or the `!` important prefix for tailwind classes - Find existing `!important` classes that are interfering with the styling and propose corrections of those instead. +- NEVER use arbitrary percentage values like `w-[80%]` when a Tailwind fraction utility exists + - Use `w-4/5` instead of `w-[80%]`, `w-1/2` instead of `w-[50%]`, etc. ## Agent-only rules diff --git a/package.json b/package.json index cc2872d024a..2fb75821a7d 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "@prettier/plugin-oxc": "catalog:", "@sentry/vite-plugin": "catalog:", "@storybook/addon-docs": "catalog:", + "@storybook/addon-mcp": "catalog:", "@storybook/vue3": "catalog:", "@storybook/vue3-vite": "catalog:", "@tailwindcss/vite": "catalog:", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2188bf0e4e7..1db0c2c10c8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,7 +44,7 @@ catalogs: version: 22.2.6 '@pinia/testing': specifier: ^0.1.5 - version: 0.1.5 + version: 0.1.7 '@playwright/test': specifier: ^1.57.0 version: 1.57.0 @@ -77,13 +77,16 @@ catalogs: version: 4.6.0 '@sentry/vue': specifier: ^8.48.0 - version: 8.48.0 + version: 8.55.0 '@sparkjsdev/spark': specifier: ^0.1.10 version: 0.1.10 '@storybook/addon-docs': specifier: ^10.1.9 version: 10.1.9 + '@storybook/addon-mcp': + specifier: 0.1.6 + version: 0.1.6 '@storybook/vue3': specifier: ^10.1.9 version: 10.1.9 @@ -179,7 +182,7 @@ catalogs: version: 15.15.0 happy-dom: specifier: ^15.11.0 - version: 15.11.0 + version: 15.11.7 husky: specifier: ^9.1.7 version: 9.1.7 @@ -293,7 +296,7 @@ catalogs: version: 3.5.13 vue-component-type-helpers: specifier: ^3.0.7 - version: 3.1.8 + version: 3.2.2 vue-eslint-parser: specifier: ^10.2.0 version: 10.2.0 @@ -305,7 +308,7 @@ catalogs: version: 4.4.3 vue-tsc: specifier: ^3.1.8 - version: 3.1.8 + version: 3.2.1 vuefire: specifier: ^3.2.1 version: 3.2.1 @@ -376,7 +379,7 @@ importers: version: 4.2.5 '@sentry/vue': specifier: 'catalog:' - version: 8.48.0(pinia@2.2.2(typescript@5.9.3)(vue@3.5.13(typescript@5.9.3)))(vue@3.5.13(typescript@5.9.3)) + version: 8.55.0(pinia@2.2.2(typescript@5.9.3)(vue@3.5.13(typescript@5.9.3)))(vue@3.5.13(typescript@5.9.3)) '@sparkjsdev/spark': specifier: 'catalog:' version: 0.1.10 @@ -530,7 +533,7 @@ importers: version: 22.2.6(@babel/traverse@7.28.5)(nx@22.2.6)(typescript@5.9.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.2))(vitest@3.2.4) '@pinia/testing': specifier: 'catalog:' - version: 0.1.5(pinia@2.2.2(typescript@5.9.3)(vue@3.5.13(typescript@5.9.3)))(vue@3.5.13(typescript@5.9.3)) + version: 0.1.7(pinia@2.2.2(typescript@5.9.3)(vue@3.5.13(typescript@5.9.3)))(vue@3.5.13(typescript@5.9.3)) '@playwright/test': specifier: 'catalog:' version: 1.57.0 @@ -543,6 +546,9 @@ importers: '@storybook/addon-docs': specifier: 'catalog:' version: 10.1.9(@types/react@19.1.9)(esbuild@0.27.1)(rollup@4.53.5)(storybook@10.1.9(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.2)) + '@storybook/addon-mcp': + specifier: 'catalog:' + version: 0.1.6(storybook@10.1.9(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3) '@storybook/vue3': specifier: 'catalog:' version: 10.1.9(storybook@10.1.9(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vue@3.5.13(typescript@5.9.3)) @@ -620,7 +626,7 @@ importers: version: 15.15.0 happy-dom: specifier: 'catalog:' - version: 15.11.0 + version: 15.11.7 husky: specifier: 'catalog:' version: 9.1.7 @@ -716,16 +722,16 @@ importers: version: 8.0.5(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.2))(vue@3.5.13(typescript@5.9.3)) vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@24.10.4)(@vitest/ui@3.2.4)(happy-dom@15.11.0)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.1)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@24.10.4)(@vitest/ui@3.2.4)(happy-dom@15.11.7)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.1)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.2) vue-component-type-helpers: specifier: 'catalog:' - version: 3.1.8 + version: 3.2.2 vue-eslint-parser: specifier: 'catalog:' version: 10.2.0(eslint@9.39.1(jiti@2.6.1)) vue-tsc: specifier: 'catalog:' - version: 3.1.8(typescript@5.9.3) + version: 3.2.1(typescript@5.9.3) zip-dir: specifier: ^2.0.0 version: 2.0.0 @@ -795,7 +801,7 @@ importers: version: 8.0.5(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.2))(vue@3.5.13(typescript@5.9.3)) vue-tsc: specifier: 'catalog:' - version: 3.1.8(typescript@5.9.3) + version: 3.2.1(typescript@5.9.3) packages/design-system: dependencies: @@ -1499,8 +1505,8 @@ packages: peerDependencies: '@csstools/css-tokenizer': ^3.0.4 - '@csstools/css-syntax-patches-for-csstree@1.0.20': - resolution: {integrity: sha512-8BHsjXfSciZxjmHQOuVdW2b8WLUPts9a+mfL13/PzEviufUEW2xnvQuOlKs9dRBHgRqJ53SF/DUoK9+MZk72oQ==} + '@csstools/css-syntax-patches-for-csstree@1.0.22': + resolution: {integrity: sha512-qBcx6zYlhleiFfdtzkRgwNC7VVoAwfK76Vmsw5t+PbvtdknO9StgRk7ROvq9so1iqbdW4uLIDAsXRsTfUrIoOw==} engines: {node: '>=18'} '@csstools/css-tokenizer@3.0.4': @@ -2765,10 +2771,10 @@ packages: peerDependencies: typescript: ^3 || ^4 || ^5 - '@pinia/testing@0.1.5': - resolution: {integrity: sha512-AcGzuotkzhRoF00htuxLfIPBBHVE6HjjB3YC5Y3os8vRgKu6ipknK5GBQq9+pduwYQhZ+BcCZDC9TyLAUlUpoQ==} + '@pinia/testing@0.1.7': + resolution: {integrity: sha512-xcDq6Ry/kNhZ5bsUMl7DeoFXwdume1NYzDggCiDUDKoPQ6Mo0eH9VU7bJvBtlurqe6byAntWoX5IhVFqWzRz/Q==} peerDependencies: - pinia: '>=2.2.1' + pinia: '>=2.2.6' '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} @@ -3017,28 +3023,28 @@ packages: '@rushstack/ts-command-line@5.0.3': resolution: {integrity: sha512-bgPhQEqLVv/2hwKLYv/XvsTWNZ9B/+X1zJ7WgQE9rO5oiLzrOZvkIW4pk13yOQBhHyjcND5qMOa6p83t+Z66iQ==} - '@sentry-internal/browser-utils@8.48.0': - resolution: {integrity: sha512-pLtu0Fa1Ou0v3M1OEO1MB1EONJVmXEGtoTwFRCO1RPQI2ulmkG6BikINClFG5IBpoYKZ33WkEXuM6U5xh+pdZg==} + '@sentry-internal/browser-utils@8.55.0': + resolution: {integrity: sha512-ROgqtQfpH/82AQIpESPqPQe0UyWywKJsmVIqi3c5Fh+zkds5LUxnssTj3yNd1x+kxaPDVB023jAP+3ibNgeNDw==} engines: {node: '>=14.18'} - '@sentry-internal/feedback@8.48.0': - resolution: {integrity: sha512-6PwcJNHVPg0EfZxmN+XxVOClfQpv7MBAweV8t9i5l7VFr8sM/7wPNSeU/cG7iK19Ug9ZEkBpzMOe3G4GXJ5bpw==} + '@sentry-internal/feedback@8.55.0': + resolution: {integrity: sha512-cP3BD/Q6pquVQ+YL+rwCnorKuTXiS9KXW8HNKu4nmmBAyf7urjs+F6Hr1k9MXP5yQ8W3yK7jRWd09Yu6DHWOiw==} engines: {node: '>=14.18'} - '@sentry-internal/replay-canvas@8.48.0': - resolution: {integrity: sha512-LdivLfBXXB9us1aAc6XaL7/L2Ob4vi3C/fEOXElehg3qHjX6q6pewiv5wBvVXGX1NfZTRvu+X11k6TZoxKsezw==} + '@sentry-internal/replay-canvas@8.55.0': + resolution: {integrity: sha512-nIkfgRWk1091zHdu4NbocQsxZF1rv1f7bbp3tTIlZYbrH62XVZosx5iHAuZG0Zc48AETLE7K4AX9VGjvQj8i9w==} engines: {node: '>=14.18'} - '@sentry-internal/replay@8.48.0': - resolution: {integrity: sha512-csILVupc5RkrsTrncuUTGmlB56FQSFjXPYWG8I8yBTGlXEJ+o8oTuF6+55R4vbw3EIzBveXWi4kEBbnQlXW/eg==} + '@sentry-internal/replay@8.55.0': + resolution: {integrity: sha512-roCDEGkORwolxBn8xAKedybY+Jlefq3xYmgN2fr3BTnsXjSYOPC7D1/mYqINBat99nDtvgFvNfRcZPiwwZ1hSw==} engines: {node: '>=14.18'} '@sentry/babel-plugin-component-annotate@4.6.0': resolution: {integrity: sha512-3soTX50JPQQ51FSbb4qvNBf4z/yP7jTdn43vMTp9E4IxvJ9HKJR7OEuKkCMszrZmWsVABXl02msqO7QisePdiQ==} engines: {node: '>= 14'} - '@sentry/browser@8.48.0': - resolution: {integrity: sha512-fuuVULB5/1vI8NoIwXwR3xwhJJqk+y4RdSdajExGF7nnUDBpwUJyXsmYJnOkBO+oLeEs58xaCpotCKiPUNnE3g==} + '@sentry/browser@8.55.0': + resolution: {integrity: sha512-1A31mCEWCjaMxJt6qGUK+aDnLDcK6AwLAZnqpSchNysGni1pSn1RWSmk9TBF8qyTds5FH8B31H480uxMPUJ7Cw==} engines: {node: '>=14.18'} '@sentry/bundler-plugin-core@4.6.0': @@ -3097,19 +3103,19 @@ packages: engines: {node: '>= 10'} hasBin: true - '@sentry/core@8.48.0': - resolution: {integrity: sha512-VGwYgTfLpvJ5LRO5A+qWo1gpo6SfqaGXL9TOzVgBucAdpzbrYHpZ87sEarDVq/4275uk1b0S293/mfsskFczyw==} + '@sentry/core@8.55.0': + resolution: {integrity: sha512-6g7jpbefjHYs821Z+EBJ8r4Z7LT5h80YSWRJaylGS4nW5W5Z2KXzpdnyFarv37O7QjauzVC2E+PABmpkw5/JGA==} engines: {node: '>=14.18'} '@sentry/vite-plugin@4.6.0': resolution: {integrity: sha512-fMR2d+EHwbzBa0S1fp45SNUTProxmyFBp+DeBWWQOSP9IU6AH6ea2rqrpMAnp/skkcdW4z4LSRrOEpMZ5rWXLw==} engines: {node: '>= 14'} - '@sentry/vue@8.48.0': - resolution: {integrity: sha512-hqm9X7hz1vMQQB1HBYezrDBQihZk6e/MxWIG1wMJoClcBnD1Sh7y+D36UwaQlR4Gr/Ftiz+Bb0DxuAYHoUS4ow==} + '@sentry/vue@8.55.0': + resolution: {integrity: sha512-J6lcpzL39snV/spoGpwyk5Rp1wSFxOV4qV1NhQ9OlLHORVBp/Xpw7cEA0oKqG2w1wVtCV+gC5Jjf9HTmYiHQOQ==} engines: {node: '>=14.18'} peerDependencies: - pinia: 2.x + pinia: 2.x || 3.x vue: 2.x || 3.x peerDependenciesMeta: pinia: @@ -3121,11 +3127,19 @@ packages: '@sparkjsdev/spark@0.1.10': resolution: {integrity: sha512-CiijdZQuj7KPDUqIZPiEqyUkJCYo1JqR05vq/V+ElxMwqR7L70ZuZDyIKcasjZHSiPB8pGRMH8HZGqUKO9aRPQ==} + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@storybook/addon-docs@10.1.9': resolution: {integrity: sha512-SvwEZ32lyk5p3PRmE3pmfAhs4HMiVo5zxjTBVmK9kgz9zGgWCTlikb56tJ998hVe52CFyCvt3I9rkHeYMCKPww==} peerDependencies: storybook: ^10.1.9 + '@storybook/addon-mcp@0.1.6': + resolution: {integrity: sha512-+EagCHqwIb9tg3DKskEsXpsqQVnMljxgR5Tt3Bu0ZpWweB1HdMy+ok128gzNfTZ3r+5ljksr0q66YCEkrQwdDA==} + peerDependencies: + storybook: ^9.1.16 || ^10.0.0 || ^10.1.0-0 || ^10.2.0-0 || ^10.3.0-0 || ^10.4.0-0 + '@storybook/builder-vite@10.1.9': resolution: {integrity: sha512-rUILpjGV7gKfXrUeZzpNAer9PspB3LJI1d+gJHISx2Gs24bdneA3y/gu0fWw46ccOSIcwb91xoK5QxliJcWsWg==} peerDependencies: @@ -3159,6 +3173,9 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + '@storybook/mcp@0.1.1': + resolution: {integrity: sha512-+AivFDms1XkY2VUvZBBYy0co5qvRh20eYXYwhaDPQXX2Q4y96arSkWn22e/l3DQwA9Ywzv481vj4gl4zPrCQkg==} + '@storybook/react-dom-shim@10.1.9': resolution: {integrity: sha512-gJsR6fI1gG4DSin6sQx8RmGDQF8Lije0cZbxHyVedNleBsveGXIPFUKFVi+pRNdwBPni1Z2g/gYyHzkOEqPD2w==} peerDependencies: @@ -3431,6 +3448,26 @@ packages: '@tiptap/starter-kit@2.10.4': resolution: {integrity: sha512-tu/WCs9Mkr5Nt8c3/uC4VvAbQlVX0OY7ygcqdzHGUeG9zP3twdW7o5xM3kyDKR2++sbVzqu5Ll5qNU+1JZvPGQ==} + '@tmcp/adapter-valibot@0.1.5': + resolution: {integrity: sha512-9P2wrVYPngemNK0UvPb/opC722/jfd09QxXmme1TRp/wPsl98vpSk/MXt24BCMqBRv4Dvs0xxJH4KHDcjXW52Q==} + peerDependencies: + tmcp: ^1.17.0 + valibot: ^1.1.0 + + '@tmcp/session-manager@0.2.1': + resolution: {integrity: sha512-DOGy9LfufXCy1wfpGHZ6qPSDQtRnTVwOb71+41ffovTqzLMZlK3iLK/LIsekHxIiku+iIAUiqEKN+DHbqEm8IA==} + peerDependencies: + tmcp: ^1.16.3 + + '@tmcp/transport-http@0.8.3': + resolution: {integrity: sha512-gnoBjDBd8/ppl4WRrNKPKHlioCxE8D0zTyNUOzqUjsg0s6GRsyB5iMirh9lC4QjQt0NEOrI+sIJdz+9ymf0MDA==} + peerDependencies: + '@tmcp/auth': ^0.3.3 || ^0.4.0 + tmcp: ^1.18.0 + peerDependenciesMeta: + '@tmcp/auth': + optional: true + '@trivago/prettier-plugin-sort-imports@5.2.2': resolution: {integrity: sha512-fYDQA9e6yTNmA13TLVSA+WMQRc5Bn/c0EUBditUHNfMMxN7M82c38b1kEggVE3pLpZ0FwkwJkUEKMiOi52JXFA==} engines: {node: '>18.12'} @@ -3758,6 +3795,11 @@ packages: cpu: [x64] os: [win32] + '@valibot/to-json-schema@1.5.0': + resolution: {integrity: sha512-GE7DmSr1C2UCWPiV0upRH6mv0cCPsqYGs819fb6srCS1tWhyXrkGGe+zxUiwzn/L1BOfADH4sNjY/YHCuP8phQ==} + peerDependencies: + valibot: ^1.2.0 + '@vitejs/plugin-vue@6.0.3': resolution: {integrity: sha512-TlGPkLFLVOY3T7fZrwdvKpjprR3s4fxRln0ORDo1VQ7HHyxJwTlrjKU3kpVWTlaAjIEuCTokmjkZnr8Tpc925w==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3811,20 +3853,20 @@ packages: '@volar/language-core@2.4.15': resolution: {integrity: sha512-3VHw+QZU0ZG9IuQmzT68IyN4hZNd9GchGPhbD9+pa8CVv7rnoOZwo7T8weIbrRmihqy3ATpdfXFnqRrfPVK6CA==} - '@volar/language-core@2.4.26': - resolution: {integrity: sha512-hH0SMitMxnB43OZpyF1IFPS9bgb2I3bpCh76m2WEK7BE0A0EzpYsRp0CCH2xNKshr7kacU5TQBLYn4zj7CG60A==} + '@volar/language-core@2.4.27': + resolution: {integrity: sha512-DjmjBWZ4tJKxfNC1F6HyYERNHPYS7L7OPFyCrestykNdUZMFYzI9WTyvwPcaNaHlrEUwESHYsfEw3isInncZxQ==} '@volar/source-map@2.4.15': resolution: {integrity: sha512-CPbMWlUN6hVZJYGcU/GSoHu4EnCHiLaXI9n8c9la6RaI9W5JHX+NqG+GSQcB0JdC2FIBLdZJwGsfKyBB71VlTg==} - '@volar/source-map@2.4.26': - resolution: {integrity: sha512-JJw0Tt/kSFsIRmgTQF4JSt81AUSI1aEye5Zl65EeZ8H35JHnTvFGmpDOBn5iOxd48fyGE+ZvZBp5FcgAy/1Qhw==} + '@volar/source-map@2.4.27': + resolution: {integrity: sha512-ynlcBReMgOZj2i6po+qVswtDUeeBRCTgDurjMGShbm8WYZgJ0PA4RmtebBJ0BCYol1qPv3GQF6jK7C9qoVc7lg==} '@volar/typescript@2.4.15': resolution: {integrity: sha512-2aZ8i0cqPGjXb4BhkMsPYDkkuc2ZQ6yOpqwAuNwUoncELqoy5fRgOQtLR9gB0g902iS0NAkvpIzs27geVyVdPg==} - '@volar/typescript@2.4.26': - resolution: {integrity: sha512-N87ecLD48Sp6zV9zID/5yuS1+5foj0DfuYGdQ6KHj/IbKvyKv1zNX6VCmnKYwtmHadEO6mFc2EKISiu3RDPAvA==} + '@volar/typescript@2.4.27': + resolution: {integrity: sha512-eWaYCcl/uAPInSK2Lze6IqVWaBu/itVqR5InXcHXFyles4zO++Mglt3oxdgj75BDcv1Knr9Y93nowS8U3wqhxg==} '@vue/babel-helper-vue-transform-on@1.4.0': resolution: {integrity: sha512-mCokbouEQ/ocRce/FpKCRItGo+013tHg7tixg3DUNS+6bmIchPt66012kBMm476vyEIJPafrvOf4E5OYj3shSw==} @@ -3848,12 +3890,18 @@ packages: '@vue/compiler-core@3.5.25': resolution: {integrity: sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==} + '@vue/compiler-core@3.5.26': + resolution: {integrity: sha512-vXyI5GMfuoBCnv5ucIT7jhHKl55Y477yxP6fc4eUswjP8FG3FFVFd41eNDArR+Uk3QKn2Z85NavjaxLxOC19/w==} + '@vue/compiler-dom@3.5.13': resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==} '@vue/compiler-dom@3.5.25': resolution: {integrity: sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==} + '@vue/compiler-dom@3.5.26': + resolution: {integrity: sha512-y1Tcd3eXs834QjswshSilCBnKGeQjQXB6PqFn/1nxcQw4pmG42G8lwz+FZPAZAby6gZeHSt/8LMPfZ4Rb+Bd/A==} + '@vue/compiler-sfc@3.5.13': resolution: {integrity: sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==} @@ -3872,6 +3920,9 @@ packages: '@vue/devtools-api@6.6.3': resolution: {integrity: sha512-0MiMsFma/HqA6g3KLKn+AGpL1kgKhFWszC9U29NfpWK5LE7bjeXxySWJrOJ77hBz+TBrBQ7o4QJqbPbqbs8rJw==} + '@vue/devtools-api@6.6.4': + resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} + '@vue/devtools-core@8.0.5': resolution: {integrity: sha512-dpCw8nl0GDBuiL9SaY0mtDxoGIEmU38w+TQiYEPOLhW03VDC0lfNMYXS/qhl4I0YlysGp04NLY4UNn6xgD0VIQ==} peerDependencies: @@ -3899,13 +3950,8 @@ packages: typescript: optional: true - '@vue/language-core@3.1.8': - resolution: {integrity: sha512-PfwAW7BLopqaJbneChNL6cUOTL3GL+0l8paYP5shhgY5toBNidWnMXWM+qDwL7MC9+zDtzCF2enT8r6VPu64iw==} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@vue/language-core@3.2.1': + resolution: {integrity: sha512-g6oSenpnGMtpxHGAwKuu7HJJkNZpemK/zg3vZzZbJ6cnnXq1ssxuNrXSsAHYM3NvH8p4IkTw+NLmuxyeYz4r8A==} '@vue/reactivity@3.5.13': resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==} @@ -3927,6 +3973,9 @@ packages: '@vue/shared@3.5.25': resolution: {integrity: sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==} + '@vue/shared@3.5.26': + resolution: {integrity: sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A==} + '@vue/test-utils@2.4.6': resolution: {integrity: sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==} @@ -4113,8 +4162,8 @@ packages: alien-signals@1.0.13: resolution: {integrity: sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==} - alien-signals@3.1.1: - resolution: {integrity: sha512-ogkIWbVrLwKtHY6oOAXaYkAxP+cTH7V5FZ5+Tm4NZFd8VDZ6uNMDrfzqctTZ42eTMCSR3ne3otpcxmqSnFfPYA==} + alien-signals@3.1.2: + resolution: {integrity: sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw==} ansi-align@3.0.1: resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} @@ -4218,8 +4267,8 @@ packages: resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} engines: {node: '>=4'} - ast-v8-to-istanbul@0.3.5: - resolution: {integrity: sha512-9SdXjNheSiE8bALAQCQQuT6fgQaoxJh7IRYrRGZ8/9nv8WhJeC1aXAwN8TbaOssGOukUvyvnkgD9+Yuykvl1aA==} + ast-v8-to-istanbul@0.3.10: + resolution: {integrity: sha512-p4K7vMz2ZSk3wN8l5o3y2bJAoZXT3VuJI5OLTATY/01CYWumWvwkUw0SqDBnNq6IiTO3qDa1eSQDibAV8g7XOQ==} astral-regex@2.0.0: resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} @@ -4884,6 +4933,10 @@ packages: resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} engines: {node: '>=0.12'} + entities@7.0.0: + resolution: {integrity: sha512-FDWG5cmEYf2Z00IkYRhbFrwIwvdFKH07uV8dvNy0omp/Qb1xcyCWp2UDtcwJF4QZZvk0sLudP6/hAu42TaqVhQ==} + engines: {node: '>=0.12'} + env-paths@2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} @@ -5105,6 +5158,9 @@ packages: jiti: optional: true + esm-env@1.2.2: + resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==} + esm-resolve@1.0.11: resolution: {integrity: sha512-LxF0wfUQm3ldUDHkkV2MIbvvY0TgzIpJ420jHSV1Dm+IlplBEWiJTKWM61GtxUfvjV6iD4OtTYFGAGM2uuIUWg==} @@ -5150,8 +5206,8 @@ packages: eventemitter3@5.0.1: resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} - expect-type@1.2.2: - resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} exsolve@1.0.8: @@ -5418,8 +5474,8 @@ packages: resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} engines: {node: '>=18'} - globals@16.4.0: - resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==} + globals@16.5.0: + resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} engines: {node: '>=18'} globalthis@1.0.4: @@ -5450,8 +5506,8 @@ packages: resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} engines: {node: '>=6.0'} - happy-dom@15.11.0: - resolution: {integrity: sha512-/zyxHbXriYJ8b9Urh43ILk/jd9tC07djURnJuAimJ3tJCOLOzOUp7dEHDwJOZyzROlrrooUhr/0INZIDBj1Bjw==} + happy-dom@15.11.7: + resolution: {integrity: sha512-KyrFvnl+J9US63TEzwoiJOQzZBJY7KgBushJA8X61DMbNsH+2ONkDuLDnCnwUiPTF42tLoEmrPyoqbenVA5zrg==} engines: {node: '>=18.0.0'} has-bigints@1.1.0: @@ -5921,6 +5977,9 @@ packages: json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-rpc-2.0@1.7.1: + resolution: {integrity: sha512-JqZjhjAanbpkXIzFE7u8mE/iFblawwlXtONaCvRqI+pyABVz7B4M1EUNpyVW+dZjqgQ2L5HFmZCmOCgUKm00hg==} + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -6163,8 +6222,8 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.1.0: - resolution: {integrity: sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==} + lru-cache@11.2.4: + resolution: {integrity: sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==} engines: {node: 20 || >=22} lru-cache@5.1.1: @@ -6529,8 +6588,8 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - nwsapi@2.2.21: - resolution: {integrity: sha512-o6nIY3qwiSXl7/LuOU0Dmuctd34Yay0yeuZRLFmDPrrdHpXKFndPj3hM+YEPVHYC5fx2otBx4Ilc/gyYSAUaIA==} + nwsapi@2.2.23: + resolution: {integrity: sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==} nx@22.2.4: resolution: {integrity: sha512-x94oITsrX1jjSIZDSW/9+aPH9zJNK1m5Hfs2PMkcHR4i6h0fL/vv3+JzGbMF8RZRMTLfqm1ZCxJgAFVh3tPatg==} @@ -7332,6 +7391,9 @@ packages: sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + sqids@0.3.0: + resolution: {integrity: sha512-lOQK1ucVg+W6n3FhRwwSeUijxe93b51Bfz5PMRMihVf1iVkl82ePQG7V5vwrhzB11v0NtsR25PSZRGiSomJaJw==} + stable-hash-x@0.2.0: resolution: {integrity: sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==} engines: {node: '>=12.0.0'} @@ -7346,8 +7408,8 @@ packages: standardized-audio-context@25.3.77: resolution: {integrity: sha512-Ki9zNz6pKcC5Pi+QPjPyVsD9GwJIJWgryji0XL9cAJXMGyn+dPOf6Qik1AHei0+UNVcc4BOCa0hWLBzlwqsW/A==} - std-env@3.9.0: - resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} stop-iteration-iterator@1.1.0: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} @@ -7432,8 +7494,8 @@ packages: resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==} engines: {node: '>=14.16'} - strip-literal@3.0.0: - resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==} + strip-literal@3.1.0: + resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} stubborn-fs@1.2.5: resolution: {integrity: sha512-H2N9c26eXjzL/S/K+i/RHHcFanE74dptvvjM8iwzwbVcWY/zjBbgRqF3K0DY4+OD+uTTASTBvDoxPDaPN02D7g==} @@ -7569,6 +7631,9 @@ packages: resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==} hasBin: true + tmcp@1.19.0: + resolution: {integrity: sha512-wOY449EdaWDo7wLZEOVjeH9fn/AqfFF4f+3pDerCI8xHpy2Z8msUjAF0Vkg01aEFIdFMmiNDiY4hu6E7jVX79w==} + tmp@0.2.5: resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==} engines: {node: '>=14.14'} @@ -7811,6 +7876,9 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + uri-template-matcher@1.1.2: + resolution: {integrity: sha512-uZc1h12jdO3m/R77SfTEOuo6VbMhgWznaawKpBjRGSJb7i91x5PgI37NQJtG+Cerxkk0yr1pylBY2qG1kQ+aEQ==} + use-sync-external-store@1.6.0: resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} peerDependencies: @@ -7826,6 +7894,14 @@ packages: resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} hasBin: true + valibot@1.2.0: + resolution: {integrity: sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==} + peerDependencies: + typescript: '>=5' + peerDependenciesMeta: + typescript: + optional: true + vfile-message@4.0.3: resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} @@ -7968,8 +8044,8 @@ packages: vue-component-type-helpers@2.2.12: resolution: {integrity: sha512-YbGqHZ5/eW4SnkPNR44mKVc6ZKQoRs/Rux1sxC6rdwXb4qpbOSYfDr9DsTHolOTGmIKgM9j141mZbBeg05R1pw==} - vue-component-type-helpers@3.1.8: - resolution: {integrity: sha512-oaowlmEM6BaYY+8o+9D9cuzxpWQWHqHTMKakMxXu0E+UCIOMTljyIPO15jcnaCwJtZu/zWDotK7mOIHvWD9mcw==} + vue-component-type-helpers@3.2.2: + resolution: {integrity: sha512-x8C2nx5XlUNM0WirgfTkHjJGO/ABBxlANZDtHw2HclHtQnn+RFPTnbjMJn8jHZW4TlUam0asHcA14lf1C6Jb+A==} vue-demi@0.14.10: resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} @@ -8009,8 +8085,8 @@ packages: peerDependencies: vue: ^3.2.0 - vue-tsc@3.1.8: - resolution: {integrity: sha512-deKgwx6exIHeZwF601P1ktZKNF0bepaSN4jBU3AsbldPx9gylUc1JDxYppl82yxgkAgaz0Y0LCLOi+cXe9HMYA==} + vue-tsc@3.2.1: + resolution: {integrity: sha512-I23Rk8dkQfmcSbxDO0dmg9ioMLjKA1pjlU3Lz6Jfk2pMGu3Uryu9810XkcZH24IzPbhzPCnkKo2rEMRX0skSrw==} hasBin: true peerDependencies: typescript: '>=5.0.0' @@ -8088,6 +8164,7 @@ packages: whatwg-encoding@3.1.1: resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} engines: {node: '>=18'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation whatwg-mimetype@3.0.0: resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} @@ -9154,7 +9231,7 @@ snapshots: dependencies: '@csstools/css-tokenizer': 3.0.4 - '@csstools/css-syntax-patches-for-csstree@1.0.20': {} + '@csstools/css-syntax-patches-for-csstree@1.0.22': {} '@csstools/css-tokenizer@3.0.4': {} @@ -9792,7 +9869,7 @@ snapshots: eslint: 9.39.1(jiti@2.6.1) eslint-compat-utils: 0.6.5(eslint@9.39.1(jiti@2.6.1)) glob: 10.4.5 - globals: 16.4.0 + globals: 16.5.0 ignore: 7.0.5 import-fresh: 3.3.1 is-language-code: 3.1.0 @@ -10324,7 +10401,7 @@ snapshots: tsconfig-paths: 4.2.0 tslib: 2.8.1 vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.2) - vitest: 3.2.4(@types/debug@4.1.12)(@types/node@24.10.4)(@vitest/ui@3.2.4)(happy-dom@15.11.0)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.1)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.2) + vitest: 3.2.4(@types/debug@4.1.12)(@types/node@24.10.4)(@vitest/ui@3.2.4)(happy-dom@15.11.7)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.1)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.2) transitivePeerDependencies: - '@babel/traverse' - '@swc-node/register' @@ -10344,7 +10421,7 @@ snapshots: tslib: 2.8.1 optionalDependencies: vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.2) - vitest: 3.2.4(@types/debug@4.1.12)(@types/node@24.10.4)(@vitest/ui@3.2.4)(happy-dom@15.11.0)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.1)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.2) + vitest: 3.2.4(@types/debug@4.1.12)(@types/node@24.10.4)(@vitest/ui@3.2.4)(happy-dom@15.11.7)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.1)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.2) transitivePeerDependencies: - '@babel/traverse' - '@swc-node/register' @@ -10547,7 +10624,7 @@ snapshots: esquery: 1.6.0 typescript: 5.9.3 - '@pinia/testing@0.1.5(pinia@2.2.2(typescript@5.9.3)(vue@3.5.13(typescript@5.9.3)))(vue@3.5.13(typescript@5.9.3))': + '@pinia/testing@0.1.7(pinia@2.2.2(typescript@5.9.3)(vue@3.5.13(typescript@5.9.3)))(vue@3.5.13(typescript@5.9.3))': dependencies: pinia: 2.2.2(typescript@5.9.3)(vue@3.5.13(typescript@5.9.3)) vue-demi: 0.14.10(vue@3.5.13(typescript@5.9.3)) @@ -10760,33 +10837,33 @@ snapshots: transitivePeerDependencies: - '@types/node' - '@sentry-internal/browser-utils@8.48.0': + '@sentry-internal/browser-utils@8.55.0': dependencies: - '@sentry/core': 8.48.0 + '@sentry/core': 8.55.0 - '@sentry-internal/feedback@8.48.0': + '@sentry-internal/feedback@8.55.0': dependencies: - '@sentry/core': 8.48.0 + '@sentry/core': 8.55.0 - '@sentry-internal/replay-canvas@8.48.0': + '@sentry-internal/replay-canvas@8.55.0': dependencies: - '@sentry-internal/replay': 8.48.0 - '@sentry/core': 8.48.0 + '@sentry-internal/replay': 8.55.0 + '@sentry/core': 8.55.0 - '@sentry-internal/replay@8.48.0': + '@sentry-internal/replay@8.55.0': dependencies: - '@sentry-internal/browser-utils': 8.48.0 - '@sentry/core': 8.48.0 + '@sentry-internal/browser-utils': 8.55.0 + '@sentry/core': 8.55.0 '@sentry/babel-plugin-component-annotate@4.6.0': {} - '@sentry/browser@8.48.0': + '@sentry/browser@8.55.0': dependencies: - '@sentry-internal/browser-utils': 8.48.0 - '@sentry-internal/feedback': 8.48.0 - '@sentry-internal/replay': 8.48.0 - '@sentry-internal/replay-canvas': 8.48.0 - '@sentry/core': 8.48.0 + '@sentry-internal/browser-utils': 8.55.0 + '@sentry-internal/feedback': 8.55.0 + '@sentry-internal/replay': 8.55.0 + '@sentry-internal/replay-canvas': 8.55.0 + '@sentry/core': 8.55.0 '@sentry/bundler-plugin-core@4.6.0': dependencies: @@ -10846,7 +10923,7 @@ snapshots: - encoding - supports-color - '@sentry/core@8.48.0': {} + '@sentry/core@8.55.0': {} '@sentry/vite-plugin@4.6.0': dependencies: @@ -10856,10 +10933,10 @@ snapshots: - encoding - supports-color - '@sentry/vue@8.48.0(pinia@2.2.2(typescript@5.9.3)(vue@3.5.13(typescript@5.9.3)))(vue@3.5.13(typescript@5.9.3))': + '@sentry/vue@8.55.0(pinia@2.2.2(typescript@5.9.3)(vue@3.5.13(typescript@5.9.3)))(vue@3.5.13(typescript@5.9.3))': dependencies: - '@sentry/browser': 8.48.0 - '@sentry/core': 8.48.0 + '@sentry/browser': 8.55.0 + '@sentry/core': 8.55.0 vue: 3.5.13(typescript@5.9.3) optionalDependencies: pinia: 2.2.2(typescript@5.9.3)(vue@3.5.13(typescript@5.9.3)) @@ -10870,6 +10947,8 @@ snapshots: dependencies: fflate: 0.8.2 + '@standard-schema/spec@1.1.0': {} + '@storybook/addon-docs@10.1.9(@types/react@19.1.9)(esbuild@0.27.1)(rollup@4.53.5)(storybook@10.1.9(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.2))': dependencies: '@mdx-js/react': 3.1.1(@types/react@19.1.9)(react@19.2.3) @@ -10887,6 +10966,18 @@ snapshots: - vite - webpack + '@storybook/addon-mcp@0.1.6(storybook@10.1.9(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3)': + dependencies: + '@storybook/mcp': 0.1.1(typescript@5.9.3) + '@tmcp/adapter-valibot': 0.1.5(tmcp@1.19.0(typescript@5.9.3))(valibot@1.2.0(typescript@5.9.3)) + '@tmcp/transport-http': 0.8.3(tmcp@1.19.0(typescript@5.9.3)) + storybook: 10.1.9(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + tmcp: 1.19.0(typescript@5.9.3) + valibot: 1.2.0(typescript@5.9.3) + transitivePeerDependencies: + - '@tmcp/auth' + - typescript + '@storybook/builder-vite@10.1.9(esbuild@0.27.1)(rollup@4.53.5)(storybook@10.1.9(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.2))': dependencies: '@storybook/csf-plugin': 10.1.9(esbuild@0.27.1)(rollup@4.53.5)(storybook@10.1.9(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.2)) @@ -10916,6 +11007,16 @@ snapshots: react: 19.2.3 react-dom: 19.2.3(react@19.2.3) + '@storybook/mcp@0.1.1(typescript@5.9.3)': + dependencies: + '@tmcp/adapter-valibot': 0.1.5(tmcp@1.19.0(typescript@5.9.3))(valibot@1.2.0(typescript@5.9.3)) + '@tmcp/transport-http': 0.8.3(tmcp@1.19.0(typescript@5.9.3)) + tmcp: 1.19.0(typescript@5.9.3) + valibot: 1.2.0(typescript@5.9.3) + transitivePeerDependencies: + - '@tmcp/auth' + - typescript + '@storybook/react-dom-shim@10.1.9(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.1.9(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))': dependencies: react: 19.2.3 @@ -10945,7 +11046,7 @@ snapshots: storybook: 10.1.9(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) type-fest: 2.19.0 vue: 3.5.13(typescript@5.9.3) - vue-component-type-helpers: 3.1.8 + vue-component-type-helpers: 3.2.2 '@swc/helpers@0.5.17': dependencies: @@ -11213,6 +11314,23 @@ snapshots: '@tiptap/extension-text-style': 2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4)) '@tiptap/pm': 2.10.4 + '@tmcp/adapter-valibot@0.1.5(tmcp@1.19.0(typescript@5.9.3))(valibot@1.2.0(typescript@5.9.3))': + dependencies: + '@standard-schema/spec': 1.1.0 + '@valibot/to-json-schema': 1.5.0(valibot@1.2.0(typescript@5.9.3)) + tmcp: 1.19.0(typescript@5.9.3) + valibot: 1.2.0(typescript@5.9.3) + + '@tmcp/session-manager@0.2.1(tmcp@1.19.0(typescript@5.9.3))': + dependencies: + tmcp: 1.19.0(typescript@5.9.3) + + '@tmcp/transport-http@0.8.3(tmcp@1.19.0(typescript@5.9.3))': + dependencies: + '@tmcp/session-manager': 0.2.1(tmcp@1.19.0(typescript@5.9.3)) + esm-env: 1.2.2 + tmcp: 1.19.0(typescript@5.9.3) + '@trivago/prettier-plugin-sort-imports@5.2.2(@vue/compiler-sfc@3.5.25)(prettier@3.7.4)': dependencies: '@babel/generator': 7.28.5 @@ -11555,6 +11673,10 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true + '@valibot/to-json-schema@1.5.0(valibot@1.2.0(typescript@5.9.3))': + dependencies: + valibot: 1.2.0(typescript@5.9.3) + '@vitejs/plugin-vue@6.0.3(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.2))(vue@3.5.13(typescript@5.9.3))': dependencies: '@rolldown/pluginutils': 1.0.0-beta.53 @@ -11571,7 +11693,7 @@ snapshots: dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 1.0.2 - ast-v8-to-istanbul: 0.3.5 + ast-v8-to-istanbul: 0.3.10 debug: 4.4.3 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 @@ -11579,10 +11701,10 @@ snapshots: istanbul-reports: 3.2.0 magic-string: 0.30.21 magicast: 0.3.5 - std-env: 3.9.0 + std-env: 3.10.0 test-exclude: 7.0.1 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/debug@4.1.12)(@types/node@24.10.4)(@vitest/ui@3.2.4)(happy-dom@15.11.0)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.1)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.2) + vitest: 3.2.4(@types/debug@4.1.12)(@types/node@24.10.4)(@vitest/ui@3.2.4)(happy-dom@15.11.7)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.1)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.2) transitivePeerDependencies: - supports-color @@ -11610,7 +11732,7 @@ snapshots: dependencies: '@vitest/utils': 3.2.4 pathe: 2.0.3 - strip-literal: 3.0.0 + strip-literal: 3.1.0 '@vitest/snapshot@3.2.4': dependencies: @@ -11631,7 +11753,7 @@ snapshots: sirv: 3.0.2 tinyglobby: 0.2.15 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/debug@4.1.12)(@types/node@24.10.4)(@vitest/ui@3.2.4)(happy-dom@15.11.0)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.1)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.2) + vitest: 3.2.4(@types/debug@4.1.12)(@types/node@24.10.4)(@vitest/ui@3.2.4)(happy-dom@15.11.7)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.1)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.2) '@vitest/utils@3.2.4': dependencies: @@ -11643,13 +11765,13 @@ snapshots: dependencies: '@volar/source-map': 2.4.15 - '@volar/language-core@2.4.26': + '@volar/language-core@2.4.27': dependencies: - '@volar/source-map': 2.4.26 + '@volar/source-map': 2.4.27 '@volar/source-map@2.4.15': {} - '@volar/source-map@2.4.26': {} + '@volar/source-map@2.4.27': {} '@volar/typescript@2.4.15': dependencies: @@ -11657,9 +11779,9 @@ snapshots: path-browserify: 1.0.1 vscode-uri: 3.1.0 - '@volar/typescript@2.4.26': + '@volar/typescript@2.4.27': dependencies: - '@volar/language-core': 2.4.26 + '@volar/language-core': 2.4.27 path-browserify: 1.0.1 vscode-uri: 3.1.0 @@ -11675,7 +11797,7 @@ snapshots: '@babel/types': 7.28.5 '@vue/babel-helper-vue-transform-on': 1.4.0 '@vue/babel-plugin-resolve-type': 1.4.0(@babel/core@7.28.5) - '@vue/shared': 3.5.25 + '@vue/shared': 3.5.26 optionalDependencies: '@babel/core': 7.28.5 transitivePeerDependencies: @@ -11708,6 +11830,14 @@ snapshots: estree-walker: 2.0.2 source-map-js: 1.2.1 + '@vue/compiler-core@3.5.26': + dependencies: + '@babel/parser': 7.28.5 + '@vue/shared': 3.5.26 + entities: 7.0.0 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + '@vue/compiler-dom@3.5.13': dependencies: '@vue/compiler-core': 3.5.13 @@ -11718,6 +11848,11 @@ snapshots: '@vue/compiler-core': 3.5.25 '@vue/shared': 3.5.25 + '@vue/compiler-dom@3.5.26': + dependencies: + '@vue/compiler-core': 3.5.26 + '@vue/shared': 3.5.26 + '@vue/compiler-sfc@3.5.13': dependencies: '@babel/parser': 7.28.5 @@ -11759,6 +11894,8 @@ snapshots: '@vue/devtools-api@6.6.3': {} + '@vue/devtools-api@6.6.4': {} + '@vue/devtools-core@8.0.5(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.2))(vue@3.5.13(typescript@5.9.3))': dependencies: '@vue/devtools-kit': 8.0.5 @@ -11799,10 +11936,10 @@ snapshots: '@vue/language-core@2.2.0(typescript@5.9.3)': dependencies: - '@volar/language-core': 2.4.26 - '@vue/compiler-dom': 3.5.25 + '@volar/language-core': 2.4.27 + '@vue/compiler-dom': 3.5.26 '@vue/compiler-vue2': 2.7.16 - '@vue/shared': 3.5.25 + '@vue/shared': 3.5.26 alien-signals: 0.4.14 minimatch: 9.0.5 muggle-string: 0.4.1 @@ -11813,9 +11950,9 @@ snapshots: '@vue/language-core@2.2.12(typescript@5.9.3)': dependencies: '@volar/language-core': 2.4.15 - '@vue/compiler-dom': 3.5.25 + '@vue/compiler-dom': 3.5.26 '@vue/compiler-vue2': 2.7.16 - '@vue/shared': 3.5.25 + '@vue/shared': 3.5.26 alien-signals: 1.0.13 minimatch: 9.0.5 muggle-string: 0.4.1 @@ -11823,17 +11960,15 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@vue/language-core@3.1.8(typescript@5.9.3)': + '@vue/language-core@3.2.1': dependencies: - '@volar/language-core': 2.4.26 - '@vue/compiler-dom': 3.5.25 - '@vue/shared': 3.5.25 - alien-signals: 3.1.1 + '@volar/language-core': 2.4.27 + '@vue/compiler-dom': 3.5.26 + '@vue/shared': 3.5.26 + alien-signals: 3.1.2 muggle-string: 0.4.1 path-browserify: 1.0.1 picomatch: 4.0.3 - optionalDependencies: - typescript: 5.9.3 '@vue/reactivity@3.5.13': dependencies: @@ -11861,6 +11996,8 @@ snapshots: '@vue/shared@3.5.25': {} + '@vue/shared@3.5.26': {} + '@vue/test-utils@2.4.6': dependencies: js-beautify: 1.15.1 @@ -12039,7 +12176,7 @@ snapshots: alien-signals@1.0.13: {} - alien-signals@3.1.1: {} + alien-signals@3.1.2: {} ansi-align@3.0.1: dependencies: @@ -12156,7 +12293,7 @@ snapshots: dependencies: tslib: 2.8.1 - ast-v8-to-istanbul@0.3.5: + ast-v8-to-istanbul@0.3.10: dependencies: '@jridgewell/trace-mapping': 0.3.31 estree-walker: 3.0.3 @@ -12835,6 +12972,8 @@ snapshots: entities@6.0.1: {} + entities@7.0.0: {} + env-paths@2.2.1: {} env-paths@3.0.0: {} @@ -13188,6 +13327,8 @@ snapshots: transitivePeerDependencies: - supports-color + esm-env@1.2.2: {} + esm-resolve@1.0.11: {} espree@10.4.0: @@ -13226,7 +13367,7 @@ snapshots: eventemitter3@5.0.1: {} - expect-type@1.2.2: {} + expect-type@1.3.0: {} exsolve@1.0.8: {} @@ -13553,7 +13694,7 @@ snapshots: globals@15.15.0: {} - globals@16.4.0: {} + globals@16.5.0: {} globalthis@1.0.4: dependencies: @@ -13587,7 +13728,7 @@ snapshots: section-matter: 1.0.0 strip-bom-string: 1.0.0 - happy-dom@15.11.0: + happy-dom@15.11.7: dependencies: entities: 4.5.0 webidl-conversions: 7.0.0 @@ -14051,7 +14192,7 @@ snapshots: http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 is-potential-custom-element-name: 1.0.1 - nwsapi: 2.2.21 + nwsapi: 2.2.23 parse5: 7.3.0 rrweb-cssom: 0.8.0 saxes: 6.0.0 @@ -14077,6 +14218,8 @@ snapshots: json-parse-even-better-errors@2.3.1: {} + json-rpc-2.0@1.7.1: {} + json-schema-traverse@0.4.1: {} json-schema-traverse@1.0.0: {} @@ -14314,7 +14457,7 @@ snapshots: lru-cache@10.4.3: {} - lru-cache@11.1.0: {} + lru-cache@11.2.4: {} lru-cache@5.1.1: dependencies: @@ -14837,7 +14980,7 @@ snapshots: dependencies: boolbase: 1.0.0 - nwsapi@2.2.21: {} + nwsapi@2.2.23: {} nx@22.2.4: dependencies: @@ -15183,7 +15326,7 @@ snapshots: path-scurry@2.0.0: dependencies: - lru-cache: 11.1.0 + lru-cache: 11.2.4 minipass: 7.1.2 path-type@4.0.0: {} @@ -15210,7 +15353,7 @@ snapshots: pinia@2.2.2(typescript@5.9.3)(vue@3.5.13(typescript@5.9.3)): dependencies: - '@vue/devtools-api': 6.6.3 + '@vue/devtools-api': 6.6.4 vue: 3.5.13(typescript@5.9.3) vue-demi: 0.14.10(vue@3.5.13(typescript@5.9.3)) optionalDependencies: @@ -15943,6 +16086,8 @@ snapshots: sprintf-js@1.0.3: {} + sqids@0.3.0: {} + stable-hash-x@0.2.0: {} stack-utils@2.0.6: @@ -15957,7 +16102,7 @@ snapshots: automation-events: 7.1.11 tslib: 2.8.1 - std-env@3.9.0: {} + std-env@3.10.0: {} stop-iteration-iterator@1.1.0: dependencies: @@ -16067,7 +16212,7 @@ snapshots: strip-json-comments@5.0.3: {} - strip-literal@3.0.0: + strip-literal@3.1.0: dependencies: js-tokens: 9.0.1 @@ -16076,7 +16221,7 @@ snapshots: stylelint@16.26.1(typescript@5.9.3): dependencies: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) - '@csstools/css-syntax-patches-for-csstree': 1.0.20 + '@csstools/css-syntax-patches-for-csstree': 1.0.22 '@csstools/css-tokenizer': 3.0.4 '@csstools/media-query-list-parser': 4.0.3(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.1) @@ -16247,6 +16392,16 @@ snapshots: dependencies: tldts-core: 6.1.86 + tmcp@1.19.0(typescript@5.9.3): + dependencies: + '@standard-schema/spec': 1.1.0 + json-rpc-2.0: 1.7.1 + sqids: 0.3.0 + uri-template-matcher: 1.1.2 + valibot: 1.2.0(typescript@5.9.3) + transitivePeerDependencies: + - typescript + tmp@0.2.5: {} to-regex-range@5.0.1: @@ -16542,6 +16697,8 @@ snapshots: dependencies: punycode: 2.3.1 + uri-template-matcher@1.1.2: {} + use-sync-external-store@1.6.0(react@19.2.3): dependencies: react: 19.2.3 @@ -16552,6 +16709,10 @@ snapshots: uuid@11.1.0: {} + valibot@1.2.0(typescript@5.9.3): + optionalDependencies: + typescript: 5.9.3 + vfile-message@4.0.3: dependencies: '@types/unist': 3.0.3 @@ -16607,7 +16768,7 @@ snapshots: dependencies: '@microsoft/api-extractor': 7.52.13(@types/node@24.10.4) '@rollup/pluginutils': 5.3.0(rollup@4.53.5) - '@volar/typescript': 2.4.26 + '@volar/typescript': 2.4.27 '@vue/language-core': 2.2.0(typescript@5.9.3) compare-versions: 6.1.1 debug: 4.4.3 @@ -16720,7 +16881,7 @@ snapshots: '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.28.5) '@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.28.5) '@vue/babel-plugin-jsx': 1.4.0(@babel/core@7.28.5) - '@vue/compiler-dom': 3.5.25 + '@vue/compiler-dom': 3.5.26 kolorist: 1.8.0 magic-string: 0.30.21 vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.2) @@ -16735,7 +16896,7 @@ snapshots: '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.28.5) '@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.28.5) '@vue/babel-plugin-jsx': 1.4.0(@babel/core@7.28.5) - '@vue/compiler-dom': 3.5.25 + '@vue/compiler-dom': 3.5.26 kolorist: 1.8.0 magic-string: 0.30.21 vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.2) @@ -16776,7 +16937,7 @@ snapshots: tsx: 4.19.4 yaml: 2.8.2 - vitest@3.2.4(@types/debug@4.1.12)(@types/node@24.10.4)(@vitest/ui@3.2.4)(happy-dom@15.11.0)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.1)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.2): + vitest@3.2.4(@types/debug@4.1.12)(@types/node@24.10.4)(@vitest/ui@3.2.4)(happy-dom@15.11.7)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.1)(terser@5.39.2)(tsx@4.19.4)(yaml@2.8.2): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 @@ -16788,11 +16949,11 @@ snapshots: '@vitest/utils': 3.2.4 chai: 5.3.3 debug: 4.4.3 - expect-type: 1.2.2 + expect-type: 1.3.0 magic-string: 0.30.21 pathe: 2.0.3 picomatch: 4.0.3 - std-env: 3.9.0 + std-env: 3.10.0 tinybench: 2.9.0 tinyexec: 0.3.2 tinyglobby: 0.2.15 @@ -16805,7 +16966,7 @@ snapshots: '@types/debug': 4.1.12 '@types/node': 24.10.4 '@vitest/ui': 3.2.4(vitest@3.2.4) - happy-dom: 15.11.0 + happy-dom: 15.11.7 jsdom: 26.1.0 transitivePeerDependencies: - jiti @@ -16836,7 +16997,7 @@ snapshots: vue-component-type-helpers@2.2.12: {} - vue-component-type-helpers@3.1.8: {} + vue-component-type-helpers@3.2.2: {} vue-demi@0.14.10(vue@3.5.13(typescript@5.9.3)): dependencies: @@ -16846,7 +17007,7 @@ snapshots: dependencies: '@babel/parser': 7.28.5 '@babel/types': 7.28.5 - '@vue/compiler-dom': 3.5.25 + '@vue/compiler-dom': 3.5.26 '@vue/compiler-sfc': 3.5.25 ast-types: 0.16.1 esm-resolve: 1.0.11 @@ -16886,10 +17047,10 @@ snapshots: '@vue/devtools-api': 6.6.3 vue: 3.5.13(typescript@5.9.3) - vue-tsc@3.1.8(typescript@5.9.3): + vue-tsc@3.2.1(typescript@5.9.3): dependencies: - '@volar/typescript': 2.4.26 - '@vue/language-core': 3.1.8(typescript@5.9.3) + '@volar/typescript': 2.4.27 + '@vue/language-core': 3.2.1 typescript: 5.9.3 vue@3.5.13(typescript@5.9.3): diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 589020fe0ef..3594fac16fd 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -29,6 +29,7 @@ catalog: '@sentry/vue': ^8.48.0 '@sparkjsdev/spark': ^0.1.10 '@storybook/addon-docs': ^10.1.9 + '@storybook/addon-mcp': 0.1.6 '@storybook/vue3': ^10.1.9 '@storybook/vue3-vite': ^10.1.9 '@tailwindcss/vite': ^4.1.12 diff --git a/src/components/honeyToast/HoneyToast.stories.ts b/src/components/honeyToast/HoneyToast.stories.ts new file mode 100644 index 00000000000..98ae5907004 --- /dev/null +++ b/src/components/honeyToast/HoneyToast.stories.ts @@ -0,0 +1,292 @@ +import type { Meta, StoryObj } from '@storybook/vue3-vite' +import { ref } from 'vue' + +import ProgressToastItem from '@/components/toast/ProgressToastItem.vue' +import Button from '@/components/ui/button/Button.vue' +import type { AssetDownload } from '@/stores/assetDownloadStore' +import { cn } from '@/utils/tailwindUtil' + +import HoneyToast from './HoneyToast.vue' + +function createMockJob(overrides: Partial = {}): AssetDownload { + return { + taskId: 'task-1', + assetId: 'asset-1', + assetName: 'model-v1.safetensors', + bytesTotal: 1000000, + bytesDownloaded: 0, + progress: 0, + status: 'created', + ...overrides + } +} + +const meta: Meta = { + title: 'Toast/HoneyToast', + component: HoneyToast, + parameters: { + layout: 'fullscreen' + }, + decorators: [ + () => ({ + template: '
' + }) + ] +} + +export default meta +type Story = StoryObj + +export const Default: Story = { + render: () => ({ + components: { HoneyToast, Button, ProgressToastItem }, + setup() { + const isExpanded = ref(false) + const jobs = [ + createMockJob({ + taskId: 'task-1', + assetName: 'model-v1.safetensors', + status: 'completed', + progress: 1 + }), + createMockJob({ + taskId: 'task-2', + assetName: 'lora-style.safetensors', + status: 'running', + progress: 0.45 + }), + createMockJob({ + taskId: 'task-3', + assetName: 'vae-decoder.safetensors', + status: 'created' + }) + ] + return { isExpanded, cn, jobs } + }, + template: ` + + + + + + ` + }) +} + +export const Expanded: Story = { + render: () => ({ + components: { HoneyToast, Button, ProgressToastItem }, + setup() { + const isExpanded = ref(true) + const jobs = [ + createMockJob({ + taskId: 'task-1', + assetName: 'model-v1.safetensors', + status: 'completed', + progress: 1 + }), + createMockJob({ + taskId: 'task-2', + assetName: 'lora-style.safetensors', + status: 'running', + progress: 0.45 + }), + createMockJob({ + taskId: 'task-3', + assetName: 'vae-decoder.safetensors', + status: 'created' + }) + ] + return { isExpanded, cn, jobs } + }, + template: ` + + + + + + ` + }) +} + +export const Completed: Story = { + render: () => ({ + components: { HoneyToast, Button, ProgressToastItem }, + setup() { + const isExpanded = ref(false) + const jobs = [ + createMockJob({ + taskId: 'task-1', + assetName: 'model-v1.safetensors', + bytesDownloaded: 1000000, + progress: 1, + status: 'completed' + }), + createMockJob({ + taskId: 'task-2', + assetId: 'asset-2', + assetName: 'lora-style.safetensors', + bytesTotal: 500000, + bytesDownloaded: 500000, + progress: 1, + status: 'completed' + }) + ] + return { isExpanded, cn, jobs } + }, + template: ` + + + + + + ` + }) +} + +export const WithError: Story = { + render: () => ({ + components: { HoneyToast, Button, ProgressToastItem }, + setup() { + const isExpanded = ref(true) + const jobs = [ + createMockJob({ + taskId: 'task-1', + assetName: 'model-v1.safetensors', + status: 'failed', + progress: 0.23 + }), + createMockJob({ + taskId: 'task-2', + assetName: 'lora-style.safetensors', + status: 'completed', + progress: 1 + }) + ] + return { isExpanded, cn, jobs } + }, + template: ` + + + + + + ` + }) +} + +export const Hidden: Story = { + render: () => ({ + components: { HoneyToast }, + template: ` +
+

HoneyToast is hidden when visible=false. Nothing appears at the bottom.

+ + + + + +
+ ` + }) +} diff --git a/src/components/honeyToast/HoneyToast.test.ts b/src/components/honeyToast/HoneyToast.test.ts new file mode 100644 index 00000000000..ada1230531a --- /dev/null +++ b/src/components/honeyToast/HoneyToast.test.ts @@ -0,0 +1,137 @@ +import type { VueWrapper } from '@vue/test-utils' +import { mount } from '@vue/test-utils' +import { beforeEach, describe, expect, it, vi } from 'vitest' +import { defineComponent, h, nextTick, ref } from 'vue' + +import HoneyToast from './HoneyToast.vue' + +describe('HoneyToast', () => { + beforeEach(() => { + vi.clearAllMocks() + document.body.innerHTML = '' + }) + + function mountComponent( + props: { visible: boolean; expanded?: boolean } = { visible: true } + ): VueWrapper { + return mount(HoneyToast, { + props, + slots: { + default: (slotProps: { isExpanded: boolean }) => + h( + 'div', + { 'data-testid': 'content' }, + slotProps.isExpanded ? 'expanded' : 'collapsed' + ), + footer: (slotProps: { isExpanded: boolean; toggle: () => void }) => + h( + 'button', + { + 'data-testid': 'toggle-btn', + onClick: slotProps.toggle + }, + slotProps.isExpanded ? 'Collapse' : 'Expand' + ) + }, + attachTo: document.body + }) + } + + it('renders when visible is true', async () => { + const wrapper = mountComponent({ visible: true }) + await nextTick() + + const toast = document.body.querySelector('[role="status"]') + expect(toast).toBeTruthy() + + wrapper.unmount() + }) + + it('does not render when visible is false', async () => { + const wrapper = mountComponent({ visible: false }) + await nextTick() + + const toast = document.body.querySelector('[role="status"]') + expect(toast).toBeFalsy() + + wrapper.unmount() + }) + + it('passes is-expanded=false to slots by default', async () => { + const wrapper = mountComponent({ visible: true }) + await nextTick() + + const content = document.body.querySelector('[data-testid="content"]') + expect(content?.textContent).toBe('collapsed') + + wrapper.unmount() + }) + + it('applies collapsed max-height class when collapsed', async () => { + const wrapper = mountComponent({ visible: true, expanded: false }) + await nextTick() + + const expandableArea = document.body.querySelector( + '[role="status"] > div:first-child' + ) + expect(expandableArea?.classList.contains('max-h-0')).toBe(true) + + wrapper.unmount() + }) + + it('has aria-live="polite" for accessibility', async () => { + const wrapper = mountComponent({ visible: true }) + await nextTick() + + const toast = document.body.querySelector('[role="status"]') + expect(toast?.getAttribute('aria-live')).toBe('polite') + + wrapper.unmount() + }) + + it('supports v-model:expanded with reactive parent state', async () => { + const TestWrapper = defineComponent({ + components: { HoneyToast }, + setup() { + const expanded = ref(false) + return { expanded } + }, + template: ` + + + + + ` + }) + + const wrapper = mount(TestWrapper, { attachTo: document.body }) + await nextTick() + + const content = document.body.querySelector('[data-testid="content"]') + expect(content?.textContent).toBe('collapsed') + + const toggleBtn = document.body.querySelector( + '[data-testid="toggle-btn"]' + ) as HTMLButtonElement + expect(toggleBtn?.textContent?.trim()).toBe('Expand') + + toggleBtn?.click() + await nextTick() + + expect(content?.textContent).toBe('expanded') + expect(toggleBtn?.textContent?.trim()).toBe('Collapse') + + const expandableArea = document.body.querySelector( + '[role="status"] > div:first-child' + ) + expect(expandableArea?.classList.contains('max-h-[400px]')).toBe(true) + + wrapper.unmount() + }) +}) diff --git a/src/components/honeyToast/HoneyToast.vue b/src/components/honeyToast/HoneyToast.vue new file mode 100644 index 00000000000..4da85ce9546 --- /dev/null +++ b/src/components/honeyToast/HoneyToast.vue @@ -0,0 +1,46 @@ + + + diff --git a/src/components/toast/ProgressToastItem.stories.ts b/src/components/toast/ProgressToastItem.stories.ts new file mode 100644 index 00000000000..2ad376a7275 --- /dev/null +++ b/src/components/toast/ProgressToastItem.stories.ts @@ -0,0 +1,94 @@ +import type { Meta, StoryObj } from '@storybook/vue3-vite' + +import type { AssetDownload } from '@/stores/assetDownloadStore' + +import ProgressToastItem from './ProgressToastItem.vue' + +const meta: Meta = { + title: 'Toast/ProgressToastItem', + component: ProgressToastItem, + parameters: { + layout: 'padded' + }, + decorators: [ + () => ({ + template: '
' + }) + ] +} + +export default meta +type Story = StoryObj + +function createMockJob(overrides: Partial = {}): AssetDownload { + return { + taskId: 'task-1', + assetId: 'asset-1', + assetName: 'model-v1.safetensors', + bytesTotal: 1000000, + bytesDownloaded: 0, + progress: 0, + status: 'created', + ...overrides + } +} + +export const Pending: Story = { + args: { + job: createMockJob({ + status: 'created', + assetName: 'sd-xl-base-1.0.safetensors' + }) + } +} + +export const Running: Story = { + args: { + job: createMockJob({ + status: 'running', + progress: 0.45, + assetName: 'lora-detail-enhancer.safetensors' + }) + } +} + +export const RunningAlmostComplete: Story = { + args: { + job: createMockJob({ + status: 'running', + progress: 0.92, + assetName: 'vae-ft-mse-840000.safetensors' + }) + } +} + +export const Completed: Story = { + args: { + job: createMockJob({ + status: 'completed', + progress: 1, + assetName: 'controlnet-canny.safetensors' + }) + } +} + +export const Failed: Story = { + args: { + job: createMockJob({ + status: 'failed', + progress: 0.23, + assetName: 'unreachable-model.safetensors' + }) + } +} + +export const LongFileName: Story = { + args: { + job: createMockJob({ + status: 'running', + progress: 0.67, + assetName: + 'very-long-model-name-with-lots-of-descriptive-text-v2.1-final-release.safetensors' + }) + } +} diff --git a/src/components/toast/ProgressToastItem.vue b/src/components/toast/ProgressToastItem.vue index 495af2e2415..80869d8f91c 100644 --- a/src/components/toast/ProgressToastItem.vue +++ b/src/components/toast/ProgressToastItem.vue @@ -30,9 +30,7 @@ const isPending = computed(() => job.status === 'created') >
{{ job.assetName }} - - {{ progressPercent }}% - +
@@ -49,9 +47,9 @@ const isPending = computed(() => job.status === 'created') diff --git a/src/composables/useCoreCommands.ts b/src/composables/useCoreCommands.ts index 843e9faadeb..a8015bb4c20 100644 --- a/src/composables/useCoreCommands.ts +++ b/src/composables/useCoreCommands.ts @@ -881,15 +881,6 @@ export function useCoreCommands(): ComfyCommand[] { }) } }, - { - id: 'Comfy.Manager.ToggleManagerProgressDialog', - icon: 'pi pi-spinner', - label: 'Toggle the Custom Nodes Manager Progress Bar', - versionAdded: '1.13.9', - function: () => { - dialogService.toggleManagerProgressDialog() - } - }, { id: 'Comfy.User.OpenSignInDialog', icon: 'pi pi-user', diff --git a/src/platform/assets/components/ModelImportProgressDialog.vue b/src/platform/assets/components/ModelImportProgressDialog.vue index d5f8c866657..b9191526f94 100644 --- a/src/platform/assets/components/ModelImportProgressDialog.vue +++ b/src/platform/assets/components/ModelImportProgressDialog.vue @@ -1,8 +1,10 @@ diff --git a/src/services/dialogService.ts b/src/services/dialogService.ts index c8a97d71733..ca72edd83c2 100644 --- a/src/services/dialogService.ts +++ b/src/services/dialogService.ts @@ -25,9 +25,7 @@ import type { DialogComponentProps, ShowDialogOptions } from '@/stores/dialogStore' -import ManagerProgressDialogContent from '@/workbench/extensions/manager/components/ManagerProgressDialogContent.vue' -import ManagerProgressFooter from '@/workbench/extensions/manager/components/ManagerProgressFooter.vue' -import ManagerProgressHeader from '@/workbench/extensions/manager/components/ManagerProgressHeader.vue' + import ManagerDialogContent from '@/workbench/extensions/manager/components/manager/ManagerDialogContent.vue' import ManagerHeader from '@/workbench/extensions/manager/components/manager/ManagerHeader.vue' import NodeConflictDialogContent from '@/workbench/extensions/manager/components/manager/NodeConflictDialogContent.vue' @@ -229,30 +227,6 @@ export const useDialogService = () => { }) } - function showManagerProgressDialog(options?: { - props?: InstanceType['$props'] - }) { - return dialogStore.showDialog({ - key: 'global-manager-progress-dialog', - component: ManagerProgressDialogContent, - headerComponent: ManagerProgressHeader, - footerComponent: ManagerProgressFooter, - props: options?.props, - priority: 2, - dialogComponentProps: { - closable: false, - modal: false, - position: 'bottom', - pt: { - root: { class: 'w-[80%] max-w-2xl mx-auto border-none' }, - content: { class: 'p-0!' }, - header: { class: 'p-0! border-none' }, - footer: { class: 'p-0! border-none' } - } - } - }) - } - /** * Shows a dialog requiring sign in for API nodes * @returns Promise that resolves to true if user clicks login, false if cancelled @@ -440,16 +414,6 @@ export const useDialogService = () => { } } - function toggleManagerProgressDialog( - props?: ComponentAttrs - ) { - if (dialogStore.isDialogOpen('global-manager-progress-dialog')) { - dialogStore.closeDialog({ key: 'global-manager-progress-dialog' }) - } else { - showManagerProgressDialog({ props }) - } - } - function showLayoutDialog(options: { key: string component: Component @@ -548,7 +512,6 @@ export const useDialogService = () => { showAboutDialog, showExecutionErrorDialog, showManagerDialog, - showManagerProgressDialog, showApiNodesSignInDialog, showSignInDialog, showSubscriptionRequiredDialog, @@ -559,7 +522,6 @@ export const useDialogService = () => { showErrorDialog, confirm, toggleManagerDialog, - toggleManagerProgressDialog, showLayoutDialog, showNodeConflictDialog } diff --git a/src/stores/README.md b/src/stores/README.md index a24a106e57d..a3cc0ae5f3a 100644 --- a/src/stores/README.md +++ b/src/stores/README.md @@ -109,7 +109,6 @@ The following table lists ALL 46 store instances in the system as of 2025-09-01: | aboutPanelStore.ts | useAboutPanelStore | Manages the About panel state and badges | UI | | apiKeyAuthStore.ts | useApiKeyAuthStore | Handles API key authentication | Auth | | comfyManagerStore.ts | useComfyManagerStore | Manages ComfyUI application state | Core | -| comfyManagerStore.ts | useManagerProgressDialogStore | Manages manager progress dialog state | UI | | comfyRegistryStore.ts | useComfyRegistryStore | Handles extensions registry | Registry | | commandStore.ts | useCommandStore | Manages commands and command execution | Core | | dialogStore.ts | useDialogStore | Controls dialog/modal display and state | UI | diff --git a/src/views/GraphView.vue b/src/views/GraphView.vue index e9525708348..e60df5692ad 100644 --- a/src/views/GraphView.vue +++ b/src/views/GraphView.vue @@ -18,6 +18,7 @@ + @@ -80,6 +81,7 @@ import { useSidebarTabStore } from '@/stores/workspace/sidebarTabStore' import { useWorkspaceStore } from '@/stores/workspaceStore' import { electronAPI, isElectron } from '@/utils/envUtil' import LinearView from '@/views/LinearView.vue' +import ManagerProgressToast from '@/workbench/extensions/manager/components/ManagerProgressToast.vue' setupAutoQueueHandler() useProgressFavicon() diff --git a/src/workbench/extensions/manager/components/ManagerProgressDialogContent.test.ts b/src/workbench/extensions/manager/components/ManagerProgressDialogContent.test.ts deleted file mode 100644 index b53e0fbece8..00000000000 --- a/src/workbench/extensions/manager/components/ManagerProgressDialogContent.test.ts +++ /dev/null @@ -1,186 +0,0 @@ -import type { VueWrapper } from '@vue/test-utils' -import { mount } from '@vue/test-utils' -import { createPinia } from 'pinia' -import Button from '@/components/ui/button/Button.vue' -import PrimeVue from 'primevue/config' -import Panel from 'primevue/panel' -import { beforeEach, describe, expect, it, vi } from 'vitest' -import { nextTick } from 'vue' -import { createI18n } from 'vue-i18n' - -import enMessages from '@/locales/en/main.json' with { type: 'json' } - -import ManagerProgressDialogContent from './ManagerProgressDialogContent.vue' - -type ComponentInstance = InstanceType & { - lastPanelRef: HTMLElement | null - onLogsAdded: () => void - handleScroll: (e: { target: HTMLElement }) => void - isUserScrolling: boolean - resetUserScrolling: () => void - collapsedPanels: Record - togglePanel: (index: number) => void -} - -const mockCollapse = vi.fn() - -const defaultMockTaskLogs = [ - { taskName: 'Task 1', logs: ['Log 1', 'Log 2'] }, - { taskName: 'Task 2', logs: ['Log 3', 'Log 4'] } -] - -vi.mock('@/workbench/extensions/manager/stores/comfyManagerStore', () => ({ - useComfyManagerStore: vi.fn(() => ({ - taskLogs: [...defaultMockTaskLogs], - succeededTasksLogs: [...defaultMockTaskLogs], - failedTasksLogs: [...defaultMockTaskLogs], - managerQueue: { historyCount: 2 }, - isLoading: false - })), - useManagerProgressDialogStore: vi.fn(() => ({ - isExpanded: true, - activeTabIndex: 0, - getActiveTabIndex: vi.fn(() => 0), - setActiveTabIndex: vi.fn(), - toggle: vi.fn(), - collapse: mockCollapse, - expand: vi.fn() - })) -})) - -describe('ManagerProgressDialogContent', () => { - beforeEach(() => { - vi.clearAllMocks() - mockCollapse.mockReset() - }) - - const mountComponent = ({ - props = {} - }: Record = {}): VueWrapper => { - const i18n = createI18n({ - legacy: false, - locale: 'en', - messages: { en: enMessages } - }) - - return mount(ManagerProgressDialogContent, { - props: { - ...props - }, - global: { - plugins: [PrimeVue, createPinia(), i18n], - components: { - Panel, - Button - } - } - }) as VueWrapper - } - - it('renders the correct number of panels', async () => { - const wrapper = mountComponent() - await nextTick() - expect(wrapper.findAllComponents(Panel).length).toBe(2) - }) - - it('expands the last panel by default', async () => { - const wrapper = mountComponent() - await nextTick() - expect(wrapper.vm.collapsedPanels[1]).toBeFalsy() - }) - - it('toggles panel expansion when toggle method is called', async () => { - const wrapper = mountComponent() - await nextTick() - - // Initial state - first panel should be collapsed - expect(wrapper.vm.collapsedPanels[0]).toBeFalsy() - - wrapper.vm.togglePanel(0) - await nextTick() - - // After toggle - first panel should be expanded - expect(wrapper.vm.collapsedPanels[0]).toBe(true) - - wrapper.vm.togglePanel(0) - await nextTick() - - expect(wrapper.vm.collapsedPanels[0]).toBeFalsy() - }) - - it('displays the correct status for each panel', async () => { - const wrapper = mountComponent() - await nextTick() - - // Expand all panels to see status text - const panels = wrapper.findAllComponents(Panel) - for (let i = 0; i < panels.length; i++) { - if (!wrapper.vm.collapsedPanels[i]) { - wrapper.vm.togglePanel(i) - await nextTick() - } - } - - const panelsText = wrapper - .findAllComponents(Panel) - .map((panel) => panel.text()) - - expect(panelsText[0]).toContain('Completed ✓') - expect(panelsText[1]).toContain('Completed ✓') - }) - - it('auto-scrolls to bottom when new logs are added', async () => { - const wrapper = mountComponent() - await nextTick() - - const mockScrollElement = document.createElement('div') - Object.defineProperty(mockScrollElement, 'scrollHeight', { value: 200 }) - Object.defineProperty(mockScrollElement, 'clientHeight', { value: 100 }) - Object.defineProperty(mockScrollElement, 'scrollTop', { - value: 0, - writable: true - }) - - wrapper.vm.lastPanelRef = mockScrollElement - - wrapper.vm.onLogsAdded() - await nextTick() - - // Check if scrollTop is set to scrollHeight (scrolled to bottom) - expect(mockScrollElement.scrollTop).toBe(200) - }) - - it('does not auto-scroll when user is manually scrolling', async () => { - const wrapper = mountComponent() - await nextTick() - - const mockScrollElement = document.createElement('div') - Object.defineProperty(mockScrollElement, 'scrollHeight', { value: 200 }) - Object.defineProperty(mockScrollElement, 'clientHeight', { value: 100 }) - Object.defineProperty(mockScrollElement, 'scrollTop', { - value: 50, - writable: true - }) - - wrapper.vm.lastPanelRef = mockScrollElement - - wrapper.vm.handleScroll({ target: mockScrollElement }) - await nextTick() - - expect(wrapper.vm.isUserScrolling).toBe(true) - - // Now trigger the log update - wrapper.vm.onLogsAdded() - await nextTick() - - // Check that scrollTop is not changed (should still be 50) - expect(mockScrollElement.scrollTop).toBe(50) - }) - - it('calls collapse method when component is unmounted', async () => { - const wrapper = mountComponent() - await nextTick() - wrapper.unmount() - expect(mockCollapse).toHaveBeenCalled() - }) -}) diff --git a/src/workbench/extensions/manager/components/ManagerProgressDialogContent.vue b/src/workbench/extensions/manager/components/ManagerProgressDialogContent.vue deleted file mode 100644 index 14280dfad77..00000000000 --- a/src/workbench/extensions/manager/components/ManagerProgressDialogContent.vue +++ /dev/null @@ -1,182 +0,0 @@ - - - diff --git a/src/workbench/extensions/manager/components/ManagerProgressFooter.vue b/src/workbench/extensions/manager/components/ManagerProgressFooter.vue deleted file mode 100644 index f8fe0052d63..00000000000 --- a/src/workbench/extensions/manager/components/ManagerProgressFooter.vue +++ /dev/null @@ -1,195 +0,0 @@ - - - diff --git a/src/workbench/extensions/manager/components/ManagerProgressHeader.vue b/src/workbench/extensions/manager/components/ManagerProgressHeader.vue deleted file mode 100644 index 686d43436e6..00000000000 --- a/src/workbench/extensions/manager/components/ManagerProgressHeader.vue +++ /dev/null @@ -1,44 +0,0 @@ - - - diff --git a/src/workbench/extensions/manager/components/ManagerProgressToast.vue b/src/workbench/extensions/manager/components/ManagerProgressToast.vue new file mode 100644 index 00000000000..3e6305b7e96 --- /dev/null +++ b/src/workbench/extensions/manager/components/ManagerProgressToast.vue @@ -0,0 +1,353 @@ + + + diff --git a/src/workbench/extensions/manager/composables/useManagerQueue.ts b/src/workbench/extensions/manager/composables/useManagerQueue.ts index 3886b40bf82..7ac796414fe 100644 --- a/src/workbench/extensions/manager/composables/useManagerQueue.ts +++ b/src/workbench/extensions/manager/composables/useManagerQueue.ts @@ -4,7 +4,6 @@ import type { Ref } from 'vue' import { computed, ref } from 'vue' import { app } from '@/scripts/app' -import { useDialogService } from '@/services/dialogService' import { normalizePackKeys } from '@/utils/packUtils' import type { components } from '@/workbench/extensions/manager/types/generatedManagerTypes' @@ -27,8 +26,6 @@ export const useManagerQueue = ( taskQueue: Ref, installedPacks: Ref> ) => { - const { showManagerProgressDialog } = useDialogService() - // Task queue state (read-only from server) const maxHistoryItems = ref(64) const isLoading = ref(false) @@ -113,15 +110,6 @@ export const useManagerQueue = ( (event: CustomEvent) => { if (event?.type === MANAGER_WS_TASK_DONE_NAME && event.detail?.state) { updateTaskState(event.detail.state) - - // If no more tasks are running/pending, hide the progress dialog - if (allTasksDone.value) { - setTimeout(() => { - if (allTasksDone.value) { - showManagerProgressDialog() - } - }, 1000) // Small delay to let users see completion - } } } ) @@ -133,9 +121,6 @@ export const useManagerQueue = ( (event: CustomEvent) => { if (event?.type === MANAGER_WS_TASK_STARTED_NAME && event.detail?.state) { updateTaskState(event.detail.state) - - // Show progress dialog when a task starts - showManagerProgressDialog() } } ) diff --git a/src/workbench/extensions/manager/stores/comfyManagerStore.ts b/src/workbench/extensions/manager/stores/comfyManagerStore.ts index 06097cbe739..df6df758a6f 100644 --- a/src/workbench/extensions/manager/stores/comfyManagerStore.ts +++ b/src/workbench/extensions/manager/stores/comfyManagerStore.ts @@ -8,7 +8,7 @@ import { useCachedRequest } from '@/composables/useCachedRequest' import { useServerLogs } from '@/composables/useServerLogs' import { api } from '@/scripts/api' import { app } from '@/scripts/app' -import { useDialogService } from '@/services/dialogService' + import { normalizePackKeys } from '@/utils/packUtils' import { useManagerQueue } from '@/workbench/extensions/manager/composables/useManagerQueue' import { useComfyManagerService } from '@/workbench/extensions/manager/services/comfyManagerService' @@ -32,7 +32,6 @@ type UpdateAllPacksParams = components['schemas']['UpdateAllPacksParams'] export const useComfyManagerStore = defineStore('comfyManager', () => { const { t } = useI18n() const managerService = useComfyManagerService() - const { showManagerProgressDialog } = useDialogService() const installedPacks = ref({}) const enabledPacksIds = ref>(new Set()) @@ -204,8 +203,6 @@ export const useComfyManagerStore = defineStore('comfyManager', () => { }) try { - // Show progress dialog immediately when task is queued - showManagerProgressDialog() managerQueue.isProcessing.value = true // Prepare logging hook @@ -392,44 +389,3 @@ export const useComfyManagerStore = defineStore('comfyManager', () => { enablePack } }) - -/** - * Store for state of the manager progress dialog content. - * The dialog itself is managed by the dialog store. This store is used to - * manage the visibility of the dialog's content, header, footer. - */ -export const useManagerProgressDialogStore = defineStore( - 'managerProgressDialog', - () => { - const isExpanded = ref(false) - const activeTabIndex = ref(0) - - const setActiveTabIndex = (index: number) => { - activeTabIndex.value = index - } - - const getActiveTabIndex = () => { - return activeTabIndex.value - } - - const toggle = () => { - isExpanded.value = !isExpanded.value - } - - const collapse = () => { - isExpanded.value = false - } - - const expand = () => { - isExpanded.value = true - } - return { - isExpanded, - toggle, - collapse, - expand, - setActiveTabIndex, - getActiveTabIndex - } - } -) diff --git a/tests-ui/tests/components/dialog/footer/ManagerProgressFooter.test.ts b/tests-ui/tests/components/dialog/footer/ManagerProgressFooter.test.ts deleted file mode 100644 index 024e025b836..00000000000 --- a/tests-ui/tests/components/dialog/footer/ManagerProgressFooter.test.ts +++ /dev/null @@ -1,486 +0,0 @@ -import { mount } from '@vue/test-utils' -import { createPinia, setActivePinia } from 'pinia' -import PrimeVue from 'primevue/config' -import { beforeEach, describe, expect, it, vi } from 'vitest' -import { nextTick } from 'vue' -import { createI18n } from 'vue-i18n' - -import { useSettingStore } from '@/platform/settings/settingStore' -import { useCommandStore } from '@/stores/commandStore' -import { useDialogStore } from '@/stores/dialogStore' -import ManagerProgressFooter from '@/workbench/extensions/manager/components/ManagerProgressFooter.vue' -import { useComfyManagerService } from '@/workbench/extensions/manager/services/comfyManagerService' -import { - useComfyManagerStore, - useManagerProgressDialogStore -} from '@/workbench/extensions/manager/stores/comfyManagerStore' -import type { TaskLog } from '@/workbench/extensions/manager/types/comfyManagerTypes' - -// Mock modules -vi.mock('@/workbench/extensions/manager/stores/comfyManagerStore') -vi.mock('@/stores/dialogStore') -vi.mock('@/platform/settings/settingStore') -vi.mock('@/stores/commandStore') -vi.mock('@/workbench/extensions/manager/services/comfyManagerService') -vi.mock( - '@/workbench/extensions/manager/composables/useConflictDetection', - () => ({ - useConflictDetection: vi.fn(() => ({ - conflictedPackages: { value: [] }, - runFullConflictAnalysis: vi.fn().mockResolvedValue(undefined) - })) - }) -) - -// Mock useEventListener to capture the event handler -let reconnectHandler: (() => void) | null = null -vi.mock('@vueuse/core', async () => { - const actual = await vi.importActual('@vueuse/core') - return { - ...actual, - useEventListener: vi.fn( - (_target: any, event: string, handler: any, _options: any) => { - if (event === 'reconnected') { - reconnectHandler = handler - } - } - ) - } -}) -vi.mock('@/platform/workflow/core/services/workflowService', () => ({ - useWorkflowService: vi.fn(() => ({ - reloadCurrentWorkflow: vi.fn().mockResolvedValue(undefined) - })) -})) -vi.mock('@/stores/workspace/colorPaletteStore', () => ({ - useColorPaletteStore: vi.fn(() => ({ - completedActivePalette: { - light_theme: false - } - })) -})) - -// Helper function to mount component with required setup -const mountComponent = (options: { captureError?: boolean } = {}) => { - const pinia = createPinia() - setActivePinia(pinia) - - const i18n = createI18n({ - legacy: false, - locale: 'en', - messages: { - en: { - g: { - close: 'Close', - progressCountOf: 'of' - }, - contextMenu: { - Collapse: 'Collapse', - Expand: 'Expand' - }, - manager: { - clickToFinishSetup: 'Click', - applyChanges: 'Apply Changes', - toFinishSetup: 'to finish setup', - restartingBackend: 'Restarting backend to apply changes...', - extensionsSuccessfullyInstalled: - 'Extension(s) successfully installed and are ready to use!', - restartToApplyChanges: 'To apply changes, please restart ComfyUI', - installingDependencies: 'Installing dependencies...' - } - } - } - }) - - const config: any = { - global: { - plugins: [pinia, PrimeVue, i18n] - } - } - - // Add error handler for tests that expect errors - if (options.captureError) { - config.global.config = { - errorHandler: () => { - // Suppress error in test - } - } - } - - return mount(ManagerProgressFooter, config) -} - -describe('ManagerProgressFooter', () => { - const mockTaskLogs: TaskLog[] = [] - - const mockComfyManagerStore = { - taskLogs: mockTaskLogs, - allTasksDone: true, - isProcessingTasks: false, - succeededTasksIds: [] as string[], - failedTasksIds: [] as string[], - taskHistory: {} as Record, - taskQueue: null, - resetTaskState: vi.fn(), - clearLogs: vi.fn(), - setStale: vi.fn(), - // Add other required properties - isLoading: { value: false }, - error: { value: null }, - statusMessage: { value: 'DONE' }, - installedPacks: {}, - installedPacksIds: new Set(), - isPackInstalled: vi.fn(), - isPackEnabled: vi.fn(), - getInstalledPackVersion: vi.fn(), - refreshInstalledList: vi.fn(), - installPack: vi.fn(), - uninstallPack: vi.fn(), - updatePack: vi.fn(), - updateAllPacks: vi.fn(), - disablePack: vi.fn(), - enablePack: vi.fn() - } - - const mockDialogStore = { - closeDialog: vi.fn(), - // Add other required properties - dialogStack: { value: [] }, - showDialog: vi.fn(), - $id: 'dialog', - $state: {} as any, - $patch: vi.fn(), - $reset: vi.fn(), - $subscribe: vi.fn(), - $dispose: vi.fn(), - $onAction: vi.fn() - } - - const mockSettingStore = { - get: vi.fn().mockReturnValue(false), - set: vi.fn(), - // Add other required properties - settingValues: { value: {} }, - settingsById: { value: {} }, - exists: vi.fn(), - getDefaultValue: vi.fn(), - loadSettingValues: vi.fn(), - updateValue: vi.fn(), - $id: 'setting', - $state: {} as any, - $patch: vi.fn(), - $reset: vi.fn(), - $subscribe: vi.fn(), - $dispose: vi.fn(), - $onAction: vi.fn() - } - - const mockProgressDialogStore = { - isExpanded: false, - toggle: vi.fn(), - collapse: vi.fn(), - expand: vi.fn() - } - - const mockCommandStore = { - execute: vi.fn().mockResolvedValue(undefined) - } - - const mockComfyManagerService = { - rebootComfyUI: vi.fn().mockResolvedValue(null) - } - - beforeEach(() => { - vi.clearAllMocks() - // Create new pinia instance for each test - const pinia = createPinia() - setActivePinia(pinia) - - // Reset task logs - mockTaskLogs.length = 0 - mockComfyManagerStore.taskLogs = mockTaskLogs - // Reset event handler - reconnectHandler = null - - vi.mocked(useComfyManagerStore).mockReturnValue( - mockComfyManagerStore as any - ) - vi.mocked(useDialogStore).mockReturnValue(mockDialogStore as any) - vi.mocked(useSettingStore).mockReturnValue(mockSettingStore as any) - vi.mocked(useManagerProgressDialogStore).mockReturnValue( - mockProgressDialogStore as any - ) - vi.mocked(useCommandStore).mockReturnValue(mockCommandStore as any) - vi.mocked(useComfyManagerService).mockReturnValue( - mockComfyManagerService as any - ) - }) - - describe('State 1: Queue Running', () => { - it('should display loading spinner and progress counter when queue is running', async () => { - // Setup queue running state - mockComfyManagerStore.isProcessingTasks = true - mockComfyManagerStore.succeededTasksIds = ['1', '2'] - mockComfyManagerStore.failedTasksIds = [] - mockComfyManagerStore.taskHistory = { - '1': { taskName: 'Installing pack1' }, - '2': { taskName: 'Installing pack2' }, - '3': { taskName: 'Installing pack3' } - } - mockTaskLogs.push( - { taskName: 'Installing pack1', taskId: '1', logs: [] }, - { taskName: 'Installing pack2', taskId: '2', logs: [] }, - { taskName: 'Installing pack3', taskId: '3', logs: [] } - ) - - const wrapper = mountComponent() - - // Check loading spinner exists (DotSpinner component) - expect(wrapper.find('.inline-flex').exists()).toBe(true) - - // Check current task name is displayed - expect(wrapper.text()).toContain('Installing pack3') - - // Check progress counter (completed: 2 of 3) - expect(wrapper.text()).toMatch(/2.*of.*3/) - - // Check expand/collapse button exists - const expandButton = wrapper.find('[aria-label="Expand"]') - expect(expandButton.exists()).toBe(true) - - // Check Apply Changes button is NOT shown - expect(wrapper.text()).not.toContain('Apply Changes') - }) - - it('should toggle expansion when expand button is clicked', async () => { - mockComfyManagerStore.isProcessingTasks = true - mockTaskLogs.push({ taskName: 'Installing', taskId: '1', logs: [] }) - - const wrapper = mountComponent() - - const expandButton = wrapper.find('[aria-label="Expand"]') - await expandButton.trigger('click') - - expect(mockProgressDialogStore.toggle).toHaveBeenCalled() - }) - }) - - describe('State 2: Tasks Completed (Waiting for Restart)', () => { - it('should display check mark and Apply Changes button when all tasks are done', async () => { - // Setup tasks completed state - mockComfyManagerStore.isProcessingTasks = false - mockTaskLogs.push( - { taskName: 'Installed pack1', taskId: '1', logs: [] }, - { taskName: 'Installed pack2', taskId: '2', logs: [] } - ) - mockComfyManagerStore.allTasksDone = true - - const wrapper = mountComponent() - - // Check check mark emoji - expect(wrapper.text()).toContain('✅') - - // Check restart message - expect(wrapper.text()).toContain( - 'To apply changes, please restart ComfyUI' - ) - expect(wrapper.text()).toContain('Apply Changes') - - // Check Apply Changes button exists - const applyButton = wrapper - .findAll('button') - .find((btn) => btn.text().includes('Apply Changes')) - expect(applyButton).toBeTruthy() - - // Check no progress counter - expect(wrapper.text()).not.toMatch(/\d+.*of.*\d+/) - }) - }) - - describe('State 3: Restarting', () => { - it('should display restarting message and spinner during restart', async () => { - // Setup completed state first - mockComfyManagerStore.isProcessingTasks = false - mockComfyManagerStore.allTasksDone = true - - const wrapper = mountComponent() - - // Click Apply Changes to trigger restart - const applyButton = wrapper - .findAll('button') - .find((btn) => btn.text().includes('Apply Changes')) - await applyButton?.trigger('click') - - // Wait for state update - await nextTick() - - // Check restarting message - expect(wrapper.text()).toContain('Restarting backend to apply changes...') - - // Check loading spinner during restart - expect(wrapper.find('.inline-flex').exists()).toBe(true) - - // Check Apply Changes button is hidden - expect(wrapper.text()).not.toContain('Apply Changes') - }) - }) - - describe('State 4: Restart Completed', () => { - it('should display success message and auto-close after 3 seconds', async () => { - vi.useFakeTimers() - - // Setup completed state - mockComfyManagerStore.isProcessingTasks = false - mockComfyManagerStore.allTasksDone = true - - const wrapper = mountComponent() - - // Trigger restart - const applyButton = wrapper - .findAll('button') - .find((btn) => btn.text().includes('Apply Changes')) - await applyButton?.trigger('click') - - // Wait for event listener to be set up - await nextTick() - - // Trigger the reconnect handler directly - if (reconnectHandler) { - await reconnectHandler() - } - - // Wait for restart completed state - await nextTick() - - // Check success message - expect(wrapper.text()).toContain('🎉') - expect(wrapper.text()).toContain( - 'Extension(s) successfully installed and are ready to use!' - ) - - // Check dialog closes after 3 seconds - vi.advanceTimersByTime(3000) - - await nextTick() - - expect(mockDialogStore.closeDialog).toHaveBeenCalledWith({ - key: 'global-manager-progress-dialog' - }) - expect(mockComfyManagerStore.resetTaskState).toHaveBeenCalled() - - vi.useRealTimers() - }) - }) - - describe('Common Features', () => { - it('should always display close button', async () => { - const wrapper = mountComponent() - - const closeButton = wrapper.find('[aria-label="Close"]') - expect(closeButton.exists()).toBe(true) - }) - - it('should close dialog when close button is clicked', async () => { - const wrapper = mountComponent() - - const closeButton = wrapper.find('[aria-label="Close"]') - await closeButton.trigger('click') - - expect(mockDialogStore.closeDialog).toHaveBeenCalledWith({ - key: 'global-manager-progress-dialog' - }) - }) - }) - - describe('Toast Management', () => { - it('should suppress reconnection toasts during restart', async () => { - mockComfyManagerStore.isProcessingTasks = false - mockComfyManagerStore.allTasksDone = true - mockSettingStore.get.mockReturnValue(false) // Original setting - - const wrapper = mountComponent() - - // Click Apply Changes - const applyButton = wrapper - .findAll('button') - .find((btn) => btn.text().includes('Apply Changes')) - await applyButton?.trigger('click') - - // Check toast setting was disabled - expect(mockSettingStore.set).toHaveBeenCalledWith( - 'Comfy.Toast.DisableReconnectingToast', - true - ) - }) - - it('should restore toast settings after restart completes', async () => { - mockComfyManagerStore.isProcessingTasks = false - mockComfyManagerStore.allTasksDone = true - mockSettingStore.get.mockReturnValue(false) // Original setting - - const wrapper = mountComponent() - - // Click Apply Changes - const applyButton = wrapper - .findAll('button') - .find((btn) => btn.text().includes('Apply Changes')) - await applyButton?.trigger('click') - - // Wait for event listener to be set up - await nextTick() - - // Trigger the reconnect handler directly - if (reconnectHandler) { - await reconnectHandler() - } - - // Wait for settings restoration - await nextTick() - - expect(mockSettingStore.set).toHaveBeenCalledWith( - 'Comfy.Toast.DisableReconnectingToast', - false // Restored to original - ) - }) - }) - - describe('Error Handling', () => { - it('should restore state and close dialog on restart error', async () => { - mockComfyManagerStore.isProcessingTasks = false - mockComfyManagerStore.allTasksDone = true - - // Mock restart to throw error - mockComfyManagerService.rebootComfyUI.mockRejectedValue( - new Error('Restart failed') - ) - - const wrapper = mountComponent({ captureError: true }) - - // Click Apply Changes - const applyButton = wrapper - .findAll('button') - .find((btn) => btn.text().includes('Apply Changes')) - - expect(applyButton).toBeTruthy() - - // The component throws the error but Vue Test Utils catches it - // We need to check if the error handling logic was executed - await applyButton!.trigger('click').catch(() => { - // Error is expected, ignore it - }) - - // Wait for error handling - await nextTick() - - // Check dialog was closed on error - expect(mockDialogStore.closeDialog).toHaveBeenCalled() - // Check toast settings were restored - expect(mockSettingStore.set).toHaveBeenCalledWith( - 'Comfy.Toast.DisableReconnectingToast', - false - ) - // Check that the error handler was called - expect(mockComfyManagerService.rebootComfyUI).toHaveBeenCalled() - }) - }) -}) diff --git a/tests-ui/tests/composables/useManagerQueue.test.ts b/tests-ui/tests/composables/useManagerQueue.test.ts index 502867b8bc1..740a1e5cfba 100644 --- a/tests-ui/tests/composables/useManagerQueue.test.ts +++ b/tests-ui/tests/composables/useManagerQueue.test.ts @@ -4,13 +4,6 @@ import { ref } from 'vue' import { useManagerQueue } from '@/workbench/extensions/manager/composables/useManagerQueue' import type { components } from '@/workbench/extensions/manager/types/generatedManagerTypes' -// Mock dialog service -vi.mock('@/services/dialogService', () => ({ - useDialogService: () => ({ - showManagerProgressDialog: vi.fn() - }) -})) - // Mock the app API vi.mock('@/scripts/app', () => ({ app: { diff --git a/tests-ui/tests/store/comfyManagerStore.test.ts b/tests-ui/tests/store/comfyManagerStore.test.ts index d131a0fc9df..d1754d59a01 100644 --- a/tests-ui/tests/store/comfyManagerStore.test.ts +++ b/tests-ui/tests/store/comfyManagerStore.test.ts @@ -17,12 +17,6 @@ vi.mock('@/workbench/extensions/manager/services/comfyManagerService', () => ({ useComfyManagerService: vi.fn() })) -vi.mock('@/services/dialogService', () => ({ - useDialogService: () => ({ - showManagerProgressDialog: vi.fn() - }) -})) - vi.mock('@/workbench/extensions/manager/composables/useManagerQueue', () => { const enqueueTaskMock = vi.fn()