diff --git a/.changeset/icy-walls-exist.md b/.changeset/icy-walls-exist.md new file mode 100644 index 00000000..b88ad316 --- /dev/null +++ b/.changeset/icy-walls-exist.md @@ -0,0 +1,6 @@ +--- +"@storybook/addon-mcp": minor +--- + +Introduced the `get-changed-stories` tool to retrieve metadata for stories marked as new, modified, or affected. +Updated `dev-instructions.md` and `storybook-story-instructions.md` to reflect the new workflow for calling `get-changed-stories` before `preview-stories`. diff --git a/apps/internal-storybook/.storybook/main.ts b/apps/internal-storybook/.storybook/main.ts index 1913cc03..6c56810c 100644 --- a/apps/internal-storybook/.storybook/main.ts +++ b/apps/internal-storybook/.storybook/main.ts @@ -29,6 +29,7 @@ const config = defineMain({ disableTelemetry: true, }, features: { + changeDetection: true, experimentalComponentsManifest: true, }, // No refs - single source mode diff --git a/apps/internal-storybook/pnpm-lock.yaml b/apps/internal-storybook/pnpm-lock.yaml index 0c170d80..d8932897 100644 --- a/apps/internal-storybook/pnpm-lock.yaml +++ b/apps/internal-storybook/pnpm-lock.yaml @@ -7,20 +7,20 @@ settings: catalogs: default: '@storybook/addon-a11y': - specifier: 10.4.0-alpha.8 - version: 10.4.0-alpha.8 + specifier: 10.4.0-alpha.12 + version: 10.4.0-alpha.12 '@storybook/addon-docs': - specifier: 10.4.0-alpha.8 - version: 10.4.0-alpha.8 + specifier: 10.4.0-alpha.12 + version: 10.4.0-alpha.12 '@storybook/addon-themes': - specifier: 10.4.0-alpha.8 - version: 10.4.0-alpha.8 + specifier: 10.4.0-alpha.12 + version: 10.4.0-alpha.12 '@storybook/addon-vitest': - specifier: 10.4.0-alpha.8 - version: 10.4.0-alpha.8 + specifier: 10.4.0-alpha.12 + version: 10.4.0-alpha.12 '@storybook/react-vite': - specifier: 10.4.0-alpha.8 - version: 10.4.0-alpha.8 + specifier: 10.4.0-alpha.12 + version: 10.4.0-alpha.12 '@vitest/browser-playwright': specifier: 4.0.6 version: 4.0.6 @@ -28,8 +28,8 @@ catalogs: specifier: 1.56.1 version: 1.56.1 storybook: - specifier: 10.4.0-alpha.8 - version: 10.4.0-alpha.8 + specifier: 10.4.0-alpha.12 + version: 10.4.0-alpha.12 vite: specifier: 7.2.2 version: 7.2.2 @@ -43,22 +43,22 @@ importers: devDependencies: '@storybook/addon-a11y': specifier: 'catalog:' - version: 10.4.0-alpha.8(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) + version: 10.4.0-alpha.12(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) '@storybook/addon-docs': specifier: 'catalog:' - version: 10.4.0-alpha.8(@types/react@18.3.28)(esbuild@0.27.3)(rollup@4.57.1)(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.2.2) + version: 10.4.0-alpha.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(esbuild@0.27.3)(rollup@4.57.1)(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.2.2) '@storybook/addon-mcp': specifier: workspace:* version: link:../../packages/addon-mcp '@storybook/addon-themes': specifier: 'catalog:' - version: 10.4.0-alpha.8(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) + version: 10.4.0-alpha.12(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) '@storybook/addon-vitest': specifier: 'catalog:' - version: 10.4.0-alpha.8(@vitest/browser-playwright@4.0.6)(@vitest/browser@4.0.6(vite@7.2.2)(vitest@4.0.6))(@vitest/runner@4.0.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vitest@4.0.6) + version: 10.4.0-alpha.12(@vitest/browser-playwright@4.0.6)(@vitest/browser@4.0.6(vite@7.2.2)(vitest@4.0.6))(@vitest/runner@4.0.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vitest@4.0.6) '@storybook/react-vite': specifier: 'catalog:' - version: 10.4.0-alpha.8(esbuild@0.27.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.57.1)(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.9.3)(vite@7.2.2) + version: 10.4.0-alpha.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(esbuild@0.27.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.57.1)(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.9.3)(vite@7.2.2) '@types/react': specifier: ^18.2.65 version: 18.3.28 @@ -82,7 +82,7 @@ importers: version: 18.3.1(react@18.3.1) storybook: specifier: 'catalog:' - version: 10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) tinyexec: specifier: ^1.0.2 version: 1.0.2 @@ -684,28 +684,32 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - '@storybook/addon-a11y@10.4.0-alpha.8': - resolution: {integrity: sha512-D/HoLv2KPk/QNAXwJMRamH7w1148Fm3xSlMulwCm1in6XfL2dkomc3khC3Fxzs4/QJJWczSw9xDCHrGjkCX56g==} + '@storybook/addon-a11y@10.4.0-alpha.12': + resolution: {integrity: sha512-exH6qseQ0uC5/grhDdrkeLioB5IvzBfZwPJAicsBLBKNcJ9hu7xgaI4YVE8SeA5YtXBW7ATjzLaVwM2syS8BmA==} peerDependencies: - storybook: ^10.4.0-alpha.8 + storybook: ^10.4.0-alpha.12 - '@storybook/addon-docs@10.4.0-alpha.8': - resolution: {integrity: sha512-28XE4CRpGLnga72GTuIKimAKMtu/I101OFTp868Eb2bTkNKEKFOp5CoGJzirt1MI6ZakI+SA9ufLjZOsOGHt3g==} + '@storybook/addon-docs@10.4.0-alpha.12': + resolution: {integrity: sha512-+e/PbM7CteCXYq2NHJCHr0036ynUTlVPh4sj+MJMWqx8RdKUpRUvQIPqU2A1bnhZ6vj7q1oD4fP+ZeVLiTkT9A==} peerDependencies: - storybook: ^10.4.0-alpha.8 + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + storybook: ^10.4.0-alpha.12 + peerDependenciesMeta: + '@types/react': + optional: true - '@storybook/addon-themes@10.4.0-alpha.8': - resolution: {integrity: sha512-lOZIq5F2jagq77lVMKDa5hjHRDM5NNQrvR2RMaVDtcb3L/Bh41UqNGmzoCo8QJdTesjAEPVkW0JWGdu5qa4/PQ==} + '@storybook/addon-themes@10.4.0-alpha.12': + resolution: {integrity: sha512-0FJ6w4Dh3jJfojKyQ9mJ9Rit8es5b8sI0p78Bb6WryxuwzHLSNKkSVP2wUrI5zdZ0mjrLfv7mXQlbVIdllhPoQ==} peerDependencies: - storybook: ^10.4.0-alpha.8 + storybook: ^10.4.0-alpha.12 - '@storybook/addon-vitest@10.4.0-alpha.8': - resolution: {integrity: sha512-UQg07DBAW4eryFMYXiJmlj4lmmLWqCkfXBvfGlFvvVKFsbMM0wUCp5XeDckskJCVVALb4O02fObAIvAs24FJaw==} + '@storybook/addon-vitest@10.4.0-alpha.12': + resolution: {integrity: sha512-vqvXoGHHbJ1GKdsuIoG9RNjPH9Scy4edaEOfAt9MqQltQnj6gvYXqaFld85weaFzASHFLWtlsZSKv1QMPzjcQg==} peerDependencies: '@vitest/browser': ^3.0.0 || ^4.0.0 '@vitest/browser-playwright': ^4.0.0 '@vitest/runner': ^3.0.0 || ^4.0.0 - storybook: ^10.4.0-alpha.8 + storybook: ^10.4.0-alpha.12 vitest: ^3.0.0 || ^4.0.0 peerDependenciesMeta: '@vitest/browser': @@ -717,18 +721,18 @@ packages: vitest: optional: true - '@storybook/builder-vite@10.4.0-alpha.8': - resolution: {integrity: sha512-weLrxdNknHwHZrGMVfWjAcN48kIG5ipYJAWjKrx2nzhCaZY30DQ1SuVVaDiwVSUfTmncK/MX5weerJjb8Ny66g==} + '@storybook/builder-vite@10.4.0-alpha.12': + resolution: {integrity: sha512-c2vhsrBIl3VJ1gyo/62ydpgBMjjbd2trVJUG+XeyIEOMI0NGVTOI1g/DOZLwtJD9HD1J5/QJLmR+Qu+Ah2nu8g==} peerDependencies: - storybook: ^10.4.0-alpha.8 + storybook: ^10.4.0-alpha.12 vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - '@storybook/csf-plugin@10.4.0-alpha.8': - resolution: {integrity: sha512-h5GXJaAQGNRhko09qvoVAxPBLvKlQkgDFBgc/3TPZKd2t0fZMErdJPX6ixn4cOONn5SpDqeI/uej0OHC5uazlg==} + '@storybook/csf-plugin@10.4.0-alpha.12': + resolution: {integrity: sha512-muyUriFPetDDM1m7YL63/Loydu3hN1HC2YfEiOQZByOimSAjkzyJAe5HWfMPVSX/Lr8e2w6/aaqllP20oitdrA==} peerDependencies: esbuild: '*' rollup: '*' - storybook: ^10.4.0-alpha.8 + storybook: ^10.4.0-alpha.12 vite: '*' webpack: '*' peerDependenciesMeta: @@ -750,29 +754,42 @@ 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/react-dom-shim@10.4.0-alpha.8': - resolution: {integrity: sha512-JlAmzvhmZQJGnwv7Wz0LBlQc+7ciAUScFtEWcxmJojRr22tGZvULslUtFlSHkJzjCf1PSymhRwfFG4Xt3l+wcg==} + '@storybook/react-dom-shim@10.4.0-alpha.12': + resolution: {integrity: sha512-ZX7N68EIVktfwiDmzFhTP3UvXMpl4upCOWbHtZPtHGv9HZb/IzmRReulBX6FYF0OEiys7hKcmGPQUYMpqFI8oQ==} peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + '@types/react-dom': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 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: ^10.4.0-alpha.8 + storybook: ^10.4.0-alpha.12 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@storybook/react-vite@10.4.0-alpha.8': - resolution: {integrity: sha512-ZeY+DI22bXH2nX95Mgwabtb+QFY3W0P6HEhMnqOc4fJHb4NwkGR81uIqvQxjF9VcMo5ONfABsr6J8+wdkyo05w==} + '@storybook/react-vite@10.4.0-alpha.12': + resolution: {integrity: sha512-TklXWkfai7AsQICMJePb4Jn9FlVYz+N6PBx13Vz5C2kmdCZUJd3Qv79/wmki5sxn6tWurzLtzpE1/GfoR5qcVg==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.4.0-alpha.8 + storybook: ^10.4.0-alpha.12 vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - '@storybook/react@10.4.0-alpha.8': - resolution: {integrity: sha512-WgidbZseAPemAtIPKILTi2eg1F2zINtYi0N44SxwygR4OSCHg6XIG4z+d96dPA25r/KtRJB7Ef9muCSRanQoLg==} + '@storybook/react@10.4.0-alpha.12': + resolution: {integrity: sha512-mCQjM953RTHnxRA/ggllebh010vtOjadQK0PzyRqEXw+sE8lCaglrveufxbBtyyYY7TiJvkWH6tWRRpsEaiGIQ==} peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + '@types/react-dom': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 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: ^10.4.0-alpha.8 + storybook: ^10.4.0-alpha.12 typescript: '>= 4.9.x' peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true typescript: optional: true @@ -1305,14 +1322,20 @@ packages: std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} - storybook@10.4.0-alpha.8: - resolution: {integrity: sha512-r3fGYI57j/9KTQmY9t/f+qJRVe0M3DJnez4jD++Dr2LTbgYOz6E6qFryXFGlHK0BVz1R5O/gzDdL0fn+tOhMgA==} + storybook@10.4.0-alpha.12: + resolution: {integrity: sha512-DVi/v+vXwf0itbM8tm8XtEjaVmf2lsTHmdZQICOQGz7Mnr5181vMJpfvdNbdnXbyLXmVvagqJS+m1AjMTwi9xQ==} hasBin: true peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 prettier: ^2 || ^3 + vite-plus: ^0.1.15 peerDependenciesMeta: + '@types/react': + optional: true prettier: optional: true + vite-plus: + optional: true strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} @@ -1891,39 +1914,41 @@ snapshots: '@standard-schema/spec@1.1.0': {} - '@storybook/addon-a11y@10.4.0-alpha.8(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))': + '@storybook/addon-a11y@10.4.0-alpha.12(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))': dependencies: '@storybook/global': 5.0.0 axe-core: 4.11.1 - storybook: 10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + storybook: 10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/addon-docs@10.4.0-alpha.8(@types/react@18.3.28)(esbuild@0.27.3)(rollup@4.57.1)(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.2.2)': + '@storybook/addon-docs@10.4.0-alpha.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(esbuild@0.27.3)(rollup@4.57.1)(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.2.2)': dependencies: '@mdx-js/react': 3.1.1(@types/react@18.3.28)(react@18.3.1) - '@storybook/csf-plugin': 10.4.0-alpha.8(esbuild@0.27.3)(rollup@4.57.1)(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.2.2) + '@storybook/csf-plugin': 10.4.0-alpha.12(esbuild@0.27.3)(rollup@4.57.1)(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.2.2) '@storybook/icons': 2.0.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/react-dom-shim': 10.4.0-alpha.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) + '@storybook/react-dom-shim': 10.4.0-alpha.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - storybook: 10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + storybook: 10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) ts-dedent: 2.2.0 + optionalDependencies: + '@types/react': 18.3.28 transitivePeerDependencies: - - '@types/react' + - '@types/react-dom' - esbuild - rollup - vite - webpack - '@storybook/addon-themes@10.4.0-alpha.8(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))': + '@storybook/addon-themes@10.4.0-alpha.12(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))': dependencies: - storybook: 10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + storybook: 10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) ts-dedent: 2.2.0 - '@storybook/addon-vitest@10.4.0-alpha.8(@vitest/browser-playwright@4.0.6)(@vitest/browser@4.0.6(vite@7.2.2)(vitest@4.0.6))(@vitest/runner@4.0.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vitest@4.0.6)': + '@storybook/addon-vitest@10.4.0-alpha.12(@vitest/browser-playwright@4.0.6)(@vitest/browser@4.0.6(vite@7.2.2)(vitest@4.0.6))(@vitest/runner@4.0.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vitest@4.0.6)': dependencies: '@storybook/global': 5.0.0 '@storybook/icons': 2.0.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - storybook: 10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + storybook: 10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) optionalDependencies: '@vitest/browser': 4.0.6(vite@7.2.2)(vitest@4.0.6) '@vitest/browser-playwright': 4.0.6(playwright@1.56.1)(vite@7.2.2)(vitest@4.0.6) @@ -1933,10 +1958,10 @@ snapshots: - react - react-dom - '@storybook/builder-vite@10.4.0-alpha.8(esbuild@0.27.3)(rollup@4.57.1)(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.2.2)': + '@storybook/builder-vite@10.4.0-alpha.12(esbuild@0.27.3)(rollup@4.57.1)(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.2.2)': dependencies: - '@storybook/csf-plugin': 10.4.0-alpha.8(esbuild@0.27.3)(rollup@4.57.1)(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.2.2) - storybook: 10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/csf-plugin': 10.4.0-alpha.12(esbuild@0.27.3)(rollup@4.57.1)(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.2.2) + storybook: 10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) ts-dedent: 2.2.0 vite: 7.2.2 transitivePeerDependencies: @@ -1944,9 +1969,9 @@ snapshots: - rollup - webpack - '@storybook/csf-plugin@10.4.0-alpha.8(esbuild@0.27.3)(rollup@4.57.1)(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.2.2)': + '@storybook/csf-plugin@10.4.0-alpha.12(esbuild@0.27.3)(rollup@4.57.1)(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.2.2)': dependencies: - storybook: 10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + storybook: 10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) unplugin: 2.3.11 optionalDependencies: esbuild: 0.27.3 @@ -1960,44 +1985,51 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@storybook/react-dom-shim@10.4.0-alpha.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))': + '@storybook/react-dom-shim@10.4.0-alpha.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))': dependencies: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - storybook: 10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + storybook: 10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.28 + '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@storybook/react-vite@10.4.0-alpha.8(esbuild@0.27.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.57.1)(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.9.3)(vite@7.2.2)': + '@storybook/react-vite@10.4.0-alpha.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(esbuild@0.27.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.57.1)(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.9.3)(vite@7.2.2)': dependencies: '@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(typescript@5.9.3)(vite@7.2.2) '@rollup/pluginutils': 5.3.0(rollup@4.57.1) - '@storybook/builder-vite': 10.4.0-alpha.8(esbuild@0.27.3)(rollup@4.57.1)(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.2.2) - '@storybook/react': 10.4.0-alpha.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.9.3) + '@storybook/builder-vite': 10.4.0-alpha.12(esbuild@0.27.3)(rollup@4.57.1)(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.2.2) + '@storybook/react': 10.4.0-alpha.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.9.3) empathic: 2.0.0 magic-string: 0.30.21 react: 18.3.1 react-docgen: 8.0.2 react-dom: 18.3.1(react@18.3.1) resolve: 1.22.11 - storybook: 10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + storybook: 10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) tsconfig-paths: 4.2.0 vite: 7.2.2 transitivePeerDependencies: + - '@types/react' + - '@types/react-dom' - esbuild - rollup - supports-color - typescript - webpack - '@storybook/react@10.4.0-alpha.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.9.3)': + '@storybook/react@10.4.0-alpha.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.9.3)': dependencies: '@storybook/global': 5.0.0 - '@storybook/react-dom-shim': 10.4.0-alpha.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) + '@storybook/react-dom-shim': 10.4.0-alpha.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) react: 18.3.1 react-docgen: 8.0.2 react-docgen-typescript: 2.4.0(typescript@5.9.3) react-dom: 18.3.1(react@18.3.1) - storybook: 10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + storybook: 10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) optionalDependencies: + '@types/react': 18.3.28 + '@types/react-dom': 18.3.7(@types/react@18.3.28) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -2582,7 +2614,7 @@ snapshots: std-env@3.10.0: {} - storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@storybook/global': 5.0.0 '@storybook/icons': 2.0.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -2597,6 +2629,8 @@ snapshots: semver: 7.7.4 use-sync-external-store: 1.6.0(react@18.3.1) ws: 8.19.0 + optionalDependencies: + '@types/react': 18.3.28 transitivePeerDependencies: - '@testing-library/dom' - bufferutil diff --git a/apps/internal-storybook/tests/helpers.ts b/apps/internal-storybook/tests/helpers.ts index c15284f6..a9563da1 100644 --- a/apps/internal-storybook/tests/helpers.ts +++ b/apps/internal-storybook/tests/helpers.ts @@ -80,8 +80,20 @@ export async function stopStorybook(storybookProcess: ReturnType | nul if (!storybookProcess || !storybookProcess.process) { return; } - const kill = Promise.withResolvers(); - storybookProcess.process.on('exit', kill.resolve); + const exitSignal = Promise.withResolvers(); + storybookProcess.process.on('exit', exitSignal.resolve); storybookProcess.kill('SIGTERM'); - await kill.promise; + + // Storybook can ignore SIGTERM while workers are shutting down. + // Escalate to SIGKILL after a short grace period to keep tests bounded. + const killTimeout = setTimeout(() => { + try { + storybookProcess.kill('SIGKILL'); + } catch { + // Process may already be gone. + } + }, 10_000); + + await exitSignal.promise; + clearTimeout(killTimeout); } diff --git a/apps/internal-storybook/tests/mcp-endpoint.e2e.test.ts b/apps/internal-storybook/tests/mcp-endpoint.e2e.test.ts index 26be1b96..f4a4b09a 100644 --- a/apps/internal-storybook/tests/mcp-endpoint.e2e.test.ts +++ b/apps/internal-storybook/tests/mcp-endpoint.e2e.test.ts @@ -100,7 +100,7 @@ describe('MCP Endpoint E2E Tests', () => { expect(response.result).toHaveProperty('tools'); // Dev, docs, and test tools should be present - expect(response.result.tools).toHaveLength(6); + expect(response.result.tools).toHaveLength(7); expect(response.result.tools).toMatchInlineSnapshot(` [ @@ -369,6 +369,15 @@ describe('MCP Endpoint E2E Tests', () => { "name": "get-storybook-story-instructions", "title": "Storybook Story Development Instructions", }, + { + "description": "Get Storybook stories marked as new, modified, or related. Returns story metadata only (no URLs).", + "inputSchema": { + "properties": {}, + "type": "object", + }, + "name": "get-changed-stories", + "title": "Get changed stories metadata", + }, { "description": "Run story tests. Provide stories for focused runs (faster while iterating), @@ -846,6 +855,7 @@ describe('MCP Endpoint E2E Tests', () => { expect(result1.result).toBeDefined(); expect(result1.result.content).toBeDefined(); expect(result1.result.content.length).toBeGreaterThan(0); + expect(result1.result.content[0].text).toContain('example-button--primary'); expect(result1.result.content[0].text).toContain('Passing Stories'); @@ -890,6 +900,7 @@ describe('MCP Endpoint E2E Tests', () => { [ "preview-stories", "get-storybook-story-instructions", + "get-changed-stories", ] `); }); diff --git a/eval/pnpm-lock.yaml b/eval/pnpm-lock.yaml index ef9e5282..40a88d75 100644 --- a/eval/pnpm-lock.yaml +++ b/eval/pnpm-lock.yaml @@ -7,17 +7,17 @@ settings: catalogs: default: '@storybook/addon-a11y': - specifier: 10.4.0-alpha.8 - version: 10.4.0-alpha.8 + specifier: 10.4.0-alpha.12 + version: 10.4.0-alpha.12 '@storybook/react-vite': - specifier: 10.4.0-alpha.8 - version: 10.4.0-alpha.8 + specifier: 10.4.0-alpha.12 + version: 10.4.0-alpha.12 playwright: specifier: 1.56.1 version: 1.56.1 storybook: - specifier: 10.4.0-alpha.8 - version: 10.4.0-alpha.8 + specifier: 10.4.0-alpha.12 + version: 10.4.0-alpha.12 valibot: specifier: 1.2.0 version: 1.2.0 @@ -49,13 +49,13 @@ importers: version: 1.1.11(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@storybook/addon-a11y': specifier: 'catalog:' - version: 10.4.0-alpha.8(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) + version: 10.4.0-alpha.12(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) '@storybook/mcp': specifier: workspace:* version: link:../packages/mcp '@storybook/react-vite': specifier: 'catalog:' - version: 10.4.0-alpha.8(esbuild@0.27.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.57.1)(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.12)) + version: 10.4.0-alpha.12(@types/react@18.3.28)(esbuild@0.27.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.57.1)(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.12)) '@tsconfig/node-ts': specifier: ^23.6.1 version: 23.6.3 @@ -127,10 +127,10 @@ importers: version: 5.83.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4) storybook: specifier: 'catalog:' - version: 10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) storybook-addon-test-codegen: specifier: ^3.0.0 - version: 3.0.1(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) + version: 3.0.1(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) tinyexec: specifier: ^1.0.1 version: 1.0.2 @@ -1509,23 +1509,23 @@ packages: react: '>=16.8.0' react-dom: '>=16.8.0' - '@storybook/addon-a11y@10.4.0-alpha.8': - resolution: {integrity: sha512-D/HoLv2KPk/QNAXwJMRamH7w1148Fm3xSlMulwCm1in6XfL2dkomc3khC3Fxzs4/QJJWczSw9xDCHrGjkCX56g==} + '@storybook/addon-a11y@10.4.0-alpha.12': + resolution: {integrity: sha512-exH6qseQ0uC5/grhDdrkeLioB5IvzBfZwPJAicsBLBKNcJ9hu7xgaI4YVE8SeA5YtXBW7ATjzLaVwM2syS8BmA==} peerDependencies: - storybook: ^10.4.0-alpha.8 + storybook: ^10.4.0-alpha.12 - '@storybook/builder-vite@10.4.0-alpha.8': - resolution: {integrity: sha512-weLrxdNknHwHZrGMVfWjAcN48kIG5ipYJAWjKrx2nzhCaZY30DQ1SuVVaDiwVSUfTmncK/MX5weerJjb8Ny66g==} + '@storybook/builder-vite@10.4.0-alpha.12': + resolution: {integrity: sha512-c2vhsrBIl3VJ1gyo/62ydpgBMjjbd2trVJUG+XeyIEOMI0NGVTOI1g/DOZLwtJD9HD1J5/QJLmR+Qu+Ah2nu8g==} peerDependencies: - storybook: ^10.4.0-alpha.8 + storybook: ^10.4.0-alpha.12 vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - '@storybook/csf-plugin@10.4.0-alpha.8': - resolution: {integrity: sha512-h5GXJaAQGNRhko09qvoVAxPBLvKlQkgDFBgc/3TPZKd2t0fZMErdJPX6ixn4cOONn5SpDqeI/uej0OHC5uazlg==} + '@storybook/csf-plugin@10.4.0-alpha.12': + resolution: {integrity: sha512-muyUriFPetDDM1m7YL63/Loydu3hN1HC2YfEiOQZByOimSAjkzyJAe5HWfMPVSX/Lr8e2w6/aaqllP20oitdrA==} peerDependencies: esbuild: '*' rollup: '*' - storybook: ^10.4.0-alpha.8 + storybook: ^10.4.0-alpha.12 vite: '*' webpack: '*' peerDependenciesMeta: @@ -1547,29 +1547,42 @@ 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/react-dom-shim@10.4.0-alpha.8': - resolution: {integrity: sha512-JlAmzvhmZQJGnwv7Wz0LBlQc+7ciAUScFtEWcxmJojRr22tGZvULslUtFlSHkJzjCf1PSymhRwfFG4Xt3l+wcg==} + '@storybook/react-dom-shim@10.4.0-alpha.12': + resolution: {integrity: sha512-ZX7N68EIVktfwiDmzFhTP3UvXMpl4upCOWbHtZPtHGv9HZb/IzmRReulBX6FYF0OEiys7hKcmGPQUYMpqFI8oQ==} peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + '@types/react-dom': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 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: ^10.4.0-alpha.8 + storybook: ^10.4.0-alpha.12 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@storybook/react-vite@10.4.0-alpha.8': - resolution: {integrity: sha512-ZeY+DI22bXH2nX95Mgwabtb+QFY3W0P6HEhMnqOc4fJHb4NwkGR81uIqvQxjF9VcMo5ONfABsr6J8+wdkyo05w==} + '@storybook/react-vite@10.4.0-alpha.12': + resolution: {integrity: sha512-TklXWkfai7AsQICMJePb4Jn9FlVYz+N6PBx13Vz5C2kmdCZUJd3Qv79/wmki5sxn6tWurzLtzpE1/GfoR5qcVg==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.4.0-alpha.8 + storybook: ^10.4.0-alpha.12 vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - '@storybook/react@10.4.0-alpha.8': - resolution: {integrity: sha512-WgidbZseAPemAtIPKILTi2eg1F2zINtYi0N44SxwygR4OSCHg6XIG4z+d96dPA25r/KtRJB7Ef9muCSRanQoLg==} + '@storybook/react@10.4.0-alpha.12': + resolution: {integrity: sha512-mCQjM953RTHnxRA/ggllebh010vtOjadQK0PzyRqEXw+sE8lCaglrveufxbBtyyYY7TiJvkWH6tWRRpsEaiGIQ==} peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + '@types/react-dom': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 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: ^10.4.0-alpha.8 + storybook: ^10.4.0-alpha.12 typescript: '>= 4.9.x' peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true typescript: optional: true @@ -2876,14 +2889,20 @@ packages: peerDependencies: storybook: ^0.0.0-0 || ^10.0.0 || ^10.0.0-0 || ^10.1.0-0 || ^10.2.0-0 || ^10.3.0-0 - storybook@10.4.0-alpha.8: - resolution: {integrity: sha512-r3fGYI57j/9KTQmY9t/f+qJRVe0M3DJnez4jD++Dr2LTbgYOz6E6qFryXFGlHK0BVz1R5O/gzDdL0fn+tOhMgA==} + storybook@10.4.0-alpha.12: + resolution: {integrity: sha512-DVi/v+vXwf0itbM8tm8XtEjaVmf2lsTHmdZQICOQGz7Mnr5181vMJpfvdNbdnXbyLXmVvagqJS+m1AjMTwi9xQ==} hasBin: true peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 prettier: ^2 || ^3 + vite-plus: ^0.1.15 peerDependenciesMeta: + '@types/react': + optional: true prettier: optional: true + vite-plus: + optional: true strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} @@ -4312,16 +4331,16 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@storybook/addon-a11y@10.4.0-alpha.8(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': + '@storybook/addon-a11y@10.4.0-alpha.12(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': dependencies: '@storybook/global': 5.0.0 axe-core: 4.11.1 - storybook: 10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + storybook: 10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@storybook/builder-vite@10.4.0-alpha.8(esbuild@0.27.3)(rollup@4.57.1)(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@24.10.12))': + '@storybook/builder-vite@10.4.0-alpha.12(esbuild@0.27.3)(rollup@4.57.1)(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@24.10.12))': dependencies: - '@storybook/csf-plugin': 10.4.0-alpha.8(esbuild@0.27.3)(rollup@4.57.1)(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@24.10.12)) - storybook: 10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@storybook/csf-plugin': 10.4.0-alpha.12(esbuild@0.27.3)(rollup@4.57.1)(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@24.10.12)) + storybook: 10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) ts-dedent: 2.2.0 vite: 7.3.1(@types/node@24.10.12) transitivePeerDependencies: @@ -4329,9 +4348,9 @@ snapshots: - rollup - webpack - '@storybook/csf-plugin@10.4.0-alpha.8(esbuild@0.27.3)(rollup@4.57.1)(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@24.10.12))': + '@storybook/csf-plugin@10.4.0-alpha.12(esbuild@0.27.3)(rollup@4.57.1)(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@24.10.12))': dependencies: - storybook: 10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + storybook: 10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) unplugin: 2.3.11 optionalDependencies: esbuild: 0.27.3 @@ -4345,44 +4364,49 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@storybook/react-dom-shim@10.4.0-alpha.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': + '@storybook/react-dom-shim@10.4.0-alpha.12(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': dependencies: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - storybook: 10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + storybook: 10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + optionalDependencies: + '@types/react': 18.3.28 - '@storybook/react-vite@10.4.0-alpha.8(esbuild@0.27.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.57.1)(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.12))': + '@storybook/react-vite@10.4.0-alpha.12(@types/react@18.3.28)(esbuild@0.27.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.57.1)(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.12))': dependencies: '@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.12)) '@rollup/pluginutils': 5.3.0(rollup@4.57.1) - '@storybook/builder-vite': 10.4.0-alpha.8(esbuild@0.27.3)(rollup@4.57.1)(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@24.10.12)) - '@storybook/react': 10.4.0-alpha.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) + '@storybook/builder-vite': 10.4.0-alpha.12(esbuild@0.27.3)(rollup@4.57.1)(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@24.10.12)) + '@storybook/react': 10.4.0-alpha.12(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) empathic: 2.0.0 magic-string: 0.30.21 react: 19.2.4 react-docgen: 8.0.2 react-dom: 19.2.4(react@19.2.4) resolve: 1.22.11 - storybook: 10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + storybook: 10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) tsconfig-paths: 4.2.0 vite: 7.3.1(@types/node@24.10.12) transitivePeerDependencies: + - '@types/react' + - '@types/react-dom' - esbuild - rollup - supports-color - typescript - webpack - '@storybook/react@10.4.0-alpha.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)': + '@storybook/react@10.4.0-alpha.12(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)': dependencies: '@storybook/global': 5.0.0 - '@storybook/react-dom-shim': 10.4.0-alpha.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) + '@storybook/react-dom-shim': 10.4.0-alpha.12(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) react: 19.2.4 react-docgen: 8.0.2 react-docgen-typescript: 2.4.0(typescript@5.9.3) react-dom: 19.2.4(react@19.2.4) - storybook: 10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + storybook: 10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) optionalDependencies: + '@types/react': 18.3.28 typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -5725,11 +5749,11 @@ snapshots: space-separated-tokens@2.0.2: {} - storybook-addon-test-codegen@3.0.1(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)): + storybook-addon-test-codegen@3.0.1(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)): dependencies: - storybook: 10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + storybook: 10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: '@storybook/global': 5.0.0 '@storybook/icons': 2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -5744,6 +5768,8 @@ snapshots: semver: 7.7.4 use-sync-external-store: 1.6.0(react@19.2.4) ws: 8.19.0 + optionalDependencies: + '@types/react': 18.3.28 transitivePeerDependencies: - '@testing-library/dom' - bufferutil diff --git a/packages/addon-mcp/pnpm-lock.yaml b/packages/addon-mcp/pnpm-lock.yaml index a139c60c..1abc3276 100644 --- a/packages/addon-mcp/pnpm-lock.yaml +++ b/packages/addon-mcp/pnpm-lock.yaml @@ -7,11 +7,11 @@ settings: catalogs: default: '@storybook/addon-a11y': - specifier: 10.4.0-alpha.8 - version: 10.4.0-alpha.8 + specifier: 10.4.0-alpha.12 + version: 10.4.0-alpha.12 '@storybook/addon-vitest': - specifier: 10.4.0-alpha.8 - version: 10.4.0-alpha.8 + specifier: 10.4.0-alpha.12 + version: 10.4.0-alpha.12 '@tmcp/adapter-valibot': specifier: ^0.1.5 version: 0.1.5 @@ -19,8 +19,8 @@ catalogs: specifier: ^0.8.5 version: 0.8.5 storybook: - specifier: 10.4.0-alpha.8 - version: 10.4.0-alpha.8 + specifier: 10.4.0-alpha.12 + version: 10.4.0-alpha.12 tmcp: specifier: ^1.19.3 version: 1.19.3 @@ -53,13 +53,13 @@ importers: devDependencies: '@storybook/addon-a11y': specifier: 'catalog:' - version: 10.4.0-alpha.8(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) + version: 10.4.0-alpha.12(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) '@storybook/addon-vitest': specifier: 'catalog:' - version: 10.4.0-alpha.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) + version: 10.4.0-alpha.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) storybook: specifier: 'catalog:' - version: 10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 10.4.0-alpha.12(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) packages: @@ -237,18 +237,18 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - '@storybook/addon-a11y@10.4.0-alpha.8': - resolution: {integrity: sha512-D/HoLv2KPk/QNAXwJMRamH7w1148Fm3xSlMulwCm1in6XfL2dkomc3khC3Fxzs4/QJJWczSw9xDCHrGjkCX56g==} + '@storybook/addon-a11y@10.4.0-alpha.12': + resolution: {integrity: sha512-exH6qseQ0uC5/grhDdrkeLioB5IvzBfZwPJAicsBLBKNcJ9hu7xgaI4YVE8SeA5YtXBW7ATjzLaVwM2syS8BmA==} peerDependencies: - storybook: ^10.4.0-alpha.8 + storybook: ^10.4.0-alpha.12 - '@storybook/addon-vitest@10.4.0-alpha.8': - resolution: {integrity: sha512-UQg07DBAW4eryFMYXiJmlj4lmmLWqCkfXBvfGlFvvVKFsbMM0wUCp5XeDckskJCVVALb4O02fObAIvAs24FJaw==} + '@storybook/addon-vitest@10.4.0-alpha.12': + resolution: {integrity: sha512-vqvXoGHHbJ1GKdsuIoG9RNjPH9Scy4edaEOfAt9MqQltQnj6gvYXqaFld85weaFzASHFLWtlsZSKv1QMPzjcQg==} peerDependencies: '@vitest/browser': ^3.0.0 || ^4.0.0 '@vitest/browser-playwright': ^4.0.0 '@vitest/runner': ^3.0.0 || ^4.0.0 - storybook: ^10.4.0-alpha.8 + storybook: ^10.4.0-alpha.12 vitest: ^3.0.0 || ^4.0.0 peerDependenciesMeta: '@vitest/browser': @@ -505,14 +505,20 @@ packages: sqids@0.3.0: resolution: {integrity: sha512-lOQK1ucVg+W6n3FhRwwSeUijxe93b51Bfz5PMRMihVf1iVkl82ePQG7V5vwrhzB11v0NtsR25PSZRGiSomJaJw==} - storybook@10.4.0-alpha.8: - resolution: {integrity: sha512-r3fGYI57j/9KTQmY9t/f+qJRVe0M3DJnez4jD++Dr2LTbgYOz6E6qFryXFGlHK0BVz1R5O/gzDdL0fn+tOhMgA==} + storybook@10.4.0-alpha.12: + resolution: {integrity: sha512-DVi/v+vXwf0itbM8tm8XtEjaVmf2lsTHmdZQICOQGz7Mnr5181vMJpfvdNbdnXbyLXmVvagqJS+m1AjMTwi9xQ==} hasBin: true peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 prettier: ^2 || ^3 + vite-plus: ^0.1.15 peerDependenciesMeta: + '@types/react': + optional: true prettier: optional: true + vite-plus: + optional: true strip-indent@3.0.0: resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} @@ -661,17 +667,17 @@ snapshots: '@standard-schema/spec@1.1.0': {} - '@storybook/addon-a11y@10.4.0-alpha.8(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': + '@storybook/addon-a11y@10.4.0-alpha.12(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': dependencies: '@storybook/global': 5.0.0 axe-core: 4.11.1 - storybook: 10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + storybook: 10.4.0-alpha.12(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@storybook/addon-vitest@10.4.0-alpha.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': + '@storybook/addon-vitest@10.4.0-alpha.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': dependencies: '@storybook/global': 5.0.0 '@storybook/icons': 2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - storybook: 10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + storybook: 10.4.0-alpha.12(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) transitivePeerDependencies: - react - react-dom @@ -918,7 +924,7 @@ snapshots: sqids@0.3.0: {} - storybook@10.4.0-alpha.8(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + storybook@10.4.0-alpha.12(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: '@storybook/global': 5.0.0 '@storybook/icons': 2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) diff --git a/packages/addon-mcp/src/instructions/build-server-instructions.test.ts b/packages/addon-mcp/src/instructions/build-server-instructions.test.ts index 3e417278..5778ad80 100644 --- a/packages/addon-mcp/src/instructions/build-server-instructions.test.ts +++ b/packages/addon-mcp/src/instructions/build-server-instructions.test.ts @@ -7,6 +7,7 @@ describe('buildServerInstructions', () => { devEnabled: true, testEnabled: true, docsEnabled: true, + changeDetectionEnabled: true, }); expect(instructions).toMatchInlineSnapshot(` @@ -16,7 +17,7 @@ describe('buildServerInstructions', () => { - Before creating or editing components or stories, call **get-storybook-story-instructions**. - Treat that tool's output as the source of truth for framework-specific imports, story patterns, and testing conventions. - - After changing any component or story, call **preview-stories**. + - After changing any component or story, call **get-changed-stories** to discover new/modified/related stories, then call **preview-stories** to retrieve preview URLs. - Always include every returned preview URL in your user-facing response so the user can verify the visual result. ## Validation Workflow @@ -51,6 +52,7 @@ describe('buildServerInstructions', () => { devEnabled: true, testEnabled: false, docsEnabled: false, + changeDetectionEnabled: true, }); expect(instructions).toMatchInlineSnapshot(` @@ -60,7 +62,27 @@ describe('buildServerInstructions', () => { - Before creating or editing components or stories, call **get-storybook-story-instructions**. - Treat that tool's output as the source of truth for framework-specific imports, story patterns, and testing conventions. - - After changing any component or story, call **preview-stories**. + - After changing any component or story, call **get-changed-stories** to discover new/modified/related stories, then call **preview-stories** to retrieve preview URLs. + - Always include every returned preview URL in your user-facing response so the user can verify the visual result." + `); + }); + + it('omits get-changed-stories step when change detection is disabled', () => { + const instructions = buildServerInstructions({ + devEnabled: true, + testEnabled: false, + docsEnabled: false, + changeDetectionEnabled: false, + }); + + expect(instructions).toMatchInlineSnapshot(` + "Follow these workflows when working with UI and/or Storybook. + + ## UI Building and Story Writing Workflow + + - Before creating or editing components or stories, call **get-storybook-story-instructions**. + - Treat that tool's output as the source of truth for framework-specific imports, story patterns, and testing conventions. + - After changing any component or story, call **preview-stories** to retrieve preview URLs. - Always include every returned preview URL in your user-facing response so the user can verify the visual result." `); }); diff --git a/packages/addon-mcp/src/instructions/build-server-instructions.ts b/packages/addon-mcp/src/instructions/build-server-instructions.ts index 5e7a2989..e85dd654 100644 --- a/packages/addon-mcp/src/instructions/build-server-instructions.ts +++ b/packages/addon-mcp/src/instructions/build-server-instructions.ts @@ -6,13 +6,23 @@ export type BuildServerInstructionsOptions = { devEnabled: boolean; testEnabled: boolean; docsEnabled: boolean; + changeDetectionEnabled?: boolean; }; export function buildServerInstructions(options: BuildServerInstructionsOptions): string { const sections = ['Follow these workflows when working with UI and/or Storybook.']; if (options.devEnabled) { - sections.push(devInstructions.trim()); + sections.push( + devInstructions + .replace( + '{{PREVIEW_STORIES_STEP}}', + (options.changeDetectionEnabled ?? false) + ? 'After changing any component or story, call **get-changed-stories** to discover new/modified/related stories, then call **preview-stories** to retrieve preview URLs.' + : 'After changing any component or story, call **preview-stories** to retrieve preview URLs.', + ) + .trim(), + ); } if (options.testEnabled) { diff --git a/packages/addon-mcp/src/instructions/dev-instructions.md b/packages/addon-mcp/src/instructions/dev-instructions.md index 9b481e45..847625f6 100644 --- a/packages/addon-mcp/src/instructions/dev-instructions.md +++ b/packages/addon-mcp/src/instructions/dev-instructions.md @@ -2,5 +2,5 @@ - Before creating or editing components or stories, call **get-storybook-story-instructions**. - Treat that tool's output as the source of truth for framework-specific imports, story patterns, and testing conventions. -- After changing any component or story, call **preview-stories**. +- {{PREVIEW_STORIES_STEP}} - Always include every returned preview URL in your user-facing response so the user can verify the visual result. diff --git a/packages/addon-mcp/src/instructions/story-testing-instructions.md b/packages/addon-mcp/src/instructions/story-testing-instructions.md index ffb53968..e297f787 100644 --- a/packages/addon-mcp/src/instructions/story-testing-instructions.md +++ b/packages/addon-mcp/src/instructions/story-testing-instructions.md @@ -5,7 +5,7 @@ ### Workflow 1. Make your change -2. Run `{{RUN_STORY_TESTS_TOOL_NAME}}` with affected stories for focused feedback (faster while iterating) +2. Run `{{RUN_STORY_TESTS_TOOL_NAME}}` with related stories for focused feedback (faster while iterating) 3. If tests fail: analyze, fix{{A11Y_FIX_SUFFIX}}, re-run 4. Repeat until all tests pass diff --git a/packages/addon-mcp/src/instructions/storybook-story-instructions.md b/packages/addon-mcp/src/instructions/storybook-story-instructions.md index 622eef3d..ac7589af 100644 --- a/packages/addon-mcp/src/instructions/storybook-story-instructions.md +++ b/packages/addon-mcp/src/instructions/storybook-story-instructions.md @@ -146,5 +146,7 @@ play: async ({ canvas }) => { ## Story Linking Agent Behavior - ALWAYS provide story links after any changes to stories files, including changes to existing stories. +- {{STORY_LINKING_WORKFLOW}} +- When sharing links, choose the most relevant subset for the user and avoid long lists (generally no more than 5 links). +- {{CHANGED_STORY_FALLBACK_LINK_GUIDANCE}} - After changing any UI components, ALWAYS search for related stories that might cover the changes you've made. If you find any, provide the story links to the user. THIS IS VERY IMPORTANT, as it allows the user to visually inspect the changes you've made. Even later in a session when changing UI components or stories that have already been linked to previously, YOU MUST PROVIDE THE LINKS AGAIN. -- Use the {{PREVIEW_STORIES_TOOL_NAME}} tool to get the correct URLs for links to stories. diff --git a/packages/addon-mcp/src/mcp-handler.ts b/packages/addon-mcp/src/mcp-handler.ts index 274bf5b2..0a831a83 100644 --- a/packages/addon-mcp/src/mcp-handler.ts +++ b/packages/addon-mcp/src/mcp-handler.ts @@ -3,6 +3,7 @@ import { ValibotJsonSchemaAdapter } from '@tmcp/adapter-valibot'; import { HttpTransport } from '@tmcp/transport-http'; import pkgJson from '../package.json' with { type: 'json' }; import { addPreviewStoriesTool } from './tools/preview-stories.ts'; +import { addGetChangedStoriesTool } from './tools/get-changed-stories.ts'; import { addGetUIBuildingInstructionsTool } from './tools/get-storybook-story-instructions.ts'; import { addListAllDocumentationTool, @@ -32,6 +33,8 @@ let a11yEnabled: boolean | undefined; const initializeMCPServer = async (options: Options, multiSource?: boolean) => { const core = await options.presets.apply('core', {}); + const features = await options.presets.apply('features', {}); + const changeDetectionEnabled = features?.changeDetection ?? false; disableTelemetry = core?.disableTelemetry ?? false; // Determine tool availability before creating server so instructions can be tailored @@ -48,6 +51,7 @@ const initializeMCPServer = async (options: Options, multiSource?: boolean) => { devEnabled: server?.ctx.custom?.toolsets?.dev ?? true, testEnabled: (server?.ctx.custom?.toolsets?.test ?? true) && !!addonVitestConstants, docsEnabled: (server?.ctx.custom?.toolsets?.docs ?? true) && manifestStatus.available, + changeDetectionEnabled, }); }, capabilities: { @@ -75,6 +79,10 @@ const initializeMCPServer = async (options: Options, multiSource?: boolean) => { await addPreviewStoriesTool(server); await addGetUIBuildingInstructionsTool(server); + if (changeDetectionEnabled) { + await addGetChangedStoriesTool(server); + } + // Register test addon tools await addRunStoryTestsTool(server, { a11yEnabled }); diff --git a/packages/addon-mcp/src/tools/get-changed-stories.test.ts b/packages/addon-mcp/src/tools/get-changed-stories.test.ts new file mode 100644 index 00000000..b749e0e3 --- /dev/null +++ b/packages/addon-mcp/src/tools/get-changed-stories.test.ts @@ -0,0 +1,303 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { McpServer } from 'tmcp'; +import { ValibotJsonSchemaAdapter } from '@tmcp/adapter-valibot'; +import { addGetChangedStoriesTool } from './get-changed-stories.ts'; +import type { AddonContext } from '../types.ts'; +import * as fetchStoryIndex from '../utils/fetch-story-index.ts'; +import smallStoryIndexFixture from '../../fixtures/small-story-index.fixture.json' with { type: 'json' }; +import { GET_CHANGED_STORIES_TOOL_NAME } from './tool-names.ts'; +import type { StoryIndex } from 'storybook/internal/types'; + +const { mockGetStatusStore } = vi.hoisted(() => ({ + mockGetStatusStore: vi.fn(), +})); + +vi.mock('storybook/internal/core-server', () => ({ + experimental_getStatusStore: (...args: unknown[]) => mockGetStatusStore(...args), +})); + +describe('getChangedStoriesTool', () => { + let server: McpServer; + const testContext: AddonContext = { + origin: 'http://localhost:6006', + options: {} as AddonContext['options'], + disableTelemetry: true, + }; + + beforeEach(async () => { + mockGetStatusStore.mockReset(); + const adapter = new ValibotJsonSchemaAdapter(); + server = new McpServer( + { + name: 'test-server', + version: '1.0.0', + description: 'Test server for get-changed-stories tool', + }, + { + adapter, + capabilities: { + tools: { listChanged: true }, + }, + }, + ).withContext(); + + await server.receive( + { + jsonrpc: '2.0', + id: 1, + method: 'initialize', + params: { + protocolVersion: '2025-06-18', + capabilities: {}, + clientInfo: { name: 'test', version: '1.0.0' }, + }, + }, + { + sessionId: 'test-session', + }, + ); + + await addGetChangedStoriesTool(server); + vi.spyOn(fetchStoryIndex, 'fetchStoryIndex').mockResolvedValue( + smallStoryIndexFixture as unknown as StoryIndex, + ); + }); + + async function callTool() { + return server.receive( + { + jsonrpc: '2.0' as const, + id: 1, + method: 'tools/call', + params: { + name: GET_CHANGED_STORIES_TOOL_NAME, + arguments: {}, + }, + }, + { + sessionId: 'test-session', + custom: testContext, + }, + ); + } + + function getResultText(response: unknown): string { + if (!response || typeof response !== 'object') return ''; + const result = (response as { result?: { content?: Array<{ text?: string }> } }).result; + return result?.content?.[0]?.text ?? ''; + } + + it('returns grouped markdown text with changed story metadata', async () => { + mockGetStatusStore.mockReturnValue({ + getAll: () => ({ + 'button--primary': { + 'storybook/change-detection': { + value: 'status-value:new', + storyId: 'button--primary', + }, + }, + 'button--secondary': { + 'storybook/change-detection': { + value: 'status-value:modified', + storyId: 'button--secondary', + }, + }, + 'input--default': { + 'storybook/change-detection': { + value: 'status-value:affected', + storyId: 'input--default', + }, + }, + }), + }); + + const response = await callTool(); + const text = getResultText(response); + + expect(fetchStoryIndex.fetchStoryIndex).toHaveBeenCalledWith('http://localhost:6006'); + expect(text).toMatchInlineSnapshot(` + "Detected 3 changed stories (1 new, 1 modified, 1 related). + + New stories: + - \`button--primary\`: Button / Primary (\`./src/Button.stories.tsx\`) + + Modified stories: + - \`button--secondary\`: Button / Secondary (\`./src/Button.stories.tsx\`) + + Related stories: + - \`input--default\`: Input / Default (\`./src/Input.stories.tsx\`)" + `); + }); + + it('filters out unsupported status values', async () => { + mockGetStatusStore.mockReturnValue({ + getAll: () => ({ + 'button--primary': { + 'storybook/change-detection': { + value: 'status-value:new', + storyId: 'button--primary', + }, + }, + 'button--secondary': { + 'storybook/change-detection': { + value: 'status-value:success', + storyId: 'button--secondary', + }, + }, + }), + }); + + const response = await callTool(); + const text = getResultText(response); + + expect(text).toMatchInlineSnapshot(` + "Detected 1 changed story (1 new, 0 modified, 0 related). + + New stories: + - \`button--primary\`: Button / Primary (\`./src/Button.stories.tsx\`)" + `); + }); + + it('groups by new, modified, related, then sorts by storyId', async () => { + mockGetStatusStore.mockReturnValue({ + getAll: () => ({ + 'input--default': { + 'storybook/change-detection': { + value: 'status-value:affected', + storyId: 'input--default', + }, + }, + 'button--secondary': { + 'storybook/change-detection': { + value: 'status-value:new', + storyId: 'button--secondary', + }, + }, + 'button--primary': { + 'storybook/change-detection': { + value: 'status-value:new', + storyId: 'button--primary', + }, + }, + }), + }); + + const response = await callTool(); + const text = getResultText(response); + + expect(text).toMatchInlineSnapshot(` + "Detected 3 changed stories (2 new, 0 modified, 1 related). + + New stories: + - \`button--primary\`: Button / Primary (\`./src/Button.stories.tsx\`) + - \`button--secondary\`: Button / Secondary (\`./src/Button.stories.tsx\`) + + Related stories: + - \`input--default\`: Input / Default (\`./src/Input.stories.tsx\`)" + `); + }); + + it('supports getAll() status-store API', async () => { + mockGetStatusStore.mockReturnValue({ + getAll: () => ({ + 'button--primary': { + 'storybook/change-detection': { + value: 'status-value:new', + storyId: 'button--primary', + }, + }, + }), + }); + + const response = await callTool(); + const text = getResultText(response); + + expect(text).toContain('Detected 1 changed story (1 new, 0 modified, 0 related).'); + expect(text).toContain('- `button--primary`: Button / Primary (`./src/Button.stories.tsx`)'); + }); + + it('supports getAll() for modified stories', async () => { + mockGetStatusStore.mockReturnValue({ + getAll: () => ({ + 'button--secondary': { + 'storybook/change-detection': { + value: 'status-value:modified', + storyId: 'button--secondary', + }, + }, + }), + }); + + const response = await callTool(); + const text = getResultText(response); + + expect(text).toContain('Detected 1 changed story (0 new, 1 modified, 0 related).'); + expect(text).toContain( + '- `button--secondary`: Button / Secondary (`./src/Button.stories.tsx`)', + ); + }); + + it('omits changed stories that are not in the index', async () => { + mockGetStatusStore.mockReturnValue({ + getAll: () => ({ + 'missing--story': { + 'storybook/change-detection': { + value: 'status-value:modified', + storyId: 'missing--story', + }, + }, + }), + }); + + const response = await callTool(); + const text = getResultText(response); + + expect(text).toMatchInlineSnapshot( + `"Detected 0 changed stories (0 new, 0 modified, 0 related)."`, + ); + }); + + it('returns an MCP error when status store cannot be read', async () => { + mockGetStatusStore.mockReturnValue({}); + + const response = await server.receive( + { + jsonrpc: '2.0' as const, + id: 1, + method: 'tools/call', + params: { name: GET_CHANGED_STORIES_TOOL_NAME, arguments: {} }, + }, + { sessionId: 'test-session', custom: testContext }, + ); + + expect(response.result).toEqual({ + content: [ + { + type: 'text', + text: 'Error: statusStore.getAll is not a function', + }, + ], + isError: true, + }); + }); + + it('returns early without fetching index when there are no relevant changed statuses', async () => { + mockGetStatusStore.mockReturnValue({ + getAll: () => ({ + 'button--primary': { + 'storybook/change-detection': { + value: 'status-value:success', + storyId: 'button--primary', + }, + }, + }), + }); + + const callCountBefore = vi.mocked(fetchStoryIndex.fetchStoryIndex).mock.calls.length; + const response = await callTool(); + const text = getResultText(response); + + expect(text).toBe('No new, modified, or related stories detected.'); + expect(vi.mocked(fetchStoryIndex.fetchStoryIndex).mock.calls.length).toBe(callCountBefore); + }); +}); diff --git a/packages/addon-mcp/src/tools/get-changed-stories.ts b/packages/addon-mcp/src/tools/get-changed-stories.ts new file mode 100644 index 00000000..56c95f6e --- /dev/null +++ b/packages/addon-mcp/src/tools/get-changed-stories.ts @@ -0,0 +1,168 @@ +import type { McpServer } from 'tmcp'; +import { experimental_getStatusStore } from 'storybook/internal/core-server'; +import { collectTelemetry } from '../telemetry.ts'; +import type { AddonContext } from '../types.ts'; +import { errorToMCPContent } from '../utils/errors.ts'; +import { fetchStoryIndex } from '../utils/fetch-story-index.ts'; +import { GET_CHANGED_STORIES_TOOL_NAME } from './tool-names.ts'; + +const CHANGE_DETECTION_TYPE = 'storybook/change-detection'; +const INCLUDED_STATUS_VALUES = new Set([ + 'status-value:new', + 'status-value:modified', + 'status-value:affected', +]); + +type StatusValue = + | 'status-value:pending' + | 'status-value:success' + | 'status-value:new' + | 'status-value:modified' + | 'status-value:affected' + | 'status-value:warning' + | 'status-value:error' + | 'status-value:unknown'; + +type StatusesByStoryIdAndTypeId = Record>; + +interface Status { + value: StatusValue; + typeId: string; + storyId: string; + title: string; + description: string; + data?: any; + sidebarContextMenu?: boolean; +} + +interface ChangedStory { + storyId: string; + statusValue: StatusValue; + title: string; + name: string; + importPath: string; +} + +function statusPriority(statusValue: StatusValue): number { + if (statusValue === 'status-value:new') return 0; + if (statusValue === 'status-value:modified') return 1; + return 2; +} + +export async function addGetChangedStoriesTool(server: McpServer) { + server.tool( + { + name: GET_CHANGED_STORIES_TOOL_NAME, + title: 'Get changed stories metadata', + description: `Get Storybook stories marked as new, modified, or related. Returns story metadata only (no URLs).`, + enabled: () => server.ctx.custom?.toolsets?.dev ?? true, + }, + async () => { + try { + const { origin, disableTelemetry } = server.ctx.custom ?? {}; + if (!origin) { + throw new Error('Origin is required in addon context'); + } + + const statusStore = experimental_getStatusStore(CHANGE_DETECTION_TYPE); + const allStatuses = statusStore.getAll() as StatusesByStoryIdAndTypeId; + const changedStoriesFromStatusStore: Status[] = []; + for (const byType of Object.values(allStatuses)) { + const status = byType?.[CHANGE_DETECTION_TYPE]; + if (status?.value && INCLUDED_STATUS_VALUES.has(status.value)) { + changedStoriesFromStatusStore.push(status); + } + } + + if (changedStoriesFromStatusStore.length === 0) { + if (!disableTelemetry) { + await collectTelemetry({ + event: 'tool:getChangedStories', + server, + toolset: 'dev', + storyCount: 0, + newStoryCount: 0, + modifiedStoryCount: 0, + affectedStoryCount: 0, + }); + } + + return { + content: [ + { type: 'text' as const, text: 'No new, modified, or related stories detected.' }, + ], + }; + } + + const index = await fetchStoryIndex(origin); + const stories = changedStoriesFromStatusStore.flatMap( + ({ storyId, value }) => { + const entry = index.entries[storyId]; + if (!entry) { + return []; + } + return [ + { + storyId, + statusValue: value, + title: entry.title, + name: entry.name, + importPath: entry.importPath, + }, + ]; + }, + ); + + stories.sort((a, b) => { + const priorityDelta = statusPriority(a.statusValue) - statusPriority(b.statusValue); + return priorityDelta !== 0 ? priorityDelta : a.storyId.localeCompare(b.storyId); + }); + + const buckets = { + new: stories.filter((story) => story.statusValue === 'status-value:new'), + modified: stories.filter((story) => story.statusValue === 'status-value:modified'), + affected: stories.filter((story) => story.statusValue === 'status-value:affected'), + }; + const counts = { + new: buckets.new.length, + modified: buckets.modified.length, + affected: buckets.affected.length, + }; + + if (!disableTelemetry) { + await collectTelemetry({ + event: 'tool:getChangedStories', + server, + toolset: 'dev', + storyCount: stories.length, + newStoryCount: counts.new, + modifiedStoryCount: counts.modified, + affectedStoryCount: counts.affected, + }); + } + + let text = `Detected ${stories.length} changed stor${stories.length === 1 ? 'y' : 'ies'} (${counts.new} new, ${counts.modified} modified, ${counts.affected} related).`; + + const serializeStory = ({ storyId, title, name, importPath }: ChangedStory) => + `- \`${storyId}\`: ${title} / ${name} (\`${importPath}\`)`; + + if (buckets.new.length > 0) { + text += `\n\nNew stories:\n`; + text += buckets.new.map(serializeStory).join('\n'); + } + if (buckets.modified.length > 0) { + text += `\n\nModified stories:\n`; + text += buckets.modified.map(serializeStory).join('\n'); + } + if (buckets.affected.length > 0) { + text += `\n\nRelated stories:\n`; + text += buckets.affected.map(serializeStory).join('\n'); + } + + return { content: [{ type: 'text' as const, text }] }; + } catch (error) { + return errorToMCPContent(error); + } + }, + ); +} diff --git a/packages/addon-mcp/src/tools/get-storybook-story-instructions.test.ts b/packages/addon-mcp/src/tools/get-storybook-story-instructions.test.ts index 83bbb991..84e47e29 100644 --- a/packages/addon-mcp/src/tools/get-storybook-story-instructions.test.ts +++ b/packages/addon-mcp/src/tools/get-storybook-story-instructions.test.ts @@ -4,7 +4,11 @@ import { ValibotJsonSchemaAdapter } from '@tmcp/adapter-valibot'; import { getAddonVitestConstants } from './run-story-tests.ts'; import { addGetUIBuildingInstructionsTool } from './get-storybook-story-instructions.ts'; import type { AddonContext } from '../types.ts'; -import { PREVIEW_STORIES_TOOL_NAME, GET_UI_BUILDING_INSTRUCTIONS_TOOL_NAME } from './tool-names.ts'; +import { + PREVIEW_STORIES_TOOL_NAME, + GET_CHANGED_STORIES_TOOL_NAME, + GET_UI_BUILDING_INSTRUCTIONS_TOOL_NAME, +} from './tool-names.ts'; vi.mock('./run-story-tests.ts', () => ({ getAddonVitestConstants: vi.fn(), @@ -157,7 +161,11 @@ describe('getUIBuildingInstructionsTool', () => { it('should return UI building instructions with framework placeholders replaced', async () => { const mockOptions = { presets: { - apply: vi.fn().mockResolvedValue('@storybook/react-vite'), + apply: vi.fn(async (presetName: string) => { + if (presetName === 'framework') return '@storybook/react-vite'; + if (presetName === 'features') return { changeDetection: true }; + return undefined; + }), }, }; @@ -188,11 +196,56 @@ describe('getUIBuildingInstructionsTool', () => { expect(instructions).toContain('@storybook/react-vite'); expect(instructions).toContain('@storybook/react'); expect(instructions).toContain(PREVIEW_STORIES_TOOL_NAME); + expect(instructions).toContain(GET_CHANGED_STORIES_TOOL_NAME); // Check that no placeholders remain expect(instructions).not.toContain('{{FRAMEWORK}}'); expect(instructions).not.toContain('{{RENDERER}}'); expect(instructions).not.toContain('{{PREVIEW_STORIES_TOOL_NAME}}'); + expect(instructions).not.toContain('{{STORY_LINKING_WORKFLOW}}'); + expect(instructions).not.toContain('{{CHANGED_STORY_FALLBACK_LINK_GUIDANCE}}'); + }); + + it('should not mention changed stories workflow when change detection is disabled', async () => { + const mockOptions = { + presets: { + apply: vi.fn(async (presetName: string) => { + if (presetName === 'framework') { + return '@storybook/react-vite'; + } + if (presetName === 'features') { + return { changeDetection: false }; + } + return undefined; + }), + }, + }; + + const testContext: AddonContext = { + origin: 'http://localhost:6006', + options: mockOptions as any, + disableTelemetry: true, + }; + + const request = { + jsonrpc: '2.0' as const, + id: 1, + method: 'tools/call', + params: { + name: GET_UI_BUILDING_INSTRUCTIONS_TOOL_NAME, + arguments: {}, + }, + }; + + const response = await server.receive(request, { + sessionId: 'test-session', + custom: testContext, + }); + + const instructions = response.result?.content[0].text as string; + + expect(instructions).toContain(PREVIEW_STORIES_TOOL_NAME); + expect(instructions).not.toContain(GET_CHANGED_STORIES_TOOL_NAME); }); it('should handle Vue framework', async () => { diff --git a/packages/addon-mcp/src/tools/get-storybook-story-instructions.ts b/packages/addon-mcp/src/tools/get-storybook-story-instructions.ts index eea98dfe..2c5cd7fa 100644 --- a/packages/addon-mcp/src/tools/get-storybook-story-instructions.ts +++ b/packages/addon-mcp/src/tools/get-storybook-story-instructions.ts @@ -6,9 +6,9 @@ import storyTestingInstructionsTemplate from '../instructions/story-testing-inst import a11yInstructionsTemplate from '../instructions/a11y-instructions.md'; import { errorToMCPContent } from '../utils/errors.ts'; import type { AddonContext } from '../types.ts'; -import { isAddonA11yEnabled } from '../utils/is-addon-a11y-enabled.ts'; import { GET_UI_BUILDING_INSTRUCTIONS_TOOL_NAME, + GET_CHANGED_STORIES_TOOL_NAME, PREVIEW_STORIES_TOOL_NAME, RUN_STORY_TESTS_TOOL_NAME, } from './tool-names.ts'; @@ -77,14 +77,23 @@ Even if you're familiar with Storybook, call this tool to ensure you're followin } const frameworkPreset = await options.presets.apply('framework'); + const featuresPreset = await options.presets.apply('features', {}); + const changeDetectionEnabled = featuresPreset?.changeDetection ?? false; const framework = typeof frameworkPreset === 'string' ? frameworkPreset : frameworkPreset?.name; const renderer = frameworkToRendererMap[framework!]; + const storyLinkingWorkflow = changeDetectionEnabled + ? `After changing UI, call \`${GET_CHANGED_STORIES_TOOL_NAME}\` first, then use \`${PREVIEW_STORIES_TOOL_NAME}\` with selected \`storyId\` values from those results.` + : `After changing UI, call \`${PREVIEW_STORIES_TOOL_NAME}\` and share the most relevant links for the changes.`; + const changedStoryFallbackLinkGuidance = changeDetectionEnabled + ? `If you do not share all changed story links, include this Storybook fallback link so the user can view the complete changed list: \`/?statuses=affected;modified;new\`.` + : `When linking only a subset of stories, mention that additional relevant stories may exist in Storybook.`; let uiInstructions = storyInstructionsTemplate .replace('{{FRAMEWORK}}', framework) .replace('{{RENDERER}}', renderer ?? framework) - .replace('{{PREVIEW_STORIES_TOOL_NAME}}', PREVIEW_STORIES_TOOL_NAME); + .replace('{{STORY_LINKING_WORKFLOW}}', storyLinkingWorkflow) + .replace('{{CHANGED_STORY_FALLBACK_LINK_GUIDANCE}}', changedStoryFallbackLinkGuidance); // Conditionally append story testing instructions if test toolset is enabled and addon-vitest is available const testToolsetAvailable = diff --git a/packages/addon-mcp/src/tools/tool-names.ts b/packages/addon-mcp/src/tools/tool-names.ts index 86543efc..30c9f0d5 100644 --- a/packages/addon-mcp/src/tools/tool-names.ts +++ b/packages/addon-mcp/src/tools/tool-names.ts @@ -3,5 +3,6 @@ */ export const PREVIEW_STORIES_TOOL_NAME = 'preview-stories'; +export const GET_CHANGED_STORIES_TOOL_NAME = 'get-changed-stories'; export const GET_UI_BUILDING_INSTRUCTIONS_TOOL_NAME = 'get-storybook-story-instructions'; export const RUN_STORY_TESTS_TOOL_NAME = 'run-story-tests'; diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 35bef716..96edea4d 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -6,16 +6,16 @@ packages: - '!eval/tasks/*/trials/*/project' catalog: - '@storybook/addon-a11y': 10.4.0-alpha.8 - '@storybook/addon-docs': 10.4.0-alpha.8 - '@storybook/addon-vitest': 10.4.0-alpha.8 - '@storybook/react-vite': 10.4.0-alpha.8 - '@storybook/addon-themes': 10.4.0-alpha.8 + '@storybook/addon-a11y': 10.4.0-alpha.12 + '@storybook/addon-docs': 10.4.0-alpha.12 + '@storybook/addon-vitest': 10.4.0-alpha.12 + '@storybook/react-vite': 10.4.0-alpha.12 + '@storybook/addon-themes': 10.4.0-alpha.12 '@tmcp/adapter-valibot': ^0.1.5 '@tmcp/transport-http': ^0.8.5 '@tmcp/transport-stdio': ^0.4.2 - eslint-plugin-storybook: 10.4.0-alpha.8 - storybook: 10.4.0-alpha.8 + eslint-plugin-storybook: 10.4.0-alpha.12 + storybook: 10.4.0-alpha.12 tmcp: ^1.19.3 tsdown: ^0.15.12 typescript: ^5.9.3 @@ -28,10 +28,10 @@ catalog: catalogs: trials: '@eslint/js': 9.39.1 - '@storybook/addon-a11y': 10.4.0-alpha.8 - '@storybook/addon-docs': 10.4.0-alpha.8 - '@storybook/addon-vitest': 10.4.0-alpha.8 - '@storybook/react-vite': 10.4.0-alpha.8 + '@storybook/addon-a11y': 10.4.0-alpha.12 + '@storybook/addon-docs': 10.4.0-alpha.12 + '@storybook/addon-vitest': 10.4.0-alpha.12 + '@storybook/react-vite': 10.4.0-alpha.12 '@types/node': 24.10.1 '@types/react': 19.2.6 '@types/react-dom': 19.2.3 @@ -40,11 +40,11 @@ catalogs: eslint: 9.39.1 eslint-plugin-react-hooks: 7.0.1 eslint-plugin-react-refresh: 0.4.24 - eslint-plugin-storybook: 10.4.0-alpha.8 + eslint-plugin-storybook: 10.4.0-alpha.12 globals: 16.5.0 react: 19.2.0 react-dom: 19.2.0 - storybook: 10.4.0-alpha.8 + storybook: 10.4.0-alpha.12 typescript: 5.9.3 typescript-eslint: 8.47.0 vite: 7.2.2