diff --git a/.gitignore b/.gitignore index fa4ab110..7864c271 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,8 @@ storybook-static/ # Vitest browser-mode failure screenshots **/__screenshots__/ +# Vitest 4 writes failure screenshots/traces here as well, keyed by content hash. +**/.vitest-attachments/ # Rust / Tauri build output + generated files target/ diff --git a/apps/web/package.json b/apps/web/package.json index 49df2eb2..e7e1177e 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -47,14 +47,15 @@ "@types/react": "^19.2.0", "@types/react-dom": "^19.2.0", "@vitejs/plugin-react": "^5.0.0", - "@vitest/browser": "^3.2.7", - "@vitest/coverage-istanbul": "^3.2.7", + "@vitest/browser": "^4.1.11", + "@vitest/browser-playwright": "^4.1.11", + "@vitest/coverage-istanbul": "^4.1.11", "playwright": "^1.61.0", "storybook": "^10.5.5", "tailwindcss": "^4.1.0", "typescript": "^6.0.3", "vite": "^7.0.0", - "vitest": "^3.2.7", + "vitest": "^4.1.11", "vitest-browser-react": "^1.0.0" } } diff --git a/apps/web/src/components/app/AppShell/hooks/useProjectRemoval.hooks.test.tsx b/apps/web/src/components/app/AppShell/hooks/useProjectRemoval.hooks.test.tsx index 3751de30..5e293bef 100644 --- a/apps/web/src/components/app/AppShell/hooks/useProjectRemoval.hooks.test.tsx +++ b/apps/web/src/components/app/AppShell/hooks/useProjectRemoval.hooks.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import type { Project } from '@/lib/bridge'; diff --git a/apps/web/src/components/app/SidebarUnified/SidebarUnified.test.tsx b/apps/web/src/components/app/SidebarUnified/SidebarUnified.test.tsx index cfc37358..3eb6d4a3 100644 --- a/apps/web/src/components/app/SidebarUnified/SidebarUnified.test.tsx +++ b/apps/web/src/components/app/SidebarUnified/SidebarUnified.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import type { ProjectSwitcherSurface } from '../Sidebar/Sidebar.types'; diff --git a/apps/web/src/components/board/BulkActionBar/BulkActionBar.test.tsx b/apps/web/src/components/board/BulkActionBar/BulkActionBar.test.tsx index 052c27e4..916c3071 100644 --- a/apps/web/src/components/board/BulkActionBar/BulkActionBar.test.tsx +++ b/apps/web/src/components/board/BulkActionBar/BulkActionBar.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { makeTask, makeTaskActions } from '../_fixtures'; diff --git a/apps/web/src/components/board/DependencyEditor/DependencyEditor.test.tsx b/apps/web/src/components/board/DependencyEditor/DependencyEditor.test.tsx index d4135c23..2818cd32 100644 --- a/apps/web/src/components/board/DependencyEditor/DependencyEditor.test.tsx +++ b/apps/web/src/components/board/DependencyEditor/DependencyEditor.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { makeTask, makeTaskActions } from '../_fixtures'; diff --git a/apps/web/src/components/board/IssueChip/IssueChip.test.tsx b/apps/web/src/components/board/IssueChip/IssueChip.test.tsx index e58455ce..74576a23 100644 --- a/apps/web/src/components/board/IssueChip/IssueChip.test.tsx +++ b/apps/web/src/components/board/IssueChip/IssueChip.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { afterEach, expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; // Spy only the chip's ONE bridge dependency (the browser open); everything else keeps its diff --git a/apps/web/src/components/board/IssueClosedChip/IssueClosedChip.test.tsx b/apps/web/src/components/board/IssueClosedChip/IssueClosedChip.test.tsx index 88b6cdf2..6114419b 100644 --- a/apps/web/src/components/board/IssueClosedChip/IssueClosedChip.test.tsx +++ b/apps/web/src/components/board/IssueClosedChip/IssueClosedChip.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { afterEach, expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; // Spy only the chip's ONE bridge dependency (the browser open); everything else — the diff --git a/apps/web/src/components/board/NewTaskForm/NewTaskForm.test.tsx b/apps/web/src/components/board/NewTaskForm/NewTaskForm.test.tsx index 150966f1..1c502664 100644 --- a/apps/web/src/components/board/NewTaskForm/NewTaskForm.test.tsx +++ b/apps/web/src/components/board/NewTaskForm/NewTaskForm.test.tsx @@ -1,7 +1,7 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { useEffect } from 'react'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import type { ProviderCapabilities } from '@nightcore/contracts'; diff --git a/apps/web/src/components/board/RunOrderPanel/RunOrderPanel.test.tsx b/apps/web/src/components/board/RunOrderPanel/RunOrderPanel.test.tsx index 8d8ea2ae..9faccf7f 100644 --- a/apps/web/src/components/board/RunOrderPanel/RunOrderPanel.test.tsx +++ b/apps/web/src/components/board/RunOrderPanel/RunOrderPanel.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import type { RunOrderProjection } from '@/lib/bridge'; diff --git a/apps/web/src/components/board/SessionComposer/SessionComposer.test.tsx b/apps/web/src/components/board/SessionComposer/SessionComposer.test.tsx index b9855bc3..6087e7c4 100644 --- a/apps/web/src/components/board/SessionComposer/SessionComposer.test.tsx +++ b/apps/web/src/components/board/SessionComposer/SessionComposer.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import * as stories from './SessionComposer.stories'; diff --git a/apps/web/src/components/board/TaskCardTerminalChip/TaskCardTerminalChip.test.tsx b/apps/web/src/components/board/TaskCardTerminalChip/TaskCardTerminalChip.test.tsx index 01279bcb..43663919 100644 --- a/apps/web/src/components/board/TaskCardTerminalChip/TaskCardTerminalChip.test.tsx +++ b/apps/web/src/components/board/TaskCardTerminalChip/TaskCardTerminalChip.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { afterEach, expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { linkTaskToSession, resetTerminalLinksForTest } from '@/lib/terminal-links'; diff --git a/apps/web/src/components/board/TaskOverviewEditor/TaskOverviewEditor.test.tsx b/apps/web/src/components/board/TaskOverviewEditor/TaskOverviewEditor.test.tsx index de435018..fddd16ed 100644 --- a/apps/web/src/components/board/TaskOverviewEditor/TaskOverviewEditor.test.tsx +++ b/apps/web/src/components/board/TaskOverviewEditor/TaskOverviewEditor.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { makeTask } from '../_fixtures.task'; diff --git a/apps/web/src/components/board/WorktreeSwitcher/WorktreeSwitcher.test.tsx b/apps/web/src/components/board/WorktreeSwitcher/WorktreeSwitcher.test.tsx index b69125c8..888be1bd 100644 --- a/apps/web/src/components/board/WorktreeSwitcher/WorktreeSwitcher.test.tsx +++ b/apps/web/src/components/board/WorktreeSwitcher/WorktreeSwitcher.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render, renderHook } from 'vitest-browser-react'; import { diff --git a/apps/web/src/components/council/CouncilReplay/CouncilReplay.test.tsx b/apps/web/src/components/council/CouncilReplay/CouncilReplay.test.tsx index 3318a7ce..3bf97314 100644 --- a/apps/web/src/components/council/CouncilReplay/CouncilReplay.test.tsx +++ b/apps/web/src/components/council/CouncilReplay/CouncilReplay.test.tsx @@ -1,6 +1,6 @@ -import { userEvent } from '@vitest/browser/context'; import type { ReactNode } from 'react'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { killCouncil, resolveCouncilConverge, startCouncil } from '@/lib/bridge'; diff --git a/apps/web/src/components/harness/ApplyConfirmDialog/ApplyConfirmDialog.test.tsx b/apps/web/src/components/harness/ApplyConfirmDialog/ApplyConfirmDialog.test.tsx index 5be8a5c9..05f56e59 100644 --- a/apps/web/src/components/harness/ApplyConfirmDialog/ApplyConfirmDialog.test.tsx +++ b/apps/web/src/components/harness/ApplyConfirmDialog/ApplyConfirmDialog.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import * as stories from './ApplyConfirmDialog.stories'; diff --git a/apps/web/src/components/new-project/NewProjectDialog/NewProjectDialog.test.tsx b/apps/web/src/components/new-project/NewProjectDialog/NewProjectDialog.test.tsx index 1bf9ec15..73598777 100644 --- a/apps/web/src/components/new-project/NewProjectDialog/NewProjectDialog.test.tsx +++ b/apps/web/src/components/new-project/NewProjectDialog/NewProjectDialog.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { projectNameFromPath } from './NewProjectDialog.hooks'; diff --git a/apps/web/src/components/prreview/PrFilterBar/PrFilterBar.test.tsx b/apps/web/src/components/prreview/PrFilterBar/PrFilterBar.test.tsx index aa15e21e..3786bbe7 100644 --- a/apps/web/src/components/prreview/PrFilterBar/PrFilterBar.test.tsx +++ b/apps/web/src/components/prreview/PrFilterBar/PrFilterBar.test.tsx @@ -1,6 +1,6 @@ -import { userEvent } from '@vitest/browser/context'; import { useState } from 'react'; import { expect, test } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import type { ReviewLifecycleState } from '../prreview-lifecycle'; diff --git a/apps/web/src/components/prreview/prreview-resize.hooks.test.tsx b/apps/web/src/components/prreview/prreview-resize.hooks.test.tsx index 29698085..66ed6cde 100644 --- a/apps/web/src/components/prreview/prreview-resize.hooks.test.tsx +++ b/apps/web/src/components/prreview/prreview-resize.hooks.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { beforeEach, expect, test } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { useResizablePanelWidth } from './prreview-resize.hooks'; diff --git a/apps/web/src/components/settings/SettingsView/SettingsView.test.tsx b/apps/web/src/components/settings/SettingsView/SettingsView.test.tsx index ee7e7631..71452b38 100644 --- a/apps/web/src/components/settings/SettingsView/SettingsView.test.tsx +++ b/apps/web/src/components/settings/SettingsView/SettingsView.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import * as stories from './SettingsView.stories'; diff --git a/apps/web/src/components/terminal/TerminalGridPane/TerminalGridPane.test.tsx b/apps/web/src/components/terminal/TerminalGridPane/TerminalGridPane.test.tsx index 9c287054..c15389a5 100644 --- a/apps/web/src/components/terminal/TerminalGridPane/TerminalGridPane.test.tsx +++ b/apps/web/src/components/terminal/TerminalGridPane/TerminalGridPane.test.tsx @@ -1,7 +1,7 @@ import { DndContext } from '@dnd-kit/core'; import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { ToastProvider } from '@/components/ui'; diff --git a/apps/web/src/components/terminal/TerminalPane/TerminalPane.test.tsx b/apps/web/src/components/terminal/TerminalPane/TerminalPane.test.tsx index a72c1cda..af708a35 100644 --- a/apps/web/src/components/terminal/TerminalPane/TerminalPane.test.tsx +++ b/apps/web/src/components/terminal/TerminalPane/TerminalPane.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { afterEach, expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { ToastProvider } from '@/components/ui'; diff --git a/apps/web/src/components/terminal/TerminalSearchBar/TerminalSearchBar.test.tsx b/apps/web/src/components/terminal/TerminalSearchBar/TerminalSearchBar.test.tsx index 88ec5c6d..7eb5c519 100644 --- a/apps/web/src/components/terminal/TerminalSearchBar/TerminalSearchBar.test.tsx +++ b/apps/web/src/components/terminal/TerminalSearchBar/TerminalSearchBar.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { TerminalSearchBar } from './TerminalSearchBar'; diff --git a/apps/web/src/components/terminal/TerminalTabs/TerminalTabs.test.tsx b/apps/web/src/components/terminal/TerminalTabs/TerminalTabs.test.tsx index 81f67dbd..a567efc2 100644 --- a/apps/web/src/components/terminal/TerminalTabs/TerminalTabs.test.tsx +++ b/apps/web/src/components/terminal/TerminalTabs/TerminalTabs.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import * as stories from './TerminalTabs.stories'; diff --git a/apps/web/src/components/terminal/TerminalTaskMenu/TerminalTaskMenu.test.tsx b/apps/web/src/components/terminal/TerminalTaskMenu/TerminalTaskMenu.test.tsx index 4a7f89bc..e6635f18 100644 --- a/apps/web/src/components/terminal/TerminalTaskMenu/TerminalTaskMenu.test.tsx +++ b/apps/web/src/components/terminal/TerminalTaskMenu/TerminalTaskMenu.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { makeTerminalSession, makeTerminalTask } from '../_fixtures'; diff --git a/apps/web/src/components/ui/BranchPicker/BranchPicker.test.tsx b/apps/web/src/components/ui/BranchPicker/BranchPicker.test.tsx index f98aeb67..a3217e65 100644 --- a/apps/web/src/components/ui/BranchPicker/BranchPicker.test.tsx +++ b/apps/web/src/components/ui/BranchPicker/BranchPicker.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import type { BranchInfo } from '@/lib/bridge'; diff --git a/apps/web/src/components/ui/Checkbox/Checkbox.test.tsx b/apps/web/src/components/ui/Checkbox/Checkbox.test.tsx index 9e0c723a..0782df71 100644 --- a/apps/web/src/components/ui/Checkbox/Checkbox.test.tsx +++ b/apps/web/src/components/ui/Checkbox/Checkbox.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { Checkbox } from './Checkbox'; diff --git a/apps/web/src/components/ui/ConfirmDialog/ConfirmDialog.test.tsx b/apps/web/src/components/ui/ConfirmDialog/ConfirmDialog.test.tsx index 29531753..70adf57f 100644 --- a/apps/web/src/components/ui/ConfirmDialog/ConfirmDialog.test.tsx +++ b/apps/web/src/components/ui/ConfirmDialog/ConfirmDialog.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import * as stories from './ConfirmDialog.stories'; diff --git a/apps/web/src/components/ui/FolderBrowserDialog/FolderBrowserDialog.test.tsx b/apps/web/src/components/ui/FolderBrowserDialog/FolderBrowserDialog.test.tsx index 67e9b347..04d3322a 100644 --- a/apps/web/src/components/ui/FolderBrowserDialog/FolderBrowserDialog.test.tsx +++ b/apps/web/src/components/ui/FolderBrowserDialog/FolderBrowserDialog.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { afterEach, expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import type { DirectoryListing } from '@/lib/bridge'; diff --git a/apps/web/src/components/ui/IssueMapDialog/IssueMapDialog.test.tsx b/apps/web/src/components/ui/IssueMapDialog/IssueMapDialog.test.tsx index cb35432b..acd971c3 100644 --- a/apps/web/src/components/ui/IssueMapDialog/IssueMapDialog.test.tsx +++ b/apps/web/src/components/ui/IssueMapDialog/IssueMapDialog.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { afterEach, beforeEach, expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; // Mock the Tauri command + event surface underneath the bridge (the CreatePRDialog diff --git a/apps/web/src/components/ui/Menu/Menu.test.tsx b/apps/web/src/components/ui/Menu/Menu.test.tsx index 71d3c869..09d0c470 100644 --- a/apps/web/src/components/ui/Menu/Menu.test.tsx +++ b/apps/web/src/components/ui/Menu/Menu.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { IconButton } from '../IconButton'; diff --git a/apps/web/src/components/ui/Modal/Modal.test.tsx b/apps/web/src/components/ui/Modal/Modal.test.tsx index baf21388..ce50b0fe 100644 --- a/apps/web/src/components/ui/Modal/Modal.test.tsx +++ b/apps/web/src/components/ui/Modal/Modal.test.tsx @@ -1,6 +1,6 @@ -import { userEvent } from '@vitest/browser/context'; import { useState } from 'react'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { MotionProvider } from '../motion'; diff --git a/apps/web/src/components/ui/ModelSelect/ModelSelect.test.tsx b/apps/web/src/components/ui/ModelSelect/ModelSelect.test.tsx index fb9b9393..902c6c32 100644 --- a/apps/web/src/components/ui/ModelSelect/ModelSelect.test.tsx +++ b/apps/web/src/components/ui/ModelSelect/ModelSelect.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import type { ModelDescriptor } from '@nightcore/contracts'; diff --git a/apps/web/src/components/ui/NumberField/NumberField.test.tsx b/apps/web/src/components/ui/NumberField/NumberField.test.tsx index fd645a90..2d63ff55 100644 --- a/apps/web/src/components/ui/NumberField/NumberField.test.tsx +++ b/apps/web/src/components/ui/NumberField/NumberField.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { NumberField } from './NumberField'; diff --git a/apps/web/src/components/ui/Segmented/Segmented.test.tsx b/apps/web/src/components/ui/Segmented/Segmented.test.tsx index 050ab2c6..d2bfe0fb 100644 --- a/apps/web/src/components/ui/Segmented/Segmented.test.tsx +++ b/apps/web/src/components/ui/Segmented/Segmented.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { MotionProvider } from '../motion'; diff --git a/apps/web/src/components/ui/ToolbarOption/ToolbarOption.test.tsx b/apps/web/src/components/ui/ToolbarOption/ToolbarOption.test.tsx index d6957731..adab8ce4 100644 --- a/apps/web/src/components/ui/ToolbarOption/ToolbarOption.test.tsx +++ b/apps/web/src/components/ui/ToolbarOption/ToolbarOption.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import { BoltIcon } from '../icons'; diff --git a/apps/web/src/components/ui/Tooltip/Tooltip.test.tsx b/apps/web/src/components/ui/Tooltip/Tooltip.test.tsx index e7e7ae92..10dae5b7 100644 --- a/apps/web/src/components/ui/Tooltip/Tooltip.test.tsx +++ b/apps/web/src/components/ui/Tooltip/Tooltip.test.tsx @@ -1,6 +1,6 @@ import { composeStories } from '@storybook/react-vite'; -import { userEvent } from '@vitest/browser/context'; import { expect, test } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; import * as stories from './Tooltip.stories'; diff --git a/apps/web/src/components/worktree/CreatePRDialog/CreatePRDialog.test.tsx b/apps/web/src/components/worktree/CreatePRDialog/CreatePRDialog.test.tsx index ee0690d6..eae817f8 100644 --- a/apps/web/src/components/worktree/CreatePRDialog/CreatePRDialog.test.tsx +++ b/apps/web/src/components/worktree/CreatePRDialog/CreatePRDialog.test.tsx @@ -1,5 +1,5 @@ -import { userEvent } from '@vitest/browser/context'; import { afterEach, beforeEach, expect, test, vi } from 'vitest'; +import { userEvent } from 'vitest/browser'; import { render } from 'vitest-browser-react'; // Mock the Tauri command surface underneath the bridge (the same seam diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json index 6c2c7975..79a1e7ad 100644 --- a/apps/web/tsconfig.json +++ b/apps/web/tsconfig.json @@ -17,7 +17,12 @@ "isolatedModules": true, "verbatimModuleSyntax": true, "noEmit": true, - "types": ["vite/client", "@vitest/browser/providers/playwright"], + // Vitest 4 moved the Playwright provider into its own package and dropped + // `@vitest/browser`'s `./providers/*` export entries, so the old + // "@vitest/browser/providers/playwright" reference no longer resolves. The + // replacement is the provider package's types-only `./context` export, which + // types `page`/`userEvent` with the Playwright-specific surface. + "types": ["vite/client", "@vitest/browser-playwright/context"], // Deliberately no `baseUrl` — TypeScript 6 already rejects it (TS5101) and 7 // removed it outright (TS5102). Without it, `paths` values resolve relative to // THIS file, which the self-relative "./src/*" below already assumes. Bundler diff --git a/apps/web/vitest.config.ts b/apps/web/vitest.config.ts index ca5df815..36d2e20a 100644 --- a/apps/web/vitest.config.ts +++ b/apps/web/vitest.config.ts @@ -3,6 +3,7 @@ import { fileURLToPath } from 'node:url'; import { storybookTest } from '@storybook/addon-vitest/vitest-plugin'; import tailwind from '@tailwindcss/vite'; import react from '@vitejs/plugin-react'; +import { playwright } from '@vitest/browser-playwright'; import { defineConfig } from 'vitest/config'; const alias = { '@': fileURLToPath(new URL('./src', import.meta.url)) }; @@ -13,18 +14,23 @@ const alias = { '@': fileURLToPath(new URL('./src', import.meta.url)) }; // name ("storybook (chromium)" / "unit (chromium)") from its own object. const chromium = () => ({ enabled: true, - provider: 'playwright' as const, + // Vitest 4 replaced the `provider: 'playwright'` string with a provider + // factory from a separate package. `contextOptions` sits on the provider call + // rather than per-instance: instance-level provider overrides do NOT merge + // with the parent, and this repo runs exactly one instance per project, so the + // single provider-level call is the unambiguous shape. + provider: playwright({ + // Emulate `prefers-reduced-motion: reduce` in the test browser. The app's + // reduced-motion rule collapses every animation to ~0ms (styles.css), so the + // slide-in detail sheets (`nc-sheet-in`) settle instantly instead of moving + // ~100px through their 280ms enter — otherwise a `.click()` can race the + // animation and land off a button that's still sliding, a latent flake in the + // shared DetailPanelShell click tests (Insight/Scorecard/Harness) that only + // surfaces in isolated runs. This makes those tests deterministic. + contextOptions: { reducedMotion: 'reduce' }, + }), headless: true, - // Emulate `prefers-reduced-motion: reduce` in the test browser. The app's - // reduced-motion rule collapses every animation to ~0ms (styles.css), so the - // slide-in detail sheets (`nc-sheet-in`) settle instantly instead of moving - // ~100px through their 280ms enter — otherwise a `.click()` can race the - // animation and land off a button that's still sliding, a latent flake in the - // shared DetailPanelShell click tests (Insight/Scorecard/Harness) that only - // surfaces in isolated runs. This makes those tests deterministic. - instances: [ - { browser: 'chromium' as const, context: { reducedMotion: 'reduce' as const } }, - ], + instances: [{ browser: 'chromium' as const }], }); /** diff --git a/bun.lock b/bun.lock index 2d948957..aa8ca1b3 100644 --- a/bun.lock +++ b/bun.lock @@ -84,14 +84,15 @@ "@types/react": "^19.2.0", "@types/react-dom": "^19.2.0", "@vitejs/plugin-react": "^5.0.0", - "@vitest/browser": "^3.2.7", - "@vitest/coverage-istanbul": "^3.2.7", + "@vitest/browser": "^4.1.11", + "@vitest/browser-playwright": "^4.1.11", + "@vitest/coverage-istanbul": "^4.1.11", "playwright": "^1.61.0", "storybook": "^10.5.5", "tailwindcss": "^4.1.0", "typescript": "^6.0.3", "vite": "^7.0.0", - "vitest": "^3.2.7", + "vitest": "^4.1.11", "vitest-browser-react": "^1.0.0", }, }, @@ -135,7 +136,7 @@ "@typescript-eslint/rule-tester": "^8.68.0", "tsup": "^8.5.1", "typescript": "^6.0.3", - "vitest": "^3.2.7", + "vitest": "^4.1.11", }, "peerDependencies": { "eslint": ">=9.0.0", @@ -177,6 +178,7 @@ }, "overrides": { "@hono/node-server": ">=1.19.15 <2", + "@vitest/spy": "4.1.11", "fast-uri": ">=3.1.5 <4", "framer-motion": "12.42.2", "js-yaml": ">=4.3.1 <5", @@ -284,6 +286,8 @@ "@babel/types": ["@babel/types@7.29.8", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg=="], + "@blazediff/core": ["@blazediff/core@1.9.1", "", {}, "sha512-ehg3jIkYKulZh+8om/O25vkvSsXXwC+skXmyA87FFx6A/45eqOkZsBltMw/TVteb0mloiGT8oGRTcjRAz66zaA=="], + "@bruits/satteri-darwin-arm64": ["@bruits/satteri-darwin-arm64@0.9.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-iw4nZgx9v30lWo/MTngQqi1pI78KI0DnkSm+lVJGYdmPLgAyDNJigVhpG42/Iq55A6c1Ll8q66ljyyRiQUxwow=="], "@bruits/satteri-darwin-x64": ["@bruits/satteri-darwin-x64@0.9.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-6T26Z5Kf3cFW2PSlk9p7zT7yVxvuBSiJvYyz9u8KjYwMTqZyIDOj2wDyNpxKV4+6yUVG7rddq2QwvG/8LJA2+Q=="], @@ -464,8 +468,6 @@ "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.35.4", "", { "os": "win32", "cpu": "x64" }, "sha512-XtmnYhBcrORsJ4XJngyzr/EWP0hRZLAZRFaApdKuviyqF78+ylxh2y06ZmtULAMOnObJ3ucpN0AcwSWnMowTRg=="], - "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], - "@istanbuljs/schema": ["@istanbuljs/schema@0.1.6", "", {}, "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw=="], "@joshwooding/vite-plugin-react-docgen-typescript": ["@joshwooding/vite-plugin-react-docgen-typescript@0.7.0", "", { "dependencies": { "glob": "^13.0.1", "react-docgen-typescript": "^2.2.2" }, "peerDependencies": { "typescript": ">= 4.3.x", "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["typescript"] }, "sha512-qvsTEwEFefhdirGOPnu9Wp6ChfIwy2dBCRuETU3uE+4cC+PFoxMSiiEhxk4lOluA34eARHA0OxqsEUYDqRMgeQ=="], @@ -636,8 +638,6 @@ "@pagefind/windows-x64": ["@pagefind/windows-x64@1.5.2", "", { "os": "win32", "cpu": "x64" }, "sha512-Fa2Iyw7kaDRzGMfNYNUXNW2zbL5FQVDgSOcbDHdzBrDEdpqOqg8TcZ68F22ol6NJ9IGzvUdmeyZypLW5dyhqsg=="], - "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], - "@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="], "@rolldown/binding-android-arm-eabi": ["@rolldown/binding-android-arm-eabi@1.2.6", "", { "os": "android", "cpu": "arm" }, "sha512-b+jTcARdTiFLI6jB4a5XjTm0RWd6KcRfQj/I2356fxUZemiho9zQLxo0RtCuMDAyKcLo6cEltkgbQp6d1+sjjQ=="], @@ -742,6 +742,8 @@ "@stablelib/base64": ["@stablelib/base64@1.0.1", "", {}, "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ=="], + "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], + "@storybook/addon-a11y": ["@storybook/addon-a11y@10.5.10", "", { "dependencies": { "@storybook/global": "^5.0.0", "axe-core": "^4.2.0" }, "peerDependencies": { "storybook": "^10.5.10" } }, "sha512-RpRQV5xUbrl6hCiNrd5FSMIo6pnRZ0VZxWvEW/ASLcreGkKUW5jl2AeLCe5YROE2i80s/dU+6VPzOYKrwWNFbQ=="], "@storybook/addon-vitest": ["@storybook/addon-vitest@10.5.10", "", { "dependencies": { "@storybook/global": "^5.0.0", "@storybook/icons": "^2.0.2" }, "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.5.10", "vitest": "^3.0.0 || ^4.0.0" }, "optionalPeers": ["@vitest/browser", "@vitest/browser-playwright", "@vitest/runner", "vitest"] }, "sha512-JNQ9DSkLfxC8qqytBCej91zBExIZ7z97B410U2zgfQPki4HkI9Ffz97a15f5yhVZ79ppIrZ/ssI+WcyWn0ykXQ=="], @@ -914,23 +916,25 @@ "@vitejs/plugin-react": ["@vitejs/plugin-react@5.2.0", "", { "dependencies": { "@babel/core": "^7.29.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-rc.3", "@types/babel__core": "^7.20.5", "react-refresh": "^0.18.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw=="], - "@vitest/browser": ["@vitest/browser@3.2.7", "", { "dependencies": { "@testing-library/dom": "^10.4.0", "@testing-library/user-event": "^14.6.1", "@vitest/mocker": "3.2.7", "@vitest/utils": "3.2.7", "magic-string": "^0.30.17", "sirv": "^3.0.1", "tinyrainbow": "^2.0.0", "ws": "^8.18.2" }, "peerDependencies": { "playwright": "*", "safaridriver": "*", "vitest": "3.2.7", "webdriverio": "^7.0.0 || ^8.0.0 || ^9.0.0" }, "optionalPeers": ["playwright", "safaridriver", "webdriverio"] }, "sha512-gIzazUkbQfv6T1rJHOLhMMKQnplKAvvQ7QNGaFwI6oCsp4z2aSDZCojGpX3QX3+MYsvJdyy/8BRIYVEbAkMkEA=="], + "@vitest/browser": ["@vitest/browser@4.1.11", "", { "dependencies": { "@blazediff/core": "1.9.1", "@vitest/mocker": "4.1.11", "@vitest/utils": "4.1.11", "magic-string": "^0.30.21", "pngjs": "^7.0.0", "sirv": "^3.0.2", "tinyrainbow": "^3.1.0", "ws": "^8.19.0" }, "peerDependencies": { "vitest": "4.1.11" } }, "sha512-bwMovvAeuTFOK5kIFevw4VEf+1gVEICv4SYK4k3knJOxl6b1zEWud8mYKD73e1B0odAn174h1MofURy2TPWf3w=="], + + "@vitest/browser-playwright": ["@vitest/browser-playwright@4.1.11", "", { "dependencies": { "@vitest/browser": "4.1.11", "@vitest/mocker": "4.1.11", "tinyrainbow": "^3.1.0" }, "peerDependencies": { "playwright": "*", "vitest": "4.1.11" } }, "sha512-riLBxPqwnJ0lWs2DN2WeUfYeKLoAjbP2Xx8cLQdSddzMi20sksIa6K2mPz79DyMZKKVKH2ksOC2yJvtNcZg8cg=="], - "@vitest/coverage-istanbul": ["@vitest/coverage-istanbul@3.2.7", "", { "dependencies": { "@istanbuljs/schema": "^0.1.3", "debug": "^4.4.1", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-instrument": "^6.0.3", "istanbul-lib-report": "^3.0.1", "istanbul-lib-source-maps": "^5.0.6", "istanbul-reports": "^3.1.7", "magicast": "^0.3.5", "test-exclude": "^7.0.1", "tinyrainbow": "^2.0.0" }, "peerDependencies": { "vitest": "3.2.7" } }, "sha512-/o+QIJBJCBZm7FdyAMqYKvr8Cd0YsqPt9UwVT6bAA+U9Ae8AR39ZAjq7xnmKCO64TkzPm0Vvi7jzYZWLdu6Y5A=="], + "@vitest/coverage-istanbul": ["@vitest/coverage-istanbul@4.1.11", "", { "dependencies": { "@babel/core": "^7.29.0", "@istanbuljs/schema": "^0.1.3", "@jridgewell/gen-mapping": "^0.3.13", "@jridgewell/trace-mapping": "0.3.31", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", "istanbul-reports": "^3.2.0", "magicast": "^0.5.2", "obug": "^2.1.1", "tinyrainbow": "^3.1.0" }, "peerDependencies": { "vitest": "4.1.11" } }, "sha512-pK9LJtOS534bmUwdwLpGD9qL52DeqVWSInrXFMNqrvWLbbAhuIPAlRup3UbsjFOMqCC/p3MmmX7uXV7ZTkcFfQ=="], - "@vitest/expect": ["@vitest/expect@3.2.7", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/spy": "3.2.7", "@vitest/utils": "3.2.7", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" } }, "sha512-E8eBXaKibuvH2pSZErOjdVb5vF4PbKYcrnluBTYxEk1l/VhhwZg1kZQsdtjq+CsF5CFydf2Rdkz7jDHKSisi3w=="], + "@vitest/expect": ["@vitest/expect@4.1.11", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.1.11", "@vitest/utils": "4.1.11", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" } }, "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw=="], - "@vitest/mocker": ["@vitest/mocker@3.2.7", "", { "dependencies": { "@vitest/spy": "3.2.7", "estree-walker": "^3.0.3", "magic-string": "^0.30.17" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "optionalPeers": ["msw", "vite"] }, "sha512-Trr0hYO9CM3Wj6ksWHRhK9IZpIY6wTMO5u/MqXurMxT57sWBaOPEtP3Oq60ihZuh5JsiagKfz95OcxdEP6dBrA=="], + "@vitest/mocker": ["@vitest/mocker@4.1.11", "", { "dependencies": { "@vitest/spy": "4.1.11", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["msw", "vite"] }, "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ=="], - "@vitest/pretty-format": ["@vitest/pretty-format@3.2.7", "", { "dependencies": { "tinyrainbow": "^2.0.0" } }, "sha512-KUHlwqVu0sRlhCdyPdQ/wBoTfRahjUky1MubOmYw9fWfIZy1gNoHpuaaQBPAaMaVYdQYHJLurzj8ECCj5OwTqA=="], + "@vitest/pretty-format": ["@vitest/pretty-format@4.1.11", "", { "dependencies": { "tinyrainbow": "^3.1.0" } }, "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw=="], - "@vitest/runner": ["@vitest/runner@3.2.7", "", { "dependencies": { "@vitest/utils": "3.2.7", "pathe": "^2.0.3", "strip-literal": "^3.0.0" } }, "sha512-sB9y4ovltoQP+WaUPwmSxO9WIg9Ig694Di5PalVPsYHklAdE027mehpWF2SQSVq+k6sFgaivbTjTJwZLSHbedA=="], + "@vitest/runner": ["@vitest/runner@4.1.11", "", { "dependencies": { "@vitest/utils": "4.1.11", "pathe": "^2.0.3" } }, "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw=="], - "@vitest/snapshot": ["@vitest/snapshot@3.2.7", "", { "dependencies": { "@vitest/pretty-format": "3.2.7", "magic-string": "^0.30.17", "pathe": "^2.0.3" } }, "sha512-7C+MwShwtBSI5Buwoyg3s/iY1eHL9PKAf+O1wVh/TdnjXUtkoL/9YQtre90i4MtNXM6edP1wJ2zOBpfCyhIS7g=="], + "@vitest/snapshot": ["@vitest/snapshot@4.1.11", "", { "dependencies": { "@vitest/pretty-format": "4.1.11", "@vitest/utils": "4.1.11", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog=="], - "@vitest/spy": ["@vitest/spy@3.2.7", "", { "dependencies": { "tinyspy": "^4.0.3" } }, "sha512-Q2eQGI6d2L/hBtZ0qNuKcAGid68XK6cv1xsoaIma6PaJhHPoqcEJhYpXZ/5myCMqkNgtP6UKuBhbc0nHKnrkuQ=="], + "@vitest/spy": ["@vitest/spy@4.1.11", "", {}, "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA=="], - "@vitest/utils": ["@vitest/utils@3.2.7", "", { "dependencies": { "@vitest/pretty-format": "3.2.7", "loupe": "^3.1.4", "tinyrainbow": "^2.0.0" } }, "sha512-x6BDOd7dyo3PFLY3I9/HJ25X/6OurhGXk2/B9gOZNPF7XDVjeBK4k01lQE5uvDpbuheErh91qYuE1E2OEjK3Rw=="], + "@vitest/utils": ["@vitest/utils@4.1.11", "", { "dependencies": { "@vitest/pretty-format": "4.1.11", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" } }, "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ=="], "@webcontainer/env": ["@webcontainer/env@1.1.1", "", {}, "sha512-6aN99yL695Hi9SuIk1oC88l9o0gmxL1nGWWQ/kNy81HigJ0FoaoTXpytCj6ItzgyCEwA9kF1wixsTuv5cjsgng=="], @@ -1040,7 +1044,7 @@ "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], - "chai": ["chai@5.3.3", "", { "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" } }, "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw=="], + "chai": ["chai@6.2.2", "", {}, "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg=="], "character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="], @@ -1060,10 +1064,6 @@ "collapse-white-space": ["collapse-white-space@2.1.0", "", {}, "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw=="], - "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], - - "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], - "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="], "commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="], @@ -1172,8 +1172,6 @@ "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], - "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], - "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], "electron-to-chromium": ["electron-to-chromium@1.5.417", "", {}, "sha512-4T+DTDWuMPM4aHlHwWdAVCVWwp7LDilnhzkj+c/Lbj91XSQrLuOmZSLtS9Q4iIqjlPUbPOnC624zDVVHCHaolQ=="], @@ -1312,8 +1310,6 @@ "for-each": ["for-each@0.3.5", "", { "dependencies": { "is-callable": "^1.2.7" } }, "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg=="], - "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], - "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], "framer-motion": ["framer-motion@12.42.2", "", { "dependencies": { "motion-dom": "^12.42.2", "motion-utils": "^12.39.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-5XY9luDiu0oHfHBjpDthFMh0ES+122w6p/papSJBweMkO8Sn+PW2QaEgRblQBpWFnuvZS5qvarpt/hO2pjGmnw=="], @@ -1474,8 +1470,6 @@ "is-finalizationregistry": ["is-finalizationregistry@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg=="], - "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], - "is-generator-function": ["is-generator-function@1.1.2", "", { "dependencies": { "call-bound": "^1.0.4", "generator-function": "^2.0.0", "get-proto": "^1.0.1", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA=="], "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], @@ -1520,23 +1514,17 @@ "istanbul-lib-coverage": ["istanbul-lib-coverage@3.2.2", "", {}, "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg=="], - "istanbul-lib-instrument": ["istanbul-lib-instrument@6.0.3", "", { "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", "semver": "^7.5.4" } }, "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q=="], - "istanbul-lib-report": ["istanbul-lib-report@3.0.1", "", { "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^4.0.0", "supports-color": "^7.1.0" } }, "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw=="], - "istanbul-lib-source-maps": ["istanbul-lib-source-maps@5.0.6", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.23", "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0" } }, "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A=="], - "istanbul-reports": ["istanbul-reports@3.2.0", "", { "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" } }, "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA=="], - "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], - "jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="], "jose": ["jose@6.2.10", "", {}, "sha512-iiW7J9qRFlGxvCOIBDBDxFePQSn7ZMAnrYGhrrOo6siO/MIqwfyilLR27pkfDgUk+raLuzADS8A3S/KLBisc0g=="], "joycon": ["joycon@3.1.1", "", {}, "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw=="], - "js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="], + "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], "js-yaml": ["js-yaml@4.3.2", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA=="], @@ -1830,8 +1818,6 @@ "p-timeout": ["p-timeout@7.0.1", "", {}, "sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg=="], - "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], - "package-manager-detector": ["package-manager-detector@1.8.0", "", {}, "sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A=="], "pagefind": ["pagefind@1.5.2", "", { "optionalDependencies": { "@pagefind/darwin-arm64": "1.5.2", "@pagefind/darwin-x64": "1.5.2", "@pagefind/freebsd-x64": "1.5.2", "@pagefind/linux-arm64": "1.5.2", "@pagefind/linux-x64": "1.5.2", "@pagefind/windows-arm64": "1.5.2", "@pagefind/windows-x64": "1.5.2" }, "bin": { "pagefind": "lib/runner/bin.cjs" } }, "sha512-XTUaK0hXMCu2jszWE584JGQT7y284TmMV9l/HX3rnG5uo3rHI/uHU56XTyyyPFjeWEBxECbAi0CaFDJOONtG0Q=="], @@ -1874,6 +1860,8 @@ "playwright-core": ["playwright-core@1.62.1", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw=="], + "pngjs": ["pngjs@7.0.0", "", {}, "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow=="], + "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], "postcss": ["postcss@8.5.26", "", { "dependencies": { "nanoid": "^3.3.17", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ=="], @@ -2040,8 +2028,6 @@ "siginfo": ["siginfo@2.0.0", "", {}, "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="], - "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], - "sirv": ["sirv@3.0.2", "", { "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", "totalist": "^3.0.0" } }, "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g=="], "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="], @@ -2062,7 +2048,7 @@ "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], - "std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="], + "std-env": ["std-env@4.2.0", "", {}, "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw=="], "stop-iteration-iterator": ["stop-iteration-iterator@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "internal-slot": "^1.1.0" } }, "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ=="], @@ -2070,10 +2056,6 @@ "stream-replace-string": ["stream-replace-string@2.0.0", "", {}, "sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w=="], - "string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], - - "string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - "string.prototype.includes": ["string.prototype.includes@2.0.1", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.3" } }, "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg=="], "string.prototype.trim": ["string.prototype.trim@1.2.11", "", { "dependencies": { "call-bind": "^1.0.9", "call-bound": "^1.0.4", "define-data-property": "^1.1.4", "define-properties": "^1.2.1", "es-abstract": "^1.24.2", "es-object-atoms": "^1.1.2", "has-property-descriptors": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-PwvK7BU+CMTJGYQCTZb5RWXIML92lftJLhQz1tBzgKiqGxJaMlBAa48POXaNAC2s4y8jr3EFqrkF9+44neS46w=="], @@ -2084,16 +2066,10 @@ "stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="], - "strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], - - "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="], "strip-indent": ["strip-indent@4.1.1", "", {}, "sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA=="], - "strip-literal": ["strip-literal@3.1.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="], - "style-to-js": ["style-to-js@1.1.21", "", { "dependencies": { "style-to-object": "1.0.14" } }, "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ=="], "style-to-object": ["style-to-object@1.0.14", "", { "dependencies": { "inline-style-parser": "0.2.7" } }, "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw=="], @@ -2110,8 +2086,6 @@ "tapable": ["tapable@2.3.3", "", {}, "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="], - "test-exclude": ["test-exclude@7.0.2", "", { "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^10.4.1", "minimatch": "^10.2.2" } }, "sha512-u9E6A+ZDYdp7a4WnarkXPZOx8Ilz46+kby6p1yZ8zsGTz9gYa6FIS7lj2oezzNKmtdyyJNNmmXDppga5GB7kSw=="], - "thenify": ["thenify@3.3.1", "", { "dependencies": { "any-promise": "^1.0.0" } }, "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw=="], "thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="], @@ -2128,11 +2102,7 @@ "tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="], - "tinypool": ["tinypool@1.1.1", "", {}, "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg=="], - - "tinyrainbow": ["tinyrainbow@2.0.0", "", {}, "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw=="], - - "tinyspy": ["tinyspy@4.0.4", "", {}, "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q=="], + "tinyrainbow": ["tinyrainbow@3.1.1", "", {}, "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw=="], "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], @@ -2236,11 +2206,9 @@ "vite": ["vite@7.3.6", "", { "dependencies": { "esbuild": "^0.27.0 || ^0.28.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg=="], - "vite-node": ["vite-node@3.2.4", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.4.1", "es-module-lexer": "^1.7.0", "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg=="], - "vitefu": ["vitefu@1.1.3", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["vite"] }, "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg=="], - "vitest": ["vitest@3.2.7", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.7", "@vitest/mocker": "3.2.7", "@vitest/pretty-format": "^3.2.7", "@vitest/runner": "3.2.7", "@vitest/snapshot": "3.2.7", "@vitest/spy": "3.2.7", "@vitest/utils": "3.2.7", "chai": "^5.2.0", "debug": "^4.4.1", "expect-type": "^1.2.1", "magic-string": "^0.30.17", "pathe": "^2.0.3", "picomatch": "^4.0.2", "std-env": "^3.9.0", "tinybench": "^2.9.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.14", "tinypool": "^1.1.1", "tinyrainbow": "^2.0.0", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", "vite-node": "3.2.4", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@types/debug": "^4.1.12", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "@vitest/browser": "3.2.7", "@vitest/ui": "3.2.7", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@types/debug", "@types/node", "@vitest/browser", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "./vitest.mjs" } }, "sha512-KrxIJ62Fd89gfysR4WotlgZABiz2dqFPgqGzX7s+CwsqLFomRH7777ZcrOD6+WVAh7khPQP41A+BKbpcJFrdEg=="], + "vitest": ["vitest@4.1.11", "", { "dependencies": { "@vitest/expect": "4.1.11", "@vitest/mocker": "4.1.11", "@vitest/pretty-format": "4.1.11", "@vitest/runner": "4.1.11", "@vitest/snapshot": "4.1.11", "@vitest/spy": "4.1.11", "@vitest/utils": "4.1.11", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.1.0", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.1.11", "@vitest/browser-preview": "4.1.11", "@vitest/browser-webdriverio": "4.1.11", "@vitest/coverage-istanbul": "4.1.11", "@vitest/coverage-v8": "4.1.11", "@vitest/ui": "4.1.11", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/coverage-istanbul", "@vitest/coverage-v8", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "./vitest.mjs" } }, "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw=="], "vitest-browser-react": ["vitest-browser-react@1.0.1", "", { "peerDependencies": { "@types/react": "^18.0.0 || ^19.0.0", "@types/react-dom": "^18.0.0 || ^19.0.0", "@vitest/browser": "^2.1.0 || ^3.0.0 || ^4.0.0-0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0", "vitest": "^2.1.0 || ^3.0.0 || ^4.0.0-0" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-LqiGFCdknrbMoSDWXTCTrPsED3SvdIXIgYOOZyYUNj2dkJusW2eF6NENOlBlxwq+FBQqzNK1X59b+b03pXFpAQ=="], @@ -2262,10 +2230,6 @@ "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], - "wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], - - "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], - "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], "ws": ["ws@8.21.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw=="], @@ -2288,8 +2252,6 @@ "@astrojs/markdown-satteri/satteri": ["satteri@0.10.5", "", { "dependencies": { "@types/estree-jsx": "^1.0.5", "@types/hast": "^3.0.5", "@types/mdast": "^4.0.4", "@types/unist": "^3.0.3" }, "optionalDependencies": { "@bruits/satteri-darwin-arm64": "0.10.5", "@bruits/satteri-darwin-x64": "0.10.5", "@bruits/satteri-linux-arm64-gnu": "0.10.5", "@bruits/satteri-linux-arm64-musl": "0.10.5", "@bruits/satteri-linux-x64-gnu": "0.10.5", "@bruits/satteri-linux-x64-musl": "0.10.5", "@bruits/satteri-wasm32-wasi": "0.10.5", "@bruits/satteri-win32-arm64-msvc": "0.10.5", "@bruits/satteri-win32-x64-msvc": "0.10.5" } }, "sha512-Ao1LKpAEa9Wdg0otgbVKViZHEq9ebdXe4DMrp3s9vQAU0HNIuHnFEuMuOcm0ZIXyV0Yzxj91NvhLpvXZJO/5ZQ=="], - "@babel/code-frame/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], - "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], @@ -2334,8 +2296,6 @@ "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.8", "", {}, "sha512-YYNsSlXBjMk92SKnkwvB5LOVSa6OznlFUGcsvrFgNJbJCd0M1XKeFVRc8ZByeCqz32FivYNHJVooLmdqrmvp/Q=="], - "@vitest/coverage-istanbul/magicast": ["magicast@0.3.5", "", { "dependencies": { "@babel/parser": "^7.25.4", "@babel/types": "^7.25.4", "source-map-js": "^1.2.0" } }, "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ=="], - "ajv-formats/ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="], "anymatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], @@ -2380,18 +2340,8 @@ "storybook/@vitest/expect": ["@vitest/expect@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" } }, "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig=="], - "storybook/@vitest/spy": ["@vitest/spy@3.2.4", "", { "dependencies": { "tinyspy": "^4.0.3" } }, "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw=="], - - "string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], - - "string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - - "strip-ansi/ansi-regex": ["ansi-regex@6.3.0", "", {}, "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ=="], - "sucrase/commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], - "test-exclude/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], - "tsup/esbuild": ["esbuild@0.27.7", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.7", "@esbuild/android-arm": "0.27.7", "@esbuild/android-arm64": "0.27.7", "@esbuild/android-x64": "0.27.7", "@esbuild/darwin-arm64": "0.27.7", "@esbuild/darwin-x64": "0.27.7", "@esbuild/freebsd-arm64": "0.27.7", "@esbuild/freebsd-x64": "0.27.7", "@esbuild/linux-arm": "0.27.7", "@esbuild/linux-arm64": "0.27.7", "@esbuild/linux-ia32": "0.27.7", "@esbuild/linux-loong64": "0.27.7", "@esbuild/linux-mips64el": "0.27.7", "@esbuild/linux-ppc64": "0.27.7", "@esbuild/linux-riscv64": "0.27.7", "@esbuild/linux-s390x": "0.27.7", "@esbuild/linux-x64": "0.27.7", "@esbuild/netbsd-arm64": "0.27.7", "@esbuild/netbsd-x64": "0.27.7", "@esbuild/openbsd-arm64": "0.27.7", "@esbuild/openbsd-x64": "0.27.7", "@esbuild/openharmony-arm64": "0.27.7", "@esbuild/sunos-x64": "0.27.7", "@esbuild/win32-arm64": "0.27.7", "@esbuild/win32-ia32": "0.27.7", "@esbuild/win32-x64": "0.27.7" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w=="], "tsup/tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], @@ -2402,17 +2352,7 @@ "vite/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], - "vite-node/es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="], - - "vitest/tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], - - "wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], - - "wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - - "wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - - "wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "vitest/vite": ["vite@8.2.2", "", { "dependencies": { "lightningcss": "^1.33.0", "picomatch": "^4.0.5", "postcss": "^8.5.26", "rolldown": "~1.2.4", "tinyglobby": "^0.2.17" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.4.0 || ^0.5.0", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q=="], "@astrojs/markdown-satteri/satteri/@bruits/satteri-darwin-arm64": ["@bruits/satteri-darwin-arm64@0.10.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-27KTVl4TJkVahMy/ohyA7qd4938G5UNneFUz/PsScYfpIhj0IVAS23mpcJXdPF44sa6nva198lmV/cKIb2YPyA=="], @@ -2476,9 +2416,9 @@ "storybook/@vitest/expect/@vitest/utils": ["@vitest/utils@3.2.4", "", { "dependencies": { "@vitest/pretty-format": "3.2.4", "loupe": "^3.1.4", "tinyrainbow": "^2.0.0" } }, "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA=="], - "test-exclude/glob/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="], + "storybook/@vitest/expect/chai": ["chai@5.3.3", "", { "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" } }, "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw=="], - "test-exclude/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], + "storybook/@vitest/expect/tinyrainbow": ["tinyrainbow@2.0.0", "", {}, "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw=="], "tsup/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.7", "", { "os": "aix", "cpu": "ppc64" }, "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg=="], @@ -2534,16 +2474,10 @@ "unstorage/chokidar/readdirp": ["readdirp@5.1.1", "", {}, "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA=="], - "wrap-ansi-cjs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + "vitest/vite/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], "eslint-plugin-jsx-a11y/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], "storybook/@vitest/expect/@vitest/utils/@vitest/pretty-format": ["@vitest/pretty-format@3.2.4", "", { "dependencies": { "tinyrainbow": "^2.0.0" } }, "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA=="], - - "test-exclude/glob/minimatch/brace-expansion": ["brace-expansion@2.1.4", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg=="], - - "test-exclude/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - - "test-exclude/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], } } diff --git a/docs/migrations/2026-08-31-vite.md b/docs/migrations/2026-08-31-vite.md new file mode 100644 index 00000000..f4eb9e7c --- /dev/null +++ b/docs/migrations/2026-08-31-vite.md @@ -0,0 +1,270 @@ +# Migration Plan: `vite` 7.3.6 → 8.2.2, `@vitejs/plugin-react` 5.0.0 → 5.2.0 (NOT 6.x), `vitest` family 3.2.7 → 4.1.11 + +**Date:** 2026-08-31 +**Agent:** kirei-migrate +**Base branch:** `deps/typescript-6` (PR #466, stacked on PR #465 `deps/phase-1-safe-bumps`) — plan stacks on this branch's `bun.lock` and TypeScript 6.0.3 state. Do **not** plan against local `main` (stale) — see "Branch Staleness" below for a real trap this uncovered. +**Target:** `vite` `7.3.6` → `8.2.2`; `@vitejs/plugin-react` `5.0.0` → `5.2.0` (recommended target — **not** the latest `6.1.1`, see BC-B3); `vitest`/`@vitest/browser`/`@vitest/coverage-istanbul` `3.2.7` → `4.1.11`; `vitest-browser-react` `1.0.1` → `2.2.0`; new package `@vitest/browser-playwright@4.1.11`. +**Migration guides read:** vitest.dev/guide/migration.html (Vitest 4.0 migration guide), vitest.dev/config/browser/playwright (Playwright provider reference), vite.dev/guide/migration (Vite 8 migration from v7), npm registry `peerDependencies`/`dependencies` for every package version cited below (live-checked 2026-08-31, not from memory). + +## Summary — THE KEY QUESTION, answered decisively + +**The coupling between `vite` and the `vitest` family is one-directional, not symmetric. Recommendation: TWO sequential PRs, not one combined PR — this confirms the plan you already had; do not merge them.** + +Evidence (live npm peer-dependency data, not documentation prose): + +| | Declares peer/dep on `vite` | Does it accept the CURRENT vite (7.3.6)? | Does it accept the TARGET vite (8.2.2)? | +|---|---|---|---| +| `vitest@4.1.11` | `"vite": "^6.0.0 \|\| ^7.0.0 \|\| ^8.0.0"` | **yes** | **yes** | +| `vitest@3.2.7` (current, locked) | `"vite": "^5.0.0 \|\| ^6.0.0 \|\| ^7.0.0-0"` | yes (current state) | **no — does not declare `^8.0.0`** | + +So: **vitest 4 already supports the vite you have today (7.3.6)** — it does not need vite 8 to be useful. But **vite 8 is not supported by the vitest you have today (3.2.7)** — bumping vite alone, first, would leave `vitest@3.2.7`'s own declared range unsatisfied and put `vite-node`/vitest's internal Vite API usage against an untested major. The dependency only points one way: vitest-4-before-vite-8 is safe; vite-8-before-vitest-4 is not. + +This means the vitest-family migration can be fully absorbed, verified, and merged **on top of the existing vite 7.3.6** — isolating 100% of Vitest 4's own structural changes (browser-provider config rewrite, new required peer package, pool/coverage/projects renames) from Vite 8's own structural changes (esbuild→Rolldown dep-optimizer swap) so a red CI run always points at exactly one migration, not an entangled pair. Recommended order: **PR A = vitest family (vite stays 7.3.6) → merge & bake → PR B = vite 8 + plugin-react (vitest already proven on 4.x, satisfies vitest 4's `^8.0.0` peer immediately)**. + +**Second finding, equally load-bearing: `@vitejs/plugin-react`'s latest major (`6.1.1`) hard-requires `vite: "^8.0.0"` ONLY** (no `^7.0.0` in its peer range) — bumping plugin-react to latest would force vite 8 immediately, and would also swap the JSX/Fast-Refresh transform from Babel to an Oxc-based pipeline (Babel is removed as a dependency entirely in 6.0) — a second, independent bundler-internals swap stacked on the same PR as Vite 8's own esbuild→Rolldown dep-optimizer swap. **`@vitejs/plugin-react@5.2.0` (the latest 5.x patch, one minor ahead of the currently-locked `5.0.0`) already declares `"vite": "^4.2.0 \|\| ^5.0.0 \|\| ^6.0.0 \|\| ^7.0.0 \|\| ^8.0.0"`** — it supports vite 8 without forcing the Oxc transform swap. Recommendation: land vite 8 with plugin-react **5.2.0**, explicitly deferring the plugin-react 6.x / Babel-removal / Oxc-transform jump to its own future migration. This is a "defer part of it" outcome, not a full defer — vite itself is safe to move now. + +**Third finding: the documented CI-freeze trap (`optimized dependencies changed` mid-run silent hang, `docs/research/2026-07-11-ci-performance.md` flake F3) is the single highest-risk item in the whole migration, and it lands entirely in PR B (vite 8), not PR A.** Vite 8 replaces esbuild with Rolldown for dependency pre-bundling/optimization. The `optimizeDeps.include`/`exclude` config API is unchanged (verified directly against the installed `vite@8.2.2` type declarations — see BC-B1), so the existing guard's *shape* survives untouched. But the *engine* that decides when a dependency needs to be discovered/re-optimized mid-run changes from esbuild's scanner to Rolldown's — meaning the current `optimizeDeps.include` list (tuned empirically against esbuild's behavior) is not guaranteed to still be exhaustive under Rolldown's scanner. This cannot be resolved by reading docs; it needs empirical, repeated, cold-cache CI runs — see BC-B1 for the exact plan. + +**Overall verdict: proceed, staged.** Neither package is a "defer this" outcome the way TypeScript 7 was — both vite 8 and vitest 4 are viable targets today, verified against this repo's actual config and actual peer-dependency graph, not assumed. The risk is real but bounded and testable (BC-B1), and the two-PR split means each PR's CI run gives an unambiguous signal about which subsystem broke. + +## Branch Staleness — a real trap this research surfaced + +`deps/phase-1-safe-bumps` and `deps/typescript-6` both branched off `main` at `49f3e51c` (the `v0.4.0` release commit). Since then, **`origin/main` has moved 7 commits ahead**, including **PR #449 (`chore(web): migrate the Storybook family to 10.x`, merged 2026-08-01, `storybook`/`@storybook/react-vite`/`@storybook/addon-vitest`/`@storybook/addon-a11y` all now `10.5.5` in lockstep on real `main`)** and **PR #447 (`chore(tooling): drop tsconfig baseUrl for TypeScript 7 readiness`, merged after `deps/typescript-6` branched)** — the exact same `baseUrl` removal the TypeScript 6 migration plan (`docs/migrations/2026-08-31-typescript.md`, BC-1) independently prescribes. **`docs/deps/2026-08-31-dependency-upgrade-plan.md` (dated the same day as this doc) is itself stale on this point** — it lists Storybook 9→10 as a still-pending Phase 3 item, but that migration already shipped on `main` a month earlier. + +Concretely, the `deps/typescript-6` branch you're asked to plan against still shows `storybook`/`@storybook/*` at `^9.1.20` (verified: `apps/web/package.json` on this branch). This is **not blocking** for the vite/vitest migration — verified below that Storybook 9.1.20's `@storybook/addon-vitest` already declares the same `vitest: "^3.0.0 || ^4.0.0"` / `@vitest/browser-playwright: "^4.0.0"` peer support as the 10.5.5 version on `main` (both checked live via npm), so this migration works whether Storybook is at 9 or 10. But **whoever lands this PR stack needs to rebase onto current `origin/main` before or shortly after merging**, or `deps/phase-1-safe-bumps`/`deps/typescript-6`/this vite PR will merge into a `main` that has since diverged on Storybook, `baseUrl`, and 4 other unrelated commits (`#450`–`#452`, `#458`) — a real merge-conflict/double-baseUrl-removal risk, not a hypothetical one. Flagging this explicitly since it's outside this migration's own scope but will bite the first person who tries to land any of this stack without noticing. + +## Pre-flight Requirements + +- Runtime: **no change needed.** `vite@8.2.2` and `vite@7.3.6` both require `node: "^20.19.0 || >=22.12.0"`; `vitest@4.1.11` requires `node: "^20.0.0 || ^22.0.0 || >=24.0.0"`. Root `package.json` already declares `engines.node: ">=22"`, which satisfies both. +- Peer deps: none block either PR — see the coupling table above. `vitest-browser-react@2.2.0`'s peer (`vitest: "^4.0.0"`) is satisfied once vitest moves to 4.x (PR A). +- New required dependency: `@vitest/browser-playwright@4.1.11` must be added to `apps/web/package.json` devDependencies in PR A — both `vitest@4.1.11`'s browser-provider architecture AND `@storybook/addon-vitest` (9.1.20 on this branch, 10.5.5 on `main` — checked both) declare it as a **required** (non-optional) peer once vitest is on the 4.x line. `@vitest/browser` must be **kept**, not removed, despite the Vitest migration guide's own suggestion that it's "no longer needed" — `@storybook/addon-vitest` (both versions checked) still declares `@vitest/browser: "^3.0.0 || ^4.0.0"` as its own required peer, so removing it would break Storybook's vitest integration even though Vitest itself no longer needs it directly. +- Branch state: land PR A and PR B stacked on `deps/typescript-6`, but plan a rebase onto current `origin/main` before or immediately after this stack merges — see "Branch Staleness" above. + +## Breaking Changes & Call Sites — PR A: `vitest` family 3.2.7 → 4.1.11 (vite stays at 7.3.6) + +### BC-A1 — Browser provider config: string form removed, object-provider form required +**Type:** Structural, hand-edit (no codemod exists — confirmed no official Vitest 3→4 codemod is published; only unrelated Jest→Vitest/Mocha→Vitest codemods exist) +**What changed:** `test.browser.provider: 'playwright'` (string) is no longer valid. Vitest 4 requires importing a provider function from a new, separate package and calling it: `import { playwright } from '@vitest/browser-playwright'; provider: playwright({ ... })`. `browser.instances[]` entries that previously set `provider: 'playwright'` inline must drop that key entirely (the provider now lives one level up). +**Call site:** `apps/web/vitest.config.ts:14-28`, the shared `chromium()` helper used by BOTH the `storybook` project (line ~108) and the `unit` project (line ~158): +```ts +const chromium = () => ({ + enabled: true, + provider: 'playwright' as const, + headless: true, + instances: [ + { browser: 'chromium' as const, context: { reducedMotion: 'reduce' as const } }, + ], +}); +``` +**Fix (verified against the official Vitest 4 config reference, `vitest.dev/config/browser/playwright`):** +```ts +import { playwright } from '@vitest/browser-playwright'; + +const chromium = () => ({ + headless: true, + provider: playwright({ + contextOptions: { reducedMotion: 'reduce' }, + }), + instances: [{ browser: 'chromium' as const }], +}); +``` +The per-instance `context: { reducedMotion: ... }` field must move to the provider's `contextOptions` — the docs are explicit that `contextOptions` is a documented, stable field of the `playwright()` call, while per-instance `context`/`contextOptions` overrides are ambiguously documented (instance-level `provider: playwright({...})` overrides do **not** merge with the parent per the docs — riskier to rely on). Since this repo runs exactly one instance (chromium) per project with no per-instance divergence, moving `contextOptions` to the single provider call is the unambiguous, doc-confirmed shape. Apply the same rewrite to both the `storybook` and `unit` project's `browser: chromium()` usage (they share the one helper, so this is a single-function edit, not two). + +### BC-A2 — `@vitest/browser/context` import path deprecated +**Type:** Mechanical, codemod-able via `sed` (not a published codemod, but a trivial one-line-per-file substitution) +**What changed:** `import { userEvent } from '@vitest/browser/context'` still works in v4 but is deprecated in favor of `import { userEvent } from 'vitest/browser'`. +**Call sites:** 36 files, all `apps/web/src/**/*.test.tsx` (component tests using `userEvent` for interaction testing) — e.g. `apps/web/src/components/ui/Tooltip/Tooltip.test.tsx:2`, `apps/web/src/components/board/NewTaskForm/NewTaskForm.test.tsx:2`, `apps/web/src/components/terminal/TerminalPane/TerminalPane.test.tsx:2`, and 33 more (full list: `grep -rl "from '@vitest/browser/context'" apps/web/src`). +**Fix:** repo-wide `sed -i '' "s/@vitest\/browser\/context/vitest\/browser/" $(grep -rl "from '@vitest/browser/context'" apps/web/src)`. Not strictly required to land PR A (old path still works in v4), but cheap to do in the same PR since you're already touching this config surface — recommend including it to avoid carrying a known-deprecated import into the codebase. If minimizing PR A's diff is preferred, this can be split into a trivial mechanical follow-up instead. + +### BC-A3 — `mock.invocationCallOrder` now starts at 1 (was 0) — CHECKED, no fix needed +**Type:** Behavioral, but verified as a false positive for this repo +**What changed:** Vitest 4's global mock-invocation counter is 1-indexed instead of 0-indexed. +**Call sites (3, all the same pattern):** `apps/web/src/components/worktree/worktree-terminal.test.tsx:104-105`, `apps/web/src/components/worktree/WorktreeView/WorktreeView.hooks.test.tsx:110-111` and `:125-126` — each does `expect(mockA.mock.invocationCallOrder[0]!).toBeLessThan(mockB.mock.invocationCallOrder[0]!)`. +**Why it's safe:** these are **relative** comparisons between two mocks that share the same global call-order counter. A uniform +1 shift to the whole counter preserves relative ordering — `toBeLessThan` still evaluates correctly. No call site in this repo asserts an *absolute* `invocationCallOrder` value (e.g. `toBe(0)`), which is the only pattern the 0→1 shift would actually break. Verified by reading all 3 files in full context — no fix needed. + +### BC-A4 — `vi.restoreAllMocks()` no longer restores automocks — CHECKED, no fix needed +**Type:** Behavioral, but verified as a false positive for this repo +**What changed:** In v4, `vi.restoreAllMocks()` restores manually-created spies (`vi.spyOn`, standalone `vi.fn()`) but not "automocks" (`vi.mock('module')` called **without** a factory function, letting Vitest auto-generate replacements for every export). +**Call sites checked:** `apps/web/src/lib/logger.test.tsx:6` (uses `vi.spyOn(console, 'error')` — a manual spy, unaffected) and `apps/web/src/components/terminal/terminal-session-manager.test.tsx:27` (uses only locally-scoped `vi.fn()`, no `vi.mock()` at all — unaffected either way). `packages/eslint-plugin/vitest.config.ts` also sets `restoreMocks: true` globally. +**Why it's safe repo-wide:** grepped **every** `vi.mock(` call in `apps/web/src` (75 total) and `packages/eslint-plugin` (0 total) — **zero** are automocks; every single one supplies an explicit factory function (`vi.mock('module', () => ({...}))`), which is not the "automock" pattern this behavior change affects. No fix needed anywhere in the repo. + +### BC-A5 through BC-A9 — checked against the full Vitest 4 migration-guide changelist, confirmed already-compliant or not-applicable +- **`coverage.include` now required explicit** — `apps/web/vitest.config.ts` already sets `coverage.include: ['src/**']` explicitly. Compliant, no change. +- **Coverage provider is `istanbul`, not `v8`** — the V8-specific AST-remapping/`coverage.all`/`coverage.experimentalAstAwareRemapping` removals in the migration guide only affect the `v8` coverage provider. This repo uses `provider: 'istanbul'`. Not applicable. +- **`workspace` renamed to `projects`, external workspace file removed** — repo already uses inline `test.projects: [...]` directly in `vitest.config.ts` (confirmed: no `vitest.workspace.*` file exists anywhere in the repo). Already compliant. +- **Pool architecture rename (`maxThreads`/`maxForks`/`poolOptions`/`singleThread`/`singleFork` → `maxWorkers`/`isolate`)** — none of these options are set in either `apps/web/vitest.config.ts` or `packages/eslint-plugin/vitest.config.ts`. Not applicable. +- **Reporter API removals (`onCollected` etc., `basic` reporter)** — no custom `reporters:` config anywhere in the repo. Not applicable. +- **`deps.optimizer.web` → `deps.optimizer.client`** — not configured anywhere. Not applicable. +- **Companion peer requirement: `@storybook/addon-vitest` requires `@vitest/browser-playwright: "^4.0.0"`** — checked live against both the currently-locked `9.1.20` and `main`'s `10.5.5`; both declare this peer as required (not in `peerDependenciesMeta`). Already covered by the pre-flight requirement above — must add this package in PR A regardless of which Storybook major is present. + +## Breaking Changes & Call Sites — PR B: `vite` 7.3.6 → 8.2.2 + `@vitejs/plugin-react` 5.0.0 → 5.2.0 + +### BC-B1 — Dependency-optimizer engine swap: esbuild → Rolldown (THE highest-risk item in this whole migration) +**Type:** Behavioral, engine-level — config API survives, discovery *behavior* does not carry a guarantee +**What changed:** Vite 8 replaces esbuild with Rolldown (a Rust bundler) for dependency pre-bundling/scanning. `optimizeDeps.esbuildOptions` is deprecated in favor of `optimizeDeps.rolldownOptions` (auto-converted for backward compat) — this repo doesn't use `esbuildOptions` anywhere, so no forced config edit there. + +**Verified directly against the installed packages (not assumed from docs):** diffed `vite@7.3.6`'s and `vite@8.2.2`'s `DepOptimizationConfig` TypeScript interface (both already present in this repo's `node_modules/.bun/`, the 8.2.2 copy pulled transitively via the `docs` workspace's `astro` dependency) — **`optimizeDeps.include` and `optimizeDeps.exclude` (`string[]` of resolvable import paths) are byte-identical in shape between the two versions.** The three existing guard locations' config API is untouched: +- `apps/web/vitest.config.ts:79-104` (`storybook` project `optimizeDeps.include`) +- `apps/web/vitest.config.ts:128-150` (`unit` project `optimizeDeps.include`, near-identical list) +- `apps/web/.storybook/main.ts:14-29` (`viteFinal` hook's `optimizeDeps.include`, used by real `storybook dev`/`build-storybook`, not just the vitest addon-vitest gate) + +**What is NOT guaranteed:** the current include lists (`react-dom/client`, `@storybook/react-dom-shim`, `motion/react`, `lucide-react`, `@dnd-kit/core`, the 4 `@xterm/*` addon packages, `@tauri-apps/api/webview`, plus `storybook/test`/`storybook/actions` in the Storybook config) were tuned empirically against **esbuild's** dependency scanner — specifically to catch modules that would otherwise be discovered mid-run and trigger the documented silent-hang trap (`docs/research/2026-07-11-ci-performance.md`, flake F3: a `"optimized dependencies changed"` reload orphans an in-flight browser test page, and the vitest server then waits forever with zero output — capped only by the CI step timeout). **Rolldown's dependency-scanning algorithm is a different implementation and is not guaranteed to discover (or fail to discover) the same set of modules in the same order as esbuild's scanner did.** This cannot be resolved by reading changelogs — it can only be resolved empirically. + +**What the plan must do to keep the guard effective:** +1. The CI cache `apps/web/node_modules/.vite` (`.github/workflows/ci.yml`, `web-coverage` job) is keyed on `hashFiles('bun.lock')` — bumping `vite`/`vitest` changes `bun.lock`, which **guarantees this PR's own first CI run is a cold-cache run**, i.e. exactly the highest-risk condition for the trap. This is actually useful: it means the PR's own CI gives a real cold-cache stress test for free, not a false-green from a stale warm cache. +2. Given F3's history shows the trigger is **nondeterministic** (it surfaced once in a 45-run sample per the CI-performance doc), a single green CI run on this PR is not sufficient evidence. Run `bun run test:web:coverage` locally **multiple times with a deleted `apps/web/node_modules/.vite` directory before each run** (`rm -rf apps/web/node_modules/.vite && bun run test:web:coverage`), and push at least 2-3 throwaway commits to the PR branch to get multiple independent cold CI runs, watching every log for the literal string `optimized dependencies changed` (the diagnostic signature). +3. If that string appears in any run: the vitest server log names the specific module that triggered the mid-run discovery (per the existing code comments' own description of this failure mode) — add that module to `optimizeDeps.include` in whichever of the 3 guard locations is relevant (both vitest projects if it's a browser-mode-shared dependency; `.storybook/main.ts` too if it's Storybook-specific) and re-run the cold-cache loop again until clean. +4. **Do not weaken or remove the existing `timeout-minutes: 7` step-level timeout** (`ci.yml`, the `bun run test:web:coverage` step) or the `timeout-minutes: 10` job-level timeout — these are what turn a would-be infinite hang into a fast, diagnosable red instead of burning the full job timeout. They remain valid and necessary under Rolldown exactly as they were under esbuild; this migration doesn't change what they defend against, only which engine can trigger the condition they defend against. +5. Treat one CI red on this specific PR as expected-possible, not a blocker signal to abandon the migration — the fix path (add the named module to the include list) is well-understood and cheap; budget for 1-2 iterations before declaring PR B stable. + +### BC-B2 — `vite/client.d.ts` CSS side-effect module declaration — VERIFIED INTACT, no fix needed +**Type:** N/A (verification, not a breaking change) +**Why this matters:** the TypeScript 6 migration (`docs/migrations/2026-08-31-typescript.md`, BC-2) flips `noUncheckedSideEffectImports` to `true` by default, and this repo's 5 CSS side-effect imports (`apps/web/src/main.tsx:2` `import './styles.css'`, plus 3× `import '@xterm/xterm/css/xterm.css'` in the terminal pane components) only typecheck because `vite/client.d.ts` ships `declare module '*.css' {}`. If Vite 8 dropped that declaration, this vite migration would silently re-break the just-landed TS 6 migration's guard. +**Verified directly, not assumed:** diffed the actual `client.d.ts` files from `vite@7.3.6` and `vite@8.2.2` (both already installed in this repo's `node_modules/.bun/`). **Both declare `'*.css' {}`, `'*.scss' {}`, `'*.sass' {}` identically** (line 40 vs line 43, offset only by 3 added lines earlier in the file — `vite/modulepreload-polyfill` and `*.wasm` declarations, both pure additions). No removals in the diff. The TS 6 `noUncheckedSideEffectImports` guard is unaffected by this vite bump. No fix needed. + +### BC-B3 — `@vitejs/plugin-react` 6.x peer range narrows to `vite: "^8.0.0"` only, and removes Babel +**Type:** Structural (peer range) + behavioral (transform engine swap) — this is why the recommendation is to stay on 5.2.0 +**What changed:** `@vitejs/plugin-react@6.0.0`+ declares `"vite": "^8.0.0"` exclusively (verified via `npm view @vitejs/plugin-react@6.0.0/6.0.1/6.1.0/6.1.1 peerDependencies` — all four consistently show only `^8.0.0`). It also removes Babel as a dependency entirely (install size ~45MB → ~8MB per the plugin's own release notes) in favor of an Oxc-based React Refresh transform, with React Compiler support moved behind an explicit opt-in (`oxc-transform-react`, `@rolldown/plugin-babel` as new optional peers) rather than the current Babel-based default. +**Call site:** `apps/web/package.json:49` (`"@vitejs/plugin-react": "^5.0.0"`), consumed in `apps/web/vite.config.ts:4,11` (`import react from '@vitejs/plugin-react'; ... plugins: [react(), tailwind()]`) and `apps/web/vitest.config.ts:5,115` (`unit` project's `plugins: [react(), tailwind()]`). +**Fix / recommendation:** bump to `@vitejs/plugin-react@5.2.0` (the latest 5.x, one minor ahead of the currently-locked `5.0.0`), **not** `6.1.1`. `5.2.0`'s peer range (`"^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"`, verified live) already covers vite 8 — confirmed directly by the plugin's own maintainers' migration notes: "v5 still works with Vite 8, so you can upgrade the plugin after upgrading Vite." This keeps the well-tested Babel-based JSX/Fast-Refresh transform in place and avoids stacking a second bundler-internals swap (Oxc transform) on top of BC-B1's Rolldown dep-optimizer swap in the same PR. No code-site changes needed beyond the version bump — the plugin's exported `react()` factory API is unchanged between 5.2.0 and current 5.0.0. +**Deferred, explicitly out of scope for this migration:** `@vitejs/plugin-react` 6.x / the Babel-removal / Oxc-transform jump. Revisit as its own future migration once Vite 8 + Vitest 4 have baked in production for a cycle, so any regression is attributable to one bundler-internals change at a time, not two. + +### BC-B4 — Default `build.target` browser baseline moves forward +**Type:** Behavioral, low risk for this repo +**What changed:** Vite 8's default `build.target` moves from Chrome 107/Edge 107/Firefox 104/Safari 16.0 to Chrome 111/Edge 111/Firefox 114/Safari 16.4 (aligned to "Baseline Widely Available" as of 2026-01-01). +**Call site:** `apps/web/vite.config.ts:23-25` already sets `build: { target: 'es2022' }` explicitly — this **overrides** Vite's own default target regardless of version, so this default-flip has zero observable effect here. Since the shipped app is a Tauri desktop frontend rendered in each OS's bundled WebKit/WebView2 (not a range of public browsers), the explicit `es2022` target is also the semantically correct choice independent of Vite's own default — no action needed. + +### BC-B5 — Tauri interaction — verified no coupling +**Type:** N/A (verification) +`apps/desktop/src-tauri/tauri.conf.json`'s `build` section (`devUrl: "http://localhost:5173"`, `beforeDevCommand`/`beforeBuildCommand` shelling out to `vite`/`vitest`-agnostic `bun run` scripts) has no Vite-major-specific requirement — Tauri's CLI (`@tauri-apps/cli@^2.11.2`, unrelated to this migration) just polls the configured `devUrl` over HTTP until it responds and serves `frontendDist` (`../../web/dist`) as static files at build time; it does not import or version-check the `vite` package. No `vite-plugin-tauri` or equivalent Tauri-specific Vite plugin is used (grepped both `vite.config.ts` and `vitest.config.ts` — no Tauri-specific imports beyond an `optimizeDeps.include` entry for `@tauri-apps/api/webview`, which is a runtime module path, not a build coupling). Zero interaction with this migration. + +### BC-B6 — `envPrefix` / `import.meta.env` — not applicable +**Type:** N/A (verification) +Grepped the entire `apps/web` tree for `envPrefix`, `VITE_`, and `import.meta.env` — **zero matches**. Tauri-detection in this codebase is a pure runtime check (`apps/web/src/lib/bridge/internal.ts:11`: `'__TAURI_INTERNALS__' in window`), not an env-var injected via Vite's `define`/`envPrefix` machinery. This entire class of Vite behavior is unused by the repo; nothing to migrate. + +## Companion Bumps / Lockstep Requirements + +| Package | Must move with | Why | +|---|---|---| +| `@vitest/browser`, `@vitest/coverage-istanbul` | `vitest` (exact) | Both declare `peerDependencies: { "vitest": "4.1.11" }` — an **exact** version peer (Vitest's own sub-packages always pin exact versions against each other), not a caret range. All three must land in the same commit at the same resolved version. | +| `vitest-browser-react` | `vitest` (^4.0.0) | `peerDependencies.vitest: "^4.0.0"` | +| `@vitest/browser-playwright` (new) | `vitest` (exact, 4.1.11) | New required package, not previously in the tree — see pre-flight. | +| `@storybook/addon-vitest` | none required, but re-verify | Already declares `vitest: "^3.0.0 || ^4.0.0"` and `@vitest/browser-playwright: "^4.0.0"` on both the `9.1.20` (this branch) and `10.5.5` (`main`) versions — no Storybook bump is *required* by this migration either direction, but do re-run `bun run test:stories` explicitly after PR A since this is the addon that actually drives vitest's browser mode for the Storybook project. | +| `@vitejs/plugin-react` | `vite` (peer range) | See BC-B3 — land `5.2.0` with vite `8.2.2` in the same PR B commit (it's a devDependency version bump, not independently useful without vite moving). | +| `motion`/`framer-motion`/`motion-dom` overrides (from `deps/phase-1-safe-bumps`, root `package.json` `overrides` block, pinned exact `12.42.2`) | no interaction | Runtime animation library, no build-tool/vite peer dependency. Checked, no interaction with either PR. | +| `@hono/node-server` override (from `deps/phase-1-safe-bumps`) | no interaction | Server-side MCP-transport package via `@anthropic-ai/claude-agent-sdk`, entirely unrelated to the frontend Vite/Vitest stack. No interaction. | + +## Codemods Available + +**None.** Confirmed no official Vitest 3→4 codemod exists (only unrelated Jest→Vitest and Mocha→Vitest codemods are published under the `codemod` registry). Vite itself does not publish a codemod for the 7→8 transition — it is a config-and-defaults release plus an internal engine swap, not an API-rename release. BC-A2 (the `@vitest/browser/context` import path) is the only item in this whole plan that is genuinely mechanical/`sed`-able across many files; everything else is either a single hand-written config rewrite (BC-A1) or a checked-safe no-op (BC-A3, BC-A4, BC-B2, BC-B4, BC-B5, BC-B6). + +## Upgrade Order + +**PR A — `vitest` family (land first, vite stays 7.3.6):** +1. Branch from `deps/typescript-6`. +2. `apps/web/package.json`: bump `vitest`, `@vitest/browser`, `@vitest/coverage-istanbul` to `4.1.11`; `vitest-browser-react` to `2.2.0`; add `@vitest/browser-playwright@4.1.11` as a new devDependency. Keep `@vitest/browser` (do not remove it — see pre-flight). +3. `packages/eslint-plugin/package.json`: bump `vitest` to `^4.1.11`. +4. Rewrite `apps/web/vitest.config.ts`'s `chromium()` helper per BC-A1 (import `playwright` from `@vitest/browser-playwright`, move `contextOptions` to the provider call). +5. (Optional, same PR or a trivial follow-up) sweep the 36-file `@vitest/browser/context` → `vitest/browser` import rename per BC-A2. +6. `bun install` to refresh `bun.lock`. +7. Run in order, fixing forward on red: `bunx tsc -b apps/web` → `bun run --filter @nightcore/web test:unit` → `bun run --filter @nightcore/web test:stories` → `bun run test:web:coverage` (repeat 2-3× with `rm -rf apps/web/node_modules/.vite` between runs, watching for `optimized dependencies changed` per BC-B1's guidance even though it's nominally a PR-B item — the Module Runner replacing vite-node internally is itself a Vitest-4-side change worth the same cold-cache scrutiny) → `bun run test:plugin` (exercises `packages/eslint-plugin`'s vitest bump). +8. Push, let CI's cold `bun.lock`-keyed cache stress-test this for real; iterate on the include lists only if a concrete `optimized dependencies changed` log line appears. +9. Merge PR A. Bake before starting PR B (at minimum, one full CI cycle post-merge with no new reds). + +**PR B — `vite` 8 + `@vitejs/plugin-react` (land after PR A is merged and stable):** +1. Branch from the post-PR-A tip (i.e. `deps/typescript-6` + PR A's commits). +2. `apps/web/package.json`: bump `vite` to `8.2.2`, `@vitejs/plugin-react` to `5.2.0` (**not** `6.1.1` — see BC-B3). +3. No config-shape edits are required for `optimizeDeps.include`/`exclude` (BC-B1 confirms the API is unchanged) — this PR's job is verification, not rewriting. +4. `bun install` to refresh `bun.lock`. +5. Run in order: `bunx tsc -b apps/web` → `bun run --filter @nightcore/web build` (exercises the actual `vite build` path, not just tests) → `bun run test:web:coverage`, repeated 2-3× with a deleted `.vite` cache dir per BC-B1's cold-cache loop, watching specifically for `optimized dependencies changed`. If it appears, add the named module to `optimizeDeps.include` in whichever of the 3 guard locations applies and re-loop. +6. Manually smoke-test `bun run desktop` (the real Tauri dev flow, `beforeDevCommand` → `vite --port 5173` → Tauri's `devUrl` poll) once, since BC-B5 is a "checked, no coupling" claim, not a substitute for actually booting the app once against the new Vite major. +7. Push, let CI's cold cache run for real (guaranteed cold since `bun.lock` changes again). +8. Merge PR B once green and the cold-cache loop has produced at least 2-3 consecutive clean runs, not just 1. + +## Verification + +- `bun run typecheck` (root `tsc -b`), `bunx tsc -b apps/web` clean at both PR A and PR B. +- `bun run lint` (incl. `lint:meta`) clean — no lint-meta rule references `vite`/`vitest` package internals directly (confirmed by grep), so this should be a pure pass-through, but run it anyway since it's part of the required gate battery. +- `bun run test:node`, `bun run test:plugin`, `bun run test:rust` green at both stages (these don't exercise the browser/vite-dev-server path directly, but `test:plugin` does exercise the `packages/eslint-plugin` vitest bump from PR A). +- `bun run test:web` (both vitest projects — `test:unit` and `test:stories`) green at both stages. +- **`bun run test:web:coverage` / the `vitest browser coverage (apps/web)` CI job** — the primary gate for this whole migration. Must be green with **repeated cold-cache runs** (not a single pass) per BC-B1's guidance, at both PR A and PR B. This is the literal file-size-ratchet-adjacent required check named in the repo's merge-gate ruleset (`docs/research/2026-07-11-ci-performance.md`). +- `bun run audit` still clean at both stages (a devDependency-only bump; not expected to introduce new advisories, but touches `bun.lock` so worth a quick re-check per the sibling dependency-upgrade-plan doc's own caution). +- File-size ratchet (`tools/lint-meta`'s `web-file-size-ratchet` rule) — the `vitest.config.ts` rewrite (BC-A1) and the 36-file import rename (BC-A2) both touch tracked files; unlikely to trip the ratchet (small diffs) but part of `bun run lint:meta`'s normal pass, no special action. +- Manual: boot `bun run desktop` once after PR B and confirm the Tauri window loads the dev server correctly (per BC-B5's upgrade-order step 6) — this is the one item in the whole plan that genuinely needs a human eyeball, not just green CI, since it's the actual shipped product surface this migration touches. + +## Rollback + +Both PRs are dev-tooling-only changes (`vite`/`vitest`-family devDependencies, one config file rewrite, 36 mechanical import-path edits, `bun.lock`) — zero production runtime code is touched beyond `apps/web/vite.config.ts`'s plugin version and `vitest.config.ts`'s test-only config. Rollback for either PR is a plain `git revert` of its merge commit — no data/state/migration concerns, no feature flags needed. Because the two PRs are sequential and independently revertible, a regression discovered after PR B merges can be resolved by reverting **only PR B** (returning to vite 7.3.6 + vitest 4.1.11, a state this plan explicitly verifies is valid per the coupling table in the Summary) without also reverting PR A's vitest-4 work. + +## Out of Scope + +- `@vitejs/plugin-react` 6.x (Babel removal, Oxc transform pipeline) — explicitly deferred, see BC-B3. Revisit as its own migration once vite 8 + vitest 4 have baked. +- Storybook 9→10 (already shipped on `main` via PR #449, not present on `deps/typescript-6` — see "Branch Staleness"). Not this migration's job to backport or re-verify; flagged as a sequencing risk for whoever lands this stack. +- Any other Phase 2/3/4 item from `docs/deps/2026-08-31-dependency-upgrade-plan.md` (dompurify, tauri-plugin-updater, shiki, marked, claude-agent-sdk, codex-sdk, motion 13.x, glib) — separate migrations, not touched here. +- Rolldown-native / raw-Rolldown usage, `@vitejs/plugin-react-oxc` (explicitly deprecated by the plugin-react maintainers in favor of the 6.x default — moot since this plan stays on 5.2.0 anyway). +- Wiring an explicit `optimizeDeps.rolldownOptions` config — not needed; the repo doesn't use `esbuildOptions` today, so there's nothing to migrate/convert, and `include`/`exclude` remain the only guard surface in use. + +--- + +## POST-IMPLEMENTATION CORRECTIONS — PR A, as actually landed (2026-08-31) + +Landing PR A surfaced four things this plan got wrong or missed. **Read this section before starting PR B** — two of them invalidate premises the PR B plan above is built on. + +### CORRECTION 1 (invalidates the two-PR premise): vite 8 arrives with PR A regardless — `vite` is a `dependencies` entry of vitest 4, not just a peer + +The Summary's coupling table reads `vitest@4.1.11`'s **`peerDependencies`** only. But `vitest@4.1.11` declares `"vite": "^6.0.0 || ^7.0.0 || ^8.0.0"` in **BOTH `peerDependencies` AND `dependencies`**. A real dependency is resolved by the package manager, not satisfied by the hoisted copy, and bun picks the highest satisfying version — `vite@8.2.2`, which `astro` (docs workspace) has already pulled into the tree. + +Result, verified on disk after `bun install`: + +- `node_modules/vite` → **7.3.6** (what `vite build` / `vite dev` use — the app build genuinely stays on vite 7) +- `node_modules/vitest/node_modules/vite` → **8.2.2** (what the vitest browser dev-server and dep-optimizer actually run) + +Confirmed at runtime, not just in the lockfile — `test:unit` logs: + +``` +[vite] warning: `optimizeDeps.esbuildOptions` option was specified by "vite:react-babel" plugin. + This option is deprecated, please use `optimizeDeps.rolldownOptions` instead. +You or a plugin you are using have set `optimizeDeps.esbuildOptions` but this option is now +deprecated. Vite now uses Rolldown to optimize the dependencies. +``` + +**So BC-B1 — the esbuild→Rolldown dep-optimizer swap, named above as "THE highest-risk item in this whole migration" — already landed in PR A.** The test suite is running on Rolldown today. + +This could not be prevented. Attempted and rejected: +- `resolutions: { "vitest/vite": "7.3.6" }` — bun 1.3.14 silently ignores scoped/nested patterns (no re-resolve). +- `overrides: { "vitest": { "vite": "7.3.6" } }` — bun ignores npm's nested-override form too. +- A flat `overrides: { "vite": "7.3.6" }` — would apply globally and break `astro@7.1.6`, which hard-requires `vite: ^8.0.13`. + +**Consequences for PR B:** PR B is now only "the *app build* moves to vite 8 + plugin-react 5.2.0". The Rolldown risk is already paid and measured (see CORRECTION 4). The plan's rollback claim — that reverting PR B returns you to "vite 7.3.6 + vitest 4.1.11" — is **wrong**: vitest carries its own vite 8 either way. + +### CORRECTION 2 (missed breaking change): `vitest-browser-react@2.x` made `render()` async + +Not mentioned anywhere above. `vitest-browser-react@2.x` changed `render()` from returning `RenderResult` to `Promise`. Bumping to `2.2.0` as the plan prescribes breaks **218 test files** — and not merely at the type level: it fails at runtime (`TypeError: disabled.unmount is not a function`), because every `render(...).getByRole(...)` / `.unmount()` chain now runs against a Promise. + +**Resolution: `vitest-browser-react` was deliberately held at `^1.0.0` (1.0.1).** Its peer range is `vitest: "^2.1.0 || ^3.0.0 || ^4.0.0-0"` and `@vitest/browser: "^2.1.0 || ^3.0.0 || ^4.0.0-0"` — `^4.0.0-0` semver-satisfies `4.1.11`, so 1.0.1 is a *supported* combination with vitest 4, not a hack. Verified: the full 517-file / 2953-test suite passes on it. + +The `1.x → 2.x` async-`render()` migration is real work (218 files, plus making the enclosing `test()` callbacks async) and belongs in **its own PR**, not bolted onto either vite PR. + +### CORRECTION 3 (missed blocker): Storybook pins `@vitest/spy@3.2.4` exactly → dual-package type skew + +The plan checked `@storybook/addon-vitest`'s peer *ranges* (`vitest: "^3.0.0 || ^4.0.0"`) and concluded Storybook 10.5.5 is vitest-4-ready. Its **`dependencies`** tell a different story: `storybook@10.5.5` depends on `@vitest/spy` at the **exact** version `3.2.4`. With vitest 4 hoisted at the root, bun keeps two copies, and their `Mock` types are structurally incompatible (vitest 4 added `MockSettledResultIncomplete` to `MockSettledResult`). Any test passing a `vi.fn()` into a composed story's args fails to typecheck: **159 errors across 69 files**. + +No released Storybook fixes this — `storybook@10.5.10` (current `latest`) still pins `@vitest/spy@3.2.4`. + +**Resolution: a root `overrides` entry, `"@vitest/spy": "4.1.11"`,** collapsing the two copies to one. `apps/web` typecheck goes 159 errors → 0, and all 2953 tests (including every Storybook play test, which exercise `fn()` from `storybook/test` heavily) pass against it. + +⚠ **This override crosses a major for Storybook (3.2.4 → 4.1.11) and therefore sits in tension with the documented override policy** in root `package.json` (`"//overrides"`): *"An override forces a PATCHED version. It never crosses a major."* It passes `bun run audit` — `assertOverridesBounded` treats exact pins as inherently bounded — so the automated gate does not catch it. It is recorded here because the policy's own escape clause covers exactly this case: *"If the patched version exists ONLY across a major, that is a dependency bump to review on its own."* Mitigations: `@vitest/spy` is dev-only test tooling with no runtime/product surface; and it must be bumped in lockstep with `vitest` (which depends on it at an exact version), so treat this entry as part of the vitest family, not an independent pin. **Revisit and delete it as soon as a Storybook release ships `@vitest/spy` 4.x.** + +### CORRECTION 4: the F3 cold-cache trap did NOT reproduce — measured, not assumed + +Because CORRECTION 1 means Rolldown is already live, PR A was stress-tested to PR B's standard: `bun run test:web` run **3 times, each with `rm -rf apps/web/node_modules/.vite` first**. All three: **517 files / 2953 tests passed, zero occurrences of `optimized dependencies changed`.** The existing `optimizeDeps.include` lists — tuned empirically against esbuild's scanner — appear to remain sufficient under Rolldown's. No include-list additions were needed. PR B should still repeat the cold-cache loop, but the `optimizeDeps` guard now has real evidence behind it, not just an assumption. + +### CORRECTION 5 (missed call site): `apps/web/tsconfig.json` `types` entry + +Not listed among BC-A1's call sites. `@vitest/browser@4` dropped its `./providers/*` export entries (and the `"./*"` wildcard), so `"types": ["vite/client", "@vitest/browser/providers/playwright"]` no longer resolves. Replaced with the provider package's types-only export: `"@vitest/browser-playwright/context"`. + +### Also landed in PR A + +- `.gitignore`: Vitest 4 writes failure screenshots to a new `**/.vitest-attachments/` directory (alongside the already-ignored `**/__screenshots__/`). Ignored, so test runs don't leave untracked binaries. +- BC-A2's 36-file `@vitest/browser/context` → `vitest/browser` sweep was included. It required an `eslint --fix` pass afterwards: the new specifier sorts differently under `simple-import-sort`, tripping the lint gate in all 36 files. +- BC-A3 and BC-A4 were confirmed correct — no `invocationCallOrder` or automock fixes were needed. diff --git a/package.json b/package.json index 15c95111..377cf41f 100644 --- a/package.json +++ b/package.json @@ -78,6 +78,7 @@ "js-yaml": ">=4.3.1 <5", "@hono/node-server": ">=1.19.15 <2", "framer-motion": "12.42.2", - "motion-dom": "12.42.2" + "motion-dom": "12.42.2", + "@vitest/spy": "4.1.11" } } diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index 55fcbf1c..3c67a798 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -29,7 +29,7 @@ "@typescript-eslint/rule-tester": "^8.68.0", "tsup": "^8.5.1", "typescript": "^6.0.3", - "vitest": "^3.2.7" + "vitest": "^4.1.11" }, "peerDependencies": { "eslint": ">=9.0.0",