diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index a7162fd64..6c1be41d3 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -34,24 +34,28 @@ jobs:
id: filter
uses: dorny/paths-filter@v3
with:
- # apps/docs is excluded from the frontend turbo run, so a
- # docs-only change does not need this job. apps/mobile has its
- # own mobile-verify workflow. Everything else the frontend job
- # touches is listed here; bias toward over-matching since a
- # missed path silently skips validation.
+ # apps/docs is excluded from the frontend turbo run, but knip does
+ # analyze it, so a docs-only change still needs this job.
+ # apps/mobile has its own mobile-verify workflow. Everything else
+ # the frontend job touches is listed here; bias toward
+ # over-matching since a missed path silently skips validation.
filters: |
frontend:
- 'apps/web/**'
- 'apps/desktop/**'
+ - 'apps/docs/**'
- 'packages/**'
- 'package.json'
- '.npmrc'
- 'pnpm-lock.yaml'
- 'pnpm-workspace.yaml'
- 'turbo.json'
+ - 'knip.jsonc'
- '.github/workflows/ci.yml'
- 'scripts/generate-reserved-slugs.mjs'
- 'server/internal/handler/reserved_slugs.json'
+ - 'scripts/check-ui-wildcard-exports.mjs'
+ - 'scripts/check-ui-wildcard-exports.test.sh'
- 'scripts/selfhost-config.test.sh'
- 'scripts/drop-database.sh'
- 'scripts/remove-worktree.sh'
@@ -213,6 +217,35 @@ jobs:
# exclude @multica/mobile.
run: pnpm exec turbo build typecheck lint --filter='!@multica/docs' --filter='!@multica/mobile'
+ # Blocking from the start: it reports nothing today, and it covers the
+ # one regression knip structurally cannot see. packages/ui exports four
+ # wildcards, which knip expands into entry-point globs over every file
+ # in those directories — so a newly stranded component there always
+ # reads as "used". See the script header for the options ruled out.
+ - name: Check packages/ui wildcard exports
+ if: ${{ needs.changes.outputs.frontend == 'true' }}
+ run: |
+ bash scripts/check-ui-wildcard-exports.test.sh
+ node scripts/check-ui-wildcard-exports.mjs
+
+ # WARN PHASE — reports, never blocks. `shamefully-hoist=true` in .npmrc
+ # hides both halves of the drift this catches: an undeclared import still
+ # resolves, and an obsolete declaration still installs. Neither shows up
+ # in build, typecheck, or lint.
+ #
+ # `continue-on-error` alone, with no `|| true`: the real exit code has to
+ # reach Actions for the step to show as a warning rather than a silent
+ # pass, and it is what makes the promotion below a one-line change.
+ #
+ # TO PROMOTE TO BLOCKING: once this step has run clean for a full cycle
+ # on main, drop `continue-on-error`. The findings it reports today are
+ # pre-existing dead code left out of the cleanup that introduced it
+ # (MUL-6353) — clear those first, or the flip turns them into a red main.
+ - name: Check for dead code and phantom dependencies (knip)
+ if: ${{ needs.changes.outputs.frontend == 'true' }}
+ continue-on-error: true
+ run: pnpm knip
+
frontend-test:
needs: changes
runs-on: ubuntu-latest
diff --git a/apps/web/package.json b/apps/web/package.json
index 3be1a8fbb..28f553dac 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -13,64 +13,20 @@
"postinstall": "fumadocs-mdx"
},
"dependencies": {
- "@base-ui/react": "^1.3.0",
- "@dnd-kit/core": "^6.3.1",
- "@dnd-kit/sortable": "^10.0.0",
- "@dnd-kit/utilities": "^3.2.2",
- "@emoji-mart/data": "^1.2.1",
- "@floating-ui/dom": "^1.7.6",
"@multica/core": "workspace:*",
"@multica/ui": "workspace:*",
"@multica/views": "workspace:*",
"@tanstack/react-query": "catalog:",
- "@tanstack/react-query-devtools": "^5.96.2",
- "@tiptap/extension-code-block-lowlight": "3.27.1",
- "@tiptap/extension-image": "3.27.1",
- "@tiptap/extension-link": "3.27.1",
- "@tiptap/extension-mention": "3.27.1",
- "@tiptap/extension-placeholder": "3.27.1",
- "@tiptap/extension-table": "3.27.1",
- "@tiptap/extension-table-cell": "3.27.1",
- "@tiptap/extension-table-header": "3.27.1",
- "@tiptap/extension-table-row": "3.27.1",
- "@tiptap/extension-typography": "3.27.1",
- "@tiptap/markdown": "3.27.1",
- "@tiptap/pm": "3.27.1",
- "@tiptap/react": "3.27.1",
- "@tiptap/starter-kit": "3.27.1",
- "@tiptap/suggestion": "3.27.1",
- "@types/linkify-it": "^5.0.0",
- "class-variance-authority": "^0.7.1",
- "clsx": "^2.1.1",
- "cmdk": "^1.1.1",
- "date-fns": "^4.1.0",
"dotenv": "^17.4.1",
- "embla-carousel-react": "^8.6.0",
- "emoji-mart": "^5.6.0",
"fumadocs-core": "^15.5.2",
"fumadocs-mdx": "^12.0.3",
- "input-otp": "^1.4.2",
- "linkify-it": "^5.0.0",
- "lowlight": "^3.3.0",
"lucide-react": "catalog:",
"next": "^16.2.5",
- "next-themes": "^0.4.6",
"react": "catalog:",
- "react-day-picker": "^9.14.0",
"react-dom": "catalog:",
- "react-markdown": "^10.1.0",
- "react-resizable-panels": "^4.7.5",
- "recharts": "3.8.0",
- "rehype-raw": "^7.0.0",
- "remark-gfm": "^4.0.1",
"shadcn": "^4.1.0",
- "shiki": "^3.21.0",
- "sonner": "^2.0.7",
- "tailwind-merge": "^3.5.0",
"tw-animate-css": "^1.4.0",
- "vaul": "^1.1.2",
- "zod": "catalog:",
- "zustand": "catalog:"
+ "zod": "catalog:"
},
"devDependencies": {
"@multica/eslint-config": "workspace:*",
diff --git a/knip.jsonc b/knip.jsonc
new file mode 100644
index 000000000..a19014ef1
--- /dev/null
+++ b/knip.jsonc
@@ -0,0 +1,79 @@
+{
+ "$schema": "https://unpkg.com/knip@6/schema.json",
+
+ // Guards the invariant in CLAUDE.md "Package Boundaries": every workspace
+ // declares the external packages it actually imports, and nothing else.
+ // `.npmrc` sets `shamefully-hoist=true`, so an undeclared import still
+ // resolves at runtime and an obsolete declaration still installs — neither
+ // failure is visible without a tool that reads the import graph.
+ //
+ // Scoped to `files`, `dependencies`, and `unlisted` on purpose. `exports` is
+ // the noisy one here: packages/ui and packages/views are consumed through
+ // per-file `exports` maps, so a named export used by exactly one app still
+ // reads as "unused" from inside its own workspace.
+ "include": ["files", "dependencies", "unlisted"],
+
+ // Go, and a workspace with its own Expo toolchain, lint pipeline, and React
+ // version (see apps/mobile/CLAUDE.md). Neither is covered by this config.
+ "ignoreWorkspaces": ["apps/mobile"],
+
+ "workspaces": {
+ ".": {
+ "entry": ["scripts/*.mjs"],
+ "project": ["scripts/*.mjs"]
+ },
+
+ "apps/web": {
+ "entry": ["eslint.config.mjs"],
+ // Referenced only by the `@type {import('postcss-load-config').Config}`
+ // JSDoc annotation in postcss.config.mjs. Declaring it would add a
+ // runtime dependency to satisfy a type comment.
+ "ignoreDependencies": ["postcss-load-config"]
+ },
+
+ "apps/desktop": {
+ // window-state.node-test.mjs is run by hand (`node --test`, see its
+ // header) rather than by a package script, so nothing imports it.
+ "entry": ["eslint.config.mjs", "src/main/*.node-test.mjs"],
+ // Consumed by `extends` in tsconfig.node.json / tsconfig.web.json.
+ // knip follows `extends` from the default tsconfig.json only.
+ "ignoreDependencies": ["@multica/tsconfig"]
+ },
+
+ "apps/docs": {},
+
+ // The three shared packages export raw .ts/.tsx compiled by their
+ // consumers (CLAUDE.md "Project Shape"), so `entry` names only the config
+ // files knip would otherwise miss and the apps supply the real entry
+ // points — a file is live when an app reaches it.
+ //
+ // That holds for views and core, whose `exports` name specific files
+ // (44 of views' 45). It does NOT hold for the four wildcard exports in
+ // packages/ui: knip expands each into a glob over its whole directory and
+ // registers every match as an entry point, so nothing under
+ // components/ui, components/common, markdown, or hooks can ever be
+ // reported unused here. `entry: []`, negated `entry` patterns, and
+ // `--production` were all tried — manifest entries come from a separate
+ // code path that none of them subtract from.
+ //
+ // scripts/check-ui-wildcard-exports.mjs covers exactly those four
+ // directories and runs as its own blocking CI step. Narrow a wildcard
+ // export and knip picks that directory back up; the script reads the same
+ // manifest, so the two stay in step without overlapping.
+ "packages/ui": {
+ "entry": ["eslint.config.mjs"],
+ "project": ["**/*.{ts,tsx}"]
+ },
+ "packages/views": {
+ "entry": ["eslint.config.mjs"],
+ "project": ["**/*.{ts,tsx}"]
+ },
+ "packages/core": {
+ "entry": ["eslint.config.mjs"],
+ "project": ["**/*.{ts,tsx}"]
+ },
+
+ "packages/eslint-config": {},
+ "packages/tsconfig": {}
+ }
+}
diff --git a/package.json b/package.json
index c31116a20..a16bbd702 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,8 @@
"typecheck": "turbo typecheck --filter=!@multica/mobile",
"test": "turbo test --filter=!@multica/mobile",
"lint": "turbo lint --filter=!@multica/mobile",
+ "knip": "knip",
+ "check:ui-exports": "node scripts/check-ui-wildcard-exports.mjs",
"clean": "turbo clean && rm -rf node_modules",
"ui:add": "cd packages/ui && npx shadcn@latest add",
"generate:reserved-slugs": "node scripts/generate-reserved-slugs.mjs"
@@ -48,6 +50,7 @@
"@playwright/test": "^1.58.2",
"@types/node": "catalog:",
"@types/pg": "^8.20.0",
+ "knip": "^6.32.2",
"pg": "^8.20.0",
"turbo": "^2.5.4",
"typescript": "catalog:"
diff --git a/packages/core/package.json b/packages/core/package.json
index 9463ad276..e09368a6b 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -159,7 +159,6 @@
"dependencies": {
"@formatjs/intl-localematcher": "catalog:",
"@tanstack/react-query": "catalog:",
- "@tanstack/react-query-devtools": "^5.96.2",
"i18next": "catalog:",
"posthog-js": "catalog:",
"react-i18next": "catalog:",
diff --git a/packages/ui/components/common/mention-hover-card.tsx b/packages/ui/components/common/mention-hover-card.tsx
deleted file mode 100644
index c1eedb3a1..000000000
--- a/packages/ui/components/common/mention-hover-card.tsx
+++ /dev/null
@@ -1,74 +0,0 @@
-"use client";
-
-import type { ReactNode } from "react";
-import { Users } from "lucide-react";
-import { HoverCard, HoverCardTrigger, HoverCardContent } from "@multica/ui/components/ui/hover-card";
-import { ActorAvatar } from "./actor-avatar";
-
-interface MentionHoverCardProps {
- type: string;
- id: string;
- name: string;
- initials: string;
- avatarUrl?: string | null;
- role?: string;
- children: ReactNode;
-}
-
-function MentionHoverCard({
- type,
- id: _id,
- name,
- initials,
- avatarUrl,
- role,
- children,
-}: MentionHoverCardProps) {
- if (type === "all") {
- return (
-
- } className="cursor-default">
- {children}
-
-
-
-
-
-
-
-
All members
-
Notifies all workspace members
-
-
-
-
- );
- }
-
- return (
-
- } className="cursor-default">
- {children}
-
-
-
-
-
-
{name}
- {role && (
-
{role}
- )}
-
-
-
-
- );
-}
-
-export { MentionHoverCard, type MentionHoverCardProps };
diff --git a/packages/ui/components/ui/accordion.tsx b/packages/ui/components/ui/accordion.tsx
deleted file mode 100644
index 124c859f3..000000000
--- a/packages/ui/components/ui/accordion.tsx
+++ /dev/null
@@ -1,74 +0,0 @@
-"use client"
-
-import { Accordion as AccordionPrimitive } from "@base-ui/react/accordion"
-
-import { cn } from "@multica/ui/lib/utils"
-import { ChevronDownIcon, ChevronUpIcon } from "lucide-react"
-
-function Accordion({ className, ...props }: AccordionPrimitive.Root.Props) {
- return (
-
- )
-}
-
-function AccordionItem({ className, ...props }: AccordionPrimitive.Item.Props) {
- return (
-
- )
-}
-
-function AccordionTrigger({
- className,
- children,
- ...props
-}: AccordionPrimitive.Trigger.Props) {
- return (
-
-
- {children}
-
-
-
-
- )
-}
-
-function AccordionContent({
- className,
- children,
- ...props
-}: AccordionPrimitive.Panel.Props) {
- return (
-
-
- {children}
-
-
- )
-}
-
-export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
diff --git a/packages/ui/components/ui/aspect-ratio.tsx b/packages/ui/components/ui/aspect-ratio.tsx
deleted file mode 100644
index f0bdf5342..000000000
--- a/packages/ui/components/ui/aspect-ratio.tsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import { cn } from "@multica/ui/lib/utils"
-
-function AspectRatio({
- ratio,
- className,
- ...props
-}: React.ComponentProps<"div"> & { ratio: number }) {
- return (
-
- )
-}
-
-export { AspectRatio }
diff --git a/packages/ui/components/ui/breadcrumb.tsx b/packages/ui/components/ui/breadcrumb.tsx
deleted file mode 100644
index 01072432b..000000000
--- a/packages/ui/components/ui/breadcrumb.tsx
+++ /dev/null
@@ -1,125 +0,0 @@
-import * as React from "react"
-import { mergeProps } from "@base-ui/react/merge-props"
-import { useRender } from "@base-ui/react/use-render"
-
-import { cn } from "@multica/ui/lib/utils"
-import { ChevronRightIcon, MoreHorizontalIcon } from "lucide-react"
-
-function Breadcrumb({ className, ...props }: React.ComponentProps<"nav">) {
- return (
-
- )
-}
-
-function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
- return (
-
- )
-}
-
-function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
- return (
-
- )
-}
-
-function BreadcrumbLink({
- className,
- render,
- ...props
-}: useRender.ComponentProps<"a">) {
- return useRender({
- defaultTagName: "a",
- props: mergeProps<"a">(
- {
- className: cn("transition-colors hover:text-foreground", className),
- },
- props
- ),
- render,
- state: {
- slot: "breadcrumb-link",
- },
- })
-}
-
-function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
- return (
-
- )
-}
-
-function BreadcrumbSeparator({
- children,
- className,
- ...props
-}: React.ComponentProps<"li">) {
- return (
- svg]:size-3.5", className)}
- {...props}
- >
- {children ?? (
-
- )}
-
- )
-}
-
-function BreadcrumbEllipsis({
- className,
- ...props
-}: React.ComponentProps<"span">) {
- return (
- svg]:size-4",
- className
- )}
- {...props}
- >
-
- More
-
- )
-}
-
-export {
- Breadcrumb,
- BreadcrumbList,
- BreadcrumbItem,
- BreadcrumbLink,
- BreadcrumbPage,
- BreadcrumbSeparator,
- BreadcrumbEllipsis,
-}
diff --git a/packages/ui/components/ui/button-group.tsx b/packages/ui/components/ui/button-group.tsx
deleted file mode 100644
index beff59cbb..000000000
--- a/packages/ui/components/ui/button-group.tsx
+++ /dev/null
@@ -1,87 +0,0 @@
-import { mergeProps } from "@base-ui/react/merge-props"
-import { useRender } from "@base-ui/react/use-render"
-import { cva, type VariantProps } from "class-variance-authority"
-
-import { cn } from "@multica/ui/lib/utils"
-import { Separator } from "@multica/ui/components/ui/separator"
-
-const buttonGroupVariants = cva(
- "flex w-fit items-stretch *:focus-visible:relative *:focus-visible:z-10 has-[>[data-slot=button-group]]:gap-2 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-lg [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1",
- {
- variants: {
- orientation: {
- horizontal:
- "*:data-slot:rounded-r-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-r-lg! [&>[data-slot]~[data-slot]]:rounded-l-none [&>[data-slot]~[data-slot]]:border-l-0",
- vertical:
- "flex-col *:data-slot:rounded-b-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-b-lg! [&>[data-slot]~[data-slot]]:rounded-t-none [&>[data-slot]~[data-slot]]:border-t-0",
- },
- },
- defaultVariants: {
- orientation: "horizontal",
- },
- }
-)
-
-function ButtonGroup({
- className,
- orientation,
- ...props
-}: React.ComponentProps<"div"> & VariantProps) {
- return (
-
- )
-}
-
-function ButtonGroupText({
- className,
- render,
- ...props
-}: useRender.ComponentProps<"div">) {
- return useRender({
- defaultTagName: "div",
- props: mergeProps<"div">(
- {
- className: cn(
- "flex items-center gap-2 rounded-lg border bg-muted px-2.5 text-body font-medium [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
- className
- ),
- },
- props
- ),
- render,
- state: {
- slot: "button-group-text",
- },
- })
-}
-
-function ButtonGroupSeparator({
- className,
- orientation = "vertical",
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-export {
- ButtonGroup,
- ButtonGroupSeparator,
- ButtonGroupText,
- buttonGroupVariants,
-}
diff --git a/packages/ui/components/ui/carousel.tsx b/packages/ui/components/ui/carousel.tsx
deleted file mode 100644
index 27d9dc041..000000000
--- a/packages/ui/components/ui/carousel.tsx
+++ /dev/null
@@ -1,242 +0,0 @@
-"use client"
-
-import * as React from "react"
-import useEmblaCarousel, {
- type UseEmblaCarouselType,
-} from "embla-carousel-react"
-
-import { cn } from "@multica/ui/lib/utils"
-import { Button } from "@multica/ui/components/ui/button"
-import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react"
-
-type CarouselApi = UseEmblaCarouselType[1]
-type UseCarouselParameters = Parameters
-type CarouselOptions = UseCarouselParameters[0]
-type CarouselPlugin = UseCarouselParameters[1]
-
-type CarouselProps = {
- opts?: CarouselOptions
- plugins?: CarouselPlugin
- orientation?: "horizontal" | "vertical"
- setApi?: (api: CarouselApi) => void
-}
-
-type CarouselContextProps = {
- carouselRef: ReturnType[0]
- api: ReturnType[1]
- scrollPrev: () => void
- scrollNext: () => void
- canScrollPrev: boolean
- canScrollNext: boolean
-} & CarouselProps
-
-const CarouselContext = React.createContext(null)
-
-function useCarousel() {
- const context = React.use(CarouselContext)
-
- if (!context) {
- throw new Error("useCarousel must be used within a ")
- }
-
- return context
-}
-
-function Carousel({
- orientation = "horizontal",
- opts,
- setApi,
- plugins,
- className,
- children,
- ...props
-}: React.ComponentProps<"div"> & CarouselProps) {
- const [carouselRef, api] = useEmblaCarousel(
- {
- ...opts,
- axis: orientation === "horizontal" ? "x" : "y",
- },
- plugins
- )
- const [canScrollPrev, setCanScrollPrev] = React.useState(false)
- const [canScrollNext, setCanScrollNext] = React.useState(false)
-
- const onSelect = React.useCallback((api: CarouselApi) => {
- if (!api) return
- setCanScrollPrev(api.canScrollPrev())
- setCanScrollNext(api.canScrollNext())
- }, [])
-
- const scrollPrev = React.useCallback(() => {
- api?.scrollPrev()
- }, [api])
-
- const scrollNext = React.useCallback(() => {
- api?.scrollNext()
- }, [api])
-
- const handleKeyDown = React.useCallback(
- (event: React.KeyboardEvent) => {
- if (event.key === "ArrowLeft") {
- event.preventDefault()
- scrollPrev()
- } else if (event.key === "ArrowRight") {
- event.preventDefault()
- scrollNext()
- }
- },
- [scrollPrev, scrollNext]
- )
-
- React.useEffect(() => {
- if (!api || !setApi) return
- setApi(api)
- }, [api, setApi])
-
- React.useEffect(() => {
- if (!api) return
- onSelect(api)
- api.on("reInit", onSelect)
- api.on("select", onSelect)
-
- return () => {
- api?.off("select", onSelect)
- }
- }, [api, onSelect])
-
- return (
-
-
- {children}
-
-
- )
-}
-
-function CarouselContent({ className, ...props }: React.ComponentProps<"div">) {
- const { carouselRef, orientation } = useCarousel()
-
- return (
-
- )
-}
-
-function CarouselItem({ className, ...props }: React.ComponentProps<"div">) {
- const { orientation } = useCarousel()
-
- return (
-
- )
-}
-
-function CarouselPrevious({
- className,
- variant = "outline",
- size = "icon-sm",
- ...props
-}: React.ComponentProps) {
- const { orientation, scrollPrev, canScrollPrev } = useCarousel()
-
- return (
-
-
- Previous slide
-
- )
-}
-
-function CarouselNext({
- className,
- variant = "outline",
- size = "icon-sm",
- ...props
-}: React.ComponentProps) {
- const { orientation, scrollNext, canScrollNext } = useCarousel()
-
- return (
-
-
- Next slide
-
- )
-}
-
-export {
- type CarouselApi,
- Carousel,
- CarouselContent,
- CarouselItem,
- CarouselPrevious,
- CarouselNext,
- useCarousel,
-}
diff --git a/packages/ui/components/ui/combobox.tsx b/packages/ui/components/ui/combobox.tsx
deleted file mode 100644
index 118e316f4..000000000
--- a/packages/ui/components/ui/combobox.tsx
+++ /dev/null
@@ -1,297 +0,0 @@
-"use client"
-
-import * as React from "react"
-import { Combobox as ComboboxPrimitive } from "@base-ui/react"
-
-import { cn } from "@multica/ui/lib/utils"
-import { Button } from "@multica/ui/components/ui/button"
-import {
- InputGroup,
- InputGroupAddon,
- InputGroupButton,
- InputGroupInput,
-} from "@multica/ui/components/ui/input-group"
-import { ChevronDownIcon, XIcon, CheckIcon } from "lucide-react"
-
-const Combobox = ComboboxPrimitive.Root
-
-function ComboboxValue({ ...props }: ComboboxPrimitive.Value.Props) {
- return
-}
-
-function ComboboxTrigger({
- className,
- children,
- ...props
-}: ComboboxPrimitive.Trigger.Props) {
- return (
-
- {children}
-
-
- )
-}
-
-function ComboboxClear({ className, ...props }: ComboboxPrimitive.Clear.Props) {
- return (
- }
- className={cn(className)}
- {...props}
- >
-
-
- )
-}
-
-function ComboboxInput({
- className,
- children,
- disabled = false,
- showTrigger = true,
- showClear = false,
- ...props
-}: ComboboxPrimitive.Input.Props & {
- showTrigger?: boolean
- showClear?: boolean
-}) {
- return (
-
- }
- {...props}
- />
-
- {showTrigger && (
- }
- data-slot="input-group-button"
- className="group-has-data-[slot=combobox-clear]/input-group:hidden data-pressed:bg-transparent"
- disabled={disabled}
- />
- )}
- {showClear && }
-
- {children}
-
- )
-}
-
-function ComboboxContent({
- className,
- side = "bottom",
- sideOffset = 6,
- align = "start",
- alignOffset = 0,
- anchor,
- ...props
-}: ComboboxPrimitive.Popup.Props &
- Pick<
- ComboboxPrimitive.Positioner.Props,
- "side" | "align" | "sideOffset" | "alignOffset" | "anchor"
- >) {
- return (
-
-
-
-
-
- )
-}
-
-function ComboboxList({ className, ...props }: ComboboxPrimitive.List.Props) {
- return (
-
- )
-}
-
-function ComboboxItem({
- className,
- children,
- ...props
-}: ComboboxPrimitive.Item.Props) {
- return (
-
- {children}
-
- }
- >
-
-
-
- )
-}
-
-function ComboboxGroup({ className, ...props }: ComboboxPrimitive.Group.Props) {
- return (
-
- )
-}
-
-function ComboboxLabel({
- className,
- ...props
-}: ComboboxPrimitive.GroupLabel.Props) {
- return (
-
- )
-}
-
-function ComboboxCollection({ ...props }: ComboboxPrimitive.Collection.Props) {
- return (
-
- )
-}
-
-function ComboboxEmpty({ className, ...props }: ComboboxPrimitive.Empty.Props) {
- return (
-
- )
-}
-
-function ComboboxSeparator({
- className,
- ...props
-}: ComboboxPrimitive.Separator.Props) {
- return (
-
- )
-}
-
-function ComboboxChips({
- className,
- ...props
-}: React.ComponentPropsWithRef &
- ComboboxPrimitive.Chips.Props) {
- return (
-
- )
-}
-
-function ComboboxChip({
- className,
- children,
- showRemove = true,
- ...props
-}: ComboboxPrimitive.Chip.Props & {
- showRemove?: boolean
-}) {
- return (
-
- {children}
- {showRemove && (
- }
- className="-ml-1 opacity-50 hover:opacity-100"
- data-slot="combobox-chip-remove"
- >
-
-
- )}
-
- )
-}
-
-function ComboboxChipsInput({
- className,
- ...props
-}: ComboboxPrimitive.Input.Props) {
- return (
-
- )
-}
-
-function useComboboxAnchor() {
- return React.useRef(null)
-}
-
-export {
- Combobox,
- ComboboxInput,
- ComboboxContent,
- ComboboxList,
- ComboboxItem,
- ComboboxGroup,
- ComboboxLabel,
- ComboboxCollection,
- ComboboxEmpty,
- ComboboxSeparator,
- ComboboxChips,
- ComboboxChip,
- ComboboxChipsInput,
- ComboboxTrigger,
- ComboboxValue,
- useComboboxAnchor,
-}
diff --git a/packages/ui/components/ui/data-table-column-header.tsx b/packages/ui/components/ui/data-table-column-header.tsx
deleted file mode 100644
index 8e9c60319..000000000
--- a/packages/ui/components/ui/data-table-column-header.tsx
+++ /dev/null
@@ -1,106 +0,0 @@
-"use client";
-
-import type { Column } from "@tanstack/react-table";
-import {
- ChevronDown,
- ChevronsUpDown,
- ChevronUp,
- EyeOff,
- X,
-} from "lucide-react";
-import type * as React from "react";
-
-import {
- DropdownMenu,
- DropdownMenuCheckboxItem,
- DropdownMenuContent,
- DropdownMenuItem,
- DropdownMenuTrigger,
-} from "@multica/ui/components/ui/dropdown-menu";
-import { cn } from "@multica/ui/lib/utils";
-
-interface DataTableColumnHeaderProps
- extends React.ComponentProps {
- column: Column;
- label: string;
-}
-
-// Sort/hide-aware column header, adapted from Dice UI
-// (https://diceui.com/r/data-table). Renders the label as plain text when
-// the column has neither sorting nor hiding enabled (so non-interactive
-// columns don't expose a useless dropdown). Otherwise wraps the label in
-// a dropdown-menu trigger that toggles sort direction and hides the
-// column on demand.
-export function DataTableColumnHeader({
- column,
- label,
- className,
- ...props
-}: DataTableColumnHeaderProps) {
- if (!column.getCanSort() && !column.getCanHide()) {
- return {label}
;
- }
-
- return (
-
-
- {label}
- {column.getCanSort() &&
- (column.getIsSorted() === "desc" ? (
-
- ) : column.getIsSorted() === "asc" ? (
-
- ) : (
-
- ))}
-
-
- {column.getCanSort() && (
- <>
- column.toggleSorting(false)}
- >
-
- Asc
-
- column.toggleSorting(true)}
- >
-
- Desc
-
- {column.getIsSorted() && (
- column.clearSorting()}
- >
-
- Reset
-
- )}
- >
- )}
- {column.getCanHide() && (
- column.toggleVisibility(false)}
- >
-
- Hide
-
- )}
-
-
- );
-}
diff --git a/packages/ui/components/ui/direction.tsx b/packages/ui/components/ui/direction.tsx
deleted file mode 100644
index d8cf13461..000000000
--- a/packages/ui/components/ui/direction.tsx
+++ /dev/null
@@ -1,6 +0,0 @@
-"use client"
-
-export {
- DirectionProvider,
- useDirection,
-} from "@base-ui/react/direction-provider"
diff --git a/packages/ui/components/ui/drawer.tsx b/packages/ui/components/ui/drawer.tsx
deleted file mode 100644
index ab7cddbde..000000000
--- a/packages/ui/components/ui/drawer.tsx
+++ /dev/null
@@ -1,134 +0,0 @@
-"use client"
-
-import * as React from "react"
-import { Drawer as DrawerPrimitive } from "vaul"
-
-import { cn } from "@multica/ui/lib/utils"
-
-function Drawer({
- ...props
-}: React.ComponentProps) {
- return
-}
-
-function DrawerTrigger({
- ...props
-}: React.ComponentProps) {
- return
-}
-
-function DrawerPortal({
- ...props
-}: React.ComponentProps) {
- return
-}
-
-function DrawerClose({
- ...props
-}: React.ComponentProps) {
- return
-}
-
-function DrawerOverlay({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function DrawerContent({
- className,
- children,
- ...props
-}: React.ComponentProps) {
- return (
-
-
-
-
- {children}
-
-
- )
-}
-
-function DrawerHeader({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
-}
-
-function DrawerFooter({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
-}
-
-function DrawerTitle({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function DrawerDescription({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-export {
- Drawer,
- DrawerPortal,
- DrawerOverlay,
- DrawerTrigger,
- DrawerClose,
- DrawerContent,
- DrawerHeader,
- DrawerFooter,
- DrawerTitle,
- DrawerDescription,
-}
diff --git a/packages/ui/components/ui/menubar.tsx b/packages/ui/components/ui/menubar.tsx
deleted file mode 100644
index 9ad056e6c..000000000
--- a/packages/ui/components/ui/menubar.tsx
+++ /dev/null
@@ -1,280 +0,0 @@
-"use client"
-
-import * as React from "react"
-import { Menu as MenuPrimitive } from "@base-ui/react/menu"
-import { Menubar as MenubarPrimitive } from "@base-ui/react/menubar"
-
-import { cn } from "@multica/ui/lib/utils"
-import {
- DropdownMenu,
- DropdownMenuContent,
- DropdownMenuGroup,
- DropdownMenuItem,
- DropdownMenuLabel,
- DropdownMenuPortal,
- DropdownMenuRadioGroup,
- DropdownMenuSeparator,
- DropdownMenuShortcut,
- DropdownMenuSub,
- DropdownMenuSubContent,
- DropdownMenuSubTrigger,
- DropdownMenuTrigger,
-} from "@multica/ui/components/ui/dropdown-menu"
-import { CheckIcon } from "lucide-react"
-
-function Menubar({ className, ...props }: MenubarPrimitive.Props) {
- return (
-
- )
-}
-
-function MenubarMenu({ ...props }: React.ComponentProps) {
- return
-}
-
-function MenubarGroup({
- ...props
-}: React.ComponentProps) {
- return
-}
-
-function MenubarPortal({
- ...props
-}: React.ComponentProps) {
- return
-}
-
-function MenubarTrigger({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function MenubarContent({
- className,
- align = "start",
- alignOffset = -4,
- sideOffset = 8,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function MenubarItem({
- className,
- inset,
- variant = "default",
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function MenubarCheckboxItem({
- className,
- children,
- checked,
- inset,
- ...props
-}: MenuPrimitive.CheckboxItem.Props & {
- inset?: boolean
-}) {
- return (
-
-
-
-
-
-
- {children}
-
- )
-}
-
-function MenubarRadioGroup({
- ...props
-}: React.ComponentProps) {
- return
-}
-
-function MenubarRadioItem({
- className,
- children,
- inset,
- ...props
-}: MenuPrimitive.RadioItem.Props & {
- inset?: boolean
-}) {
- return (
-
-
-
-
-
-
- {children}
-
- )
-}
-
-function MenubarLabel({
- className,
- inset,
- ...props
-}: React.ComponentProps & {
- inset?: boolean
-}) {
- return (
-
- )
-}
-
-function MenubarSeparator({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function MenubarShortcut({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function MenubarSub({
- ...props
-}: React.ComponentProps) {
- return
-}
-
-function MenubarSubTrigger({
- className,
- inset,
- ...props
-}: React.ComponentProps & {
- inset?: boolean
-}) {
- return (
-
- )
-}
-
-function MenubarSubContent({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-export {
- Menubar,
- MenubarPortal,
- MenubarMenu,
- MenubarTrigger,
- MenubarContent,
- MenubarGroup,
- MenubarSeparator,
- MenubarLabel,
- MenubarItem,
- MenubarShortcut,
- MenubarCheckboxItem,
- MenubarRadioGroup,
- MenubarRadioItem,
- MenubarSub,
- MenubarSubTrigger,
- MenubarSubContent,
-}
diff --git a/packages/ui/components/ui/native-select.tsx b/packages/ui/components/ui/native-select.tsx
deleted file mode 100644
index 304e589f9..000000000
--- a/packages/ui/components/ui/native-select.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-import * as React from "react"
-
-import { cn } from "@multica/ui/lib/utils"
-import { ChevronDownIcon } from "lucide-react"
-
-type NativeSelectProps = Omit, "size"> & {
- size?: "sm" | "default"
-}
-
-function NativeSelect({
- className,
- size = "default",
- ...props
-}: NativeSelectProps) {
- return (
-
-
-
-
- )
-}
-
-function NativeSelectOption({ ...props }: React.ComponentProps<"option">) {
- return
-}
-
-function NativeSelectOptGroup({
- className,
- ...props
-}: React.ComponentProps<"optgroup">) {
- return (
-
- )
-}
-
-export { NativeSelect, NativeSelectOptGroup, NativeSelectOption }
diff --git a/packages/ui/components/ui/navigation-menu.tsx b/packages/ui/components/ui/navigation-menu.tsx
deleted file mode 100644
index 87eac2537..000000000
--- a/packages/ui/components/ui/navigation-menu.tsx
+++ /dev/null
@@ -1,168 +0,0 @@
-import { NavigationMenu as NavigationMenuPrimitive } from "@base-ui/react/navigation-menu"
-import { cva } from "class-variance-authority"
-
-import { cn } from "@multica/ui/lib/utils"
-import { ChevronDownIcon } from "lucide-react"
-
-function NavigationMenu({
- align = "start",
- className,
- children,
- ...props
-}: NavigationMenuPrimitive.Root.Props &
- Pick) {
- return (
-
- {children}
-
-
- )
-}
-
-function NavigationMenuList({
- className,
- ...props
-}: React.ComponentPropsWithRef) {
- return (
-
- )
-}
-
-function NavigationMenuItem({
- className,
- ...props
-}: React.ComponentPropsWithRef) {
- return (
-
- )
-}
-
-const navigationMenuTriggerStyle = cva(
- "group/navigation-menu-trigger inline-flex h-9 w-max items-center justify-center rounded-lg bg-background px-2.5 py-1.5 text-body font-medium transition-all outline-none hover:bg-muted focus:bg-muted focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-popup-open:bg-muted/50 data-popup-open:hover:bg-muted data-open:bg-muted/50 data-open:hover:bg-muted data-open:focus:bg-muted"
-)
-
-function NavigationMenuTrigger({
- className,
- children,
- ...props
-}: NavigationMenuPrimitive.Trigger.Props) {
- return (
-
- {children}{" "}
-
-
- )
-}
-
-function NavigationMenuContent({
- className,
- ...props
-}: NavigationMenuPrimitive.Content.Props) {
- return (
-
- )
-}
-
-function NavigationMenuPositioner({
- className,
- side = "bottom",
- sideOffset = 8,
- align = "start",
- alignOffset = 0,
- ...props
-}: NavigationMenuPrimitive.Positioner.Props) {
- return (
-
-
-
-
-
-
-
- )
-}
-
-function NavigationMenuLink({
- className,
- ...props
-}: NavigationMenuPrimitive.Link.Props) {
- return (
-
- )
-}
-
-function NavigationMenuIndicator({
- className,
- ...props
-}: React.ComponentPropsWithRef) {
- return (
-
-
-
- )
-}
-
-export {
- NavigationMenu,
- NavigationMenuContent,
- NavigationMenuIndicator,
- NavigationMenuItem,
- NavigationMenuLink,
- NavigationMenuList,
- NavigationMenuTrigger,
- navigationMenuTriggerStyle,
- NavigationMenuPositioner,
-}
diff --git a/packages/ui/components/ui/pagination.tsx b/packages/ui/components/ui/pagination.tsx
deleted file mode 100644
index a3d7a085e..000000000
--- a/packages/ui/components/ui/pagination.tsx
+++ /dev/null
@@ -1,133 +0,0 @@
-import * as React from "react"
-import { useTranslation } from "react-i18next"
-
-import { cn } from "@multica/ui/lib/utils"
-import { Button } from "@multica/ui/components/ui/button"
-import { ChevronLeftIcon, ChevronRightIcon, MoreHorizontalIcon } from "lucide-react"
-
-function Pagination({ className, ...props }: React.ComponentProps<"nav">) {
- return (
-
- )
-}
-
-function PaginationContent({
- className,
- ...props
-}: React.ComponentProps<"ul">) {
- return (
-
- )
-}
-
-function PaginationItem({ ...props }: React.ComponentProps<"li">) {
- return
-}
-
-type PaginationLinkProps = {
- isActive?: boolean
-} & Pick, "size"> &
- React.ComponentProps<"a">
-
-function PaginationLink({
- className,
- isActive,
- size = "icon",
- ...props
-}: PaginationLinkProps) {
- return (
-
- }
- />
- )
-}
-
-function PaginationPrevious({
- className,
- text = "Previous",
- ...props
-}: React.ComponentProps & { text?: string }) {
- const { t } = useTranslation("ui")
- return (
- $.pagination_previous)}
- size="default"
- className={cn("pl-1.5!", className)}
- {...props}
- >
-
- {text}
-
- )
-}
-
-function PaginationNext({
- className,
- text = "Next",
- ...props
-}: React.ComponentProps & { text?: string }) {
- const { t } = useTranslation("ui")
- return (
- $.pagination_next)}
- size="default"
- className={cn("pr-1.5!", className)}
- {...props}
- >
- {text}
-
-
- )
-}
-
-function PaginationEllipsis({
- className,
- ...props
-}: React.ComponentProps<"span">) {
- return (
-
-
- More pages
-
- )
-}
-
-export {
- Pagination,
- PaginationContent,
- PaginationEllipsis,
- PaginationItem,
- PaginationLink,
- PaginationNext,
- PaginationPrevious,
-}
diff --git a/packages/ui/components/ui/radio-group.tsx b/packages/ui/components/ui/radio-group.tsx
deleted file mode 100644
index fbf818dad..000000000
--- a/packages/ui/components/ui/radio-group.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-"use client"
-
-import { Radio as RadioPrimitive } from "@base-ui/react/radio"
-import { RadioGroup as RadioGroupPrimitive } from "@base-ui/react/radio-group"
-
-import { cn } from "@multica/ui/lib/utils"
-
-function RadioGroup({ className, ...props }: RadioGroupPrimitive.Props) {
- return (
-
- )
-}
-
-function RadioGroupItem({ className, ...props }: RadioPrimitive.Root.Props) {
- return (
-
-
-
-
-
- )
-}
-
-export { RadioGroup, RadioGroupItem }
diff --git a/packages/ui/components/ui/scroll-area.tsx b/packages/ui/components/ui/scroll-area.tsx
deleted file mode 100644
index 54d676b87..000000000
--- a/packages/ui/components/ui/scroll-area.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-"use client"
-
-import { ScrollArea as ScrollAreaPrimitive } from "@base-ui/react/scroll-area"
-
-import { cn } from "@multica/ui/lib/utils"
-
-function ScrollArea({
- className,
- children,
- ...props
-}: ScrollAreaPrimitive.Root.Props) {
- return (
-
-
- {children}
-
-
-
-
- )
-}
-
-function ScrollBar({
- className,
- orientation = "vertical",
- ...props
-}: ScrollAreaPrimitive.Scrollbar.Props) {
- return (
-
-
-
- )
-}
-
-export { ScrollArea, ScrollBar }
diff --git a/packages/ui/components/ui/toggle-group.tsx b/packages/ui/components/ui/toggle-group.tsx
deleted file mode 100644
index 33433c25d..000000000
--- a/packages/ui/components/ui/toggle-group.tsx
+++ /dev/null
@@ -1,89 +0,0 @@
-"use client"
-
-import * as React from "react"
-import { Toggle as TogglePrimitive } from "@base-ui/react/toggle"
-import { ToggleGroup as ToggleGroupPrimitive } from "@base-ui/react/toggle-group"
-import { type VariantProps } from "class-variance-authority"
-
-import { cn } from "@multica/ui/lib/utils"
-import { toggleVariants } from "@multica/ui/components/ui/toggle"
-
-const ToggleGroupContext = React.createContext<
- VariantProps & {
- spacing?: number
- orientation?: "horizontal" | "vertical"
- }
->({
- size: "default",
- variant: "default",
- spacing: 0,
- orientation: "horizontal",
-})
-
-function ToggleGroup({
- className,
- variant,
- size,
- spacing = 0,
- orientation = "horizontal",
- children,
- ...props
-}: ToggleGroupPrimitive.Props &
- VariantProps & {
- spacing?: number
- orientation?: "horizontal" | "vertical"
- }) {
- return (
-
-
- {children}
-
-
- )
-}
-
-function ToggleGroupItem({
- className,
- children,
- variant = "default",
- size = "default",
- ...props
-}: TogglePrimitive.Props & VariantProps) {
- const context = React.use(ToggleGroupContext)
-
- return (
-
- {children}
-
- )
-}
-
-export { ToggleGroup, ToggleGroupItem }
diff --git a/packages/ui/hooks/use-auto-scroll.ts b/packages/ui/hooks/use-auto-scroll.ts
deleted file mode 100644
index 74b23a96e..000000000
--- a/packages/ui/hooks/use-auto-scroll.ts
+++ /dev/null
@@ -1,80 +0,0 @@
-import { type RefObject, useEffect, useRef, useCallback } from "react"
-
-/**
- * Auto-scrolls a scroll container to the bottom when its inner content grows,
- * as long as the user hasn't scrolled up to read older content.
- *
- * Returns a `lockRef` that can be set to `true` to temporarily suppress
- * auto-scroll (e.g. during history prepend operations).
- */
-export function useAutoScroll(ref: RefObject) {
- const stickRef = useRef(true)
- const lockRef = useRef(false)
- // Re-running the initial scroll-to-bottom on every effect mount would
- // overwrite the scroll position any time React tears the effect down and
- // brings it back — e.g. when the host tab cycles through `` and back. We want the jump only on a real first mount.
- const didInitialScrollRef = useRef(false)
-
- useEffect(() => {
- const el = ref.current
- if (!el) return
-
- const scrollToBottom = () => {
- el.scrollTo({ top: el.scrollHeight })
- }
-
- const onScroll = () => {
- const { scrollTop, scrollHeight, clientHeight } = el
- stickRef.current = scrollHeight - scrollTop - clientHeight < 50
- }
-
- const onContentChange = () => {
- if (lockRef.current) return
- if (stickRef.current) {
- scrollToBottom()
- }
- }
-
- // Watch child element resizes (content growth, image loads, streaming)
- const ro = new ResizeObserver(onContentChange)
- for (const child of el.children) {
- ro.observe(child)
- }
-
- // Watch for added/removed child nodes (new messages rendered)
- const mo = new MutationObserver((mutations) => {
- // Also observe newly added elements
- for (const mutation of mutations) {
- for (const node of mutation.addedNodes) {
- if (node instanceof Element) {
- ro.observe(node)
- }
- }
- }
- onContentChange()
- })
- mo.observe(el, { childList: true, subtree: true })
-
- el.addEventListener("scroll", onScroll, { passive: true })
-
- if (!didInitialScrollRef.current) {
- didInitialScrollRef.current = true
- scrollToBottom()
- }
-
- return () => {
- el.removeEventListener("scroll", onScroll)
- ro.disconnect()
- mo.disconnect()
- }
- }, [ref])
-
- /** Temporarily suppress auto-scroll during prepend operations */
- const suppressAutoScroll = useCallback(() => {
- lockRef.current = true
- return () => { lockRef.current = false }
- }, [])
-
- return { suppressAutoScroll }
-}
diff --git a/packages/ui/package.json b/packages/ui/package.json
index 164d06a40..788a404ee 100644
--- a/packages/ui/package.json
+++ b/packages/ui/package.json
@@ -35,14 +35,11 @@
"class-variance-authority": "catalog:",
"clsx": "catalog:",
"cmdk": "^1.1.1",
- "date-fns": "^4.1.0",
- "embla-carousel-react": "^8.6.0",
"emoji-mart": "^5.6.0",
"input-otp": "^1.4.2",
"linkify-it": "^5.0.0",
"katex": "catalog:",
"lucide-react": "catalog:",
- "motion": "^12.38.0",
"next-themes": "^0.4.6",
"react-day-picker": "^9.14.0",
"react-markdown": "^10.1.0",
@@ -57,9 +54,7 @@
"shiki": "^3.21.0",
"sonner": "^2.0.7",
"tailwind-merge": "catalog:",
- "tw-animate-css": "^1.4.0",
- "unicode-animations": "catalog:",
- "vaul": "^1.1.2"
+ "unicode-animations": "catalog:"
},
"peerDependencies": {
"i18next": "catalog:",
diff --git a/packages/ui/types/i18next.ts b/packages/ui/types/i18next.ts
index 7077105f3..e2957eaa9 100644
--- a/packages/ui/types/i18next.ts
+++ b/packages/ui/types/i18next.ts
@@ -19,8 +19,6 @@ declare global {
ui: {
attach_file: string;
toggle_sidebar: string;
- pagination_previous: string;
- pagination_next: string;
copy_code: string;
plain_text: string;
};
diff --git a/packages/views/issues/components/issue-hover-card.tsx b/packages/views/issues/components/issue-hover-card.tsx
index 550880ce2..8d7c5f1ec 100644
--- a/packages/views/issues/components/issue-hover-card.tsx
+++ b/packages/views/issues/components/issue-hover-card.tsx
@@ -43,11 +43,10 @@ interface IssueHoverCardProps {
* The inline chip shows status, identifier, and as much title as fits inside
* its `min(18rem, 100%)` cap — so a long title arrives truncated. The card
* carries what the chip cannot: the full untruncated title, priority, a
- * description snippet, the assignee, and sub-issue progress. Member and agent
- * mentions already preview this way via MentionHoverCard
- * (packages/ui/components/common/mention-hover-card.tsx); this is the issue
- * equivalent, and lives here rather than in packages/ui because it reads
- * workspace queries.
+ * description snippet, the assignee, and sub-issue progress. Issue mentions are
+ * the only kind with a hover preview — member and agent mentions render as a
+ * plain `.mention` span in rich-content.tsx. This lives here rather than in
+ * packages/ui because it reads workspace queries.
*
* Every query lives in IssueHoverCardBody rather than here on purpose: Base UI
* mounts the popup only while the card is open, so this component adds no
diff --git a/packages/views/locales/en/ui.json b/packages/views/locales/en/ui.json
index 69d67e3a8..2652f7cab 100644
--- a/packages/views/locales/en/ui.json
+++ b/packages/views/locales/en/ui.json
@@ -1,8 +1,6 @@
{
"attach_file": "Attach file",
"toggle_sidebar": "Toggle Sidebar",
- "pagination_previous": "Go to previous page",
- "pagination_next": "Go to next page",
"copy_code": "Copy code",
"plain_text": "plain text"
}
diff --git a/packages/views/locales/ja/ui.json b/packages/views/locales/ja/ui.json
index 80780c748..1973315a0 100644
--- a/packages/views/locales/ja/ui.json
+++ b/packages/views/locales/ja/ui.json
@@ -1,8 +1,6 @@
{
"attach_file": "ファイルを添付",
"toggle_sidebar": "サイドバーの開閉",
- "pagination_previous": "前のページへ移動",
- "pagination_next": "次のページへ移動",
"copy_code": "コードをコピー",
"plain_text": "プレーンテキスト"
}
diff --git a/packages/views/locales/ko/ui.json b/packages/views/locales/ko/ui.json
index 05f7d65ad..3bfdfa193 100644
--- a/packages/views/locales/ko/ui.json
+++ b/packages/views/locales/ko/ui.json
@@ -1,8 +1,6 @@
{
"attach_file": "파일 첨부",
"toggle_sidebar": "사이드바 열기/닫기",
- "pagination_previous": "이전 페이지로 이동",
- "pagination_next": "다음 페이지로 이동",
"copy_code": "코드 복사",
"plain_text": "일반 텍스트"
}
diff --git a/packages/views/locales/zh-Hans/ui.json b/packages/views/locales/zh-Hans/ui.json
index 9f6ef14df..24470eb41 100644
--- a/packages/views/locales/zh-Hans/ui.json
+++ b/packages/views/locales/zh-Hans/ui.json
@@ -1,8 +1,6 @@
{
"attach_file": "添加附件",
"toggle_sidebar": "切换侧边栏",
- "pagination_previous": "上一页",
- "pagination_next": "下一页",
"copy_code": "复制代码",
"plain_text": "纯文本"
}
diff --git a/packages/views/package.json b/packages/views/package.json
index 6962a3ff9..4fbad0b43 100644
--- a/packages/views/package.json
+++ b/packages/views/package.json
@@ -126,6 +126,7 @@
"@testing-library/jest-dom": "catalog:",
"@testing-library/react": "catalog:",
"@testing-library/user-event": "catalog:",
+ "@types/hast": "^3.0.4",
"@types/mdast": "^4.0.4",
"@types/react": "catalog:",
"@types/react-dom": "catalog:",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index d91b9ac4f..48141905e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -129,6 +129,9 @@ importers:
'@types/pg':
specifier: ^8.20.0
version: 8.20.0
+ knip:
+ specifier: ^6.32.2
+ version: 6.32.2
pg:
specifier: ^8.20.0
version: 8.20.0
@@ -225,7 +228,7 @@ importers:
version: link:../../packages/tsconfig
'@tailwindcss/vite':
specifier: ^4
- version: 4.2.2(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@2.6.1)(terser@5.47.1)(yaml@2.9.0))
+ version: 4.2.2(vite@8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@2.7.0)(terser@5.47.1)(yaml@2.9.0))
'@testing-library/jest-dom':
specifier: 'catalog:'
version: 6.9.1
@@ -243,7 +246,7 @@ importers:
version: 19.2.3(@types/react@19.2.14)
'@vitejs/plugin-react':
specifier: ^5.1.1
- version: 5.2.0(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@2.6.1)(terser@5.47.1)(yaml@2.9.0))
+ version: 5.2.0(vite@8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@2.7.0)(terser@5.47.1)(yaml@2.9.0))
electron:
specifier: ^39.2.6
version: 39.8.7
@@ -252,7 +255,7 @@ importers:
version: 26.8.1(electron-builder-squirrel-windows@26.8.1)
electron-vite:
specifier: ^5.0.0
- version: 5.0.0(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@2.6.1)(terser@5.47.1)(yaml@2.9.0))
+ version: 5.0.0(vite@8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@2.7.0)(terser@5.47.1)(yaml@2.9.0))
globals:
specifier: ^16.0.0
version: 16.5.0
@@ -267,7 +270,7 @@ importers:
version: 5.9.3
vitest:
specifier: 'catalog:'
- version: 4.1.0(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(jsdom@29.0.1(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@2.6.1)(terser@5.47.1)(yaml@2.9.0))
+ version: 4.1.0(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(jsdom@29.0.1(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@2.7.0)(terser@5.47.1)(yaml@2.9.0))
apps/docs:
dependencies:
@@ -279,7 +282,7 @@ importers:
version: 15.8.5(@types/react@19.2.14)(lucide-react@1.0.1(react@19.2.3))(next@15.5.18(@opentelemetry/api@1.9.1)(@playwright/test@1.58.2)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react-router@7.14.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)
fumadocs-mdx:
specifier: ^12.0.3
- version: 12.0.3(fumadocs-core@15.8.5(@types/react@19.2.14)(lucide-react@1.0.1(react@19.2.3))(next@15.5.18(@opentelemetry/api@1.9.1)(@playwright/test@1.58.2)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react-router@7.14.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3))(next@15.5.18(@opentelemetry/api@1.9.1)(@playwright/test@1.58.2)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@2.6.1)(terser@5.47.1)(yaml@2.9.0))
+ version: 12.0.3(fumadocs-core@15.8.5(@types/react@19.2.14)(lucide-react@1.0.1(react@19.2.3))(next@15.5.18(@opentelemetry/api@1.9.1)(@playwright/test@1.58.2)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react-router@7.14.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3))(next@15.5.18(@opentelemetry/api@1.9.1)(@playwright/test@1.58.2)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)(vite@8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@2.7.0)(terser@5.47.1)(yaml@2.9.0))
fumadocs-ui:
specifier: ^15.5.2
version: 15.8.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(lucide-react@1.0.1(react@19.2.3))(next@15.5.18(@opentelemetry/api@1.9.1)(@playwright/test@1.58.2)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react-router@7.14.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)(tailwindcss@4.2.2)
@@ -319,7 +322,7 @@ importers:
version: 5.9.3
vitest:
specifier: 'catalog:'
- version: 4.1.0(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(jsdom@29.0.1(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@2.6.1)(terser@5.47.1)(yaml@2.9.0))
+ version: 4.1.0(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(jsdom@29.0.1(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@2.7.0)(terser@5.47.1)(yaml@2.9.0))
apps/mobile:
dependencies:
@@ -524,28 +527,10 @@ importers:
version: 5.9.3
vitest:
specifier: 'catalog:'
- version: 4.1.0(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(jsdom@29.0.1(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@1.21.7)(terser@5.47.1)(yaml@2.9.0))
+ version: 4.1.0(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(jsdom@29.0.1(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@1.21.7)(terser@5.47.1)(yaml@2.9.0))
apps/web:
dependencies:
- '@base-ui/react':
- specifier: ^1.3.0
- version: 1.3.0(@types/react@19.2.14)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- '@dnd-kit/core':
- specifier: ^6.3.1
- version: 6.3.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- '@dnd-kit/sortable':
- specifier: ^10.0.0
- version: 10.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)
- '@dnd-kit/utilities':
- specifier: ^3.2.2
- version: 3.2.2(react@19.2.3)
- '@emoji-mart/data':
- specifier: ^1.2.1
- version: 1.2.1
- '@floating-ui/dom':
- specifier: ^1.7.6
- version: 1.7.6
'@multica/core':
specifier: workspace:*
version: link:../../packages/core
@@ -558,150 +543,36 @@ importers:
'@tanstack/react-query':
specifier: 'catalog:'
version: 5.96.2(react@19.2.3)
- '@tanstack/react-query-devtools':
- specifier: ^5.96.2
- version: 5.96.2(@tanstack/react-query@5.96.2(react@19.2.3))(react@19.2.3)
- '@tiptap/extension-code-block-lowlight':
- specifier: 3.27.1
- version: 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/extension-code-block@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)(highlight.js@11.11.1)(lowlight@3.3.0)
- '@tiptap/extension-image':
- specifier: 3.27.1
- version: 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))
- '@tiptap/extension-link':
- specifier: 3.27.1
- version: 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)
- '@tiptap/extension-mention':
- specifier: 3.27.1
- version: 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)(@tiptap/suggestion@3.27.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1))
- '@tiptap/extension-placeholder':
- specifier: 3.27.1
- version: 3.27.1(@tiptap/extensions@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1))
- '@tiptap/extension-table':
- specifier: 3.27.1
- version: 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)
- '@tiptap/extension-table-cell':
- specifier: 3.27.1
- version: 3.27.1(@tiptap/extension-table@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1))
- '@tiptap/extension-table-header':
- specifier: 3.27.1
- version: 3.27.1(@tiptap/extension-table@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1))
- '@tiptap/extension-table-row':
- specifier: 3.27.1
- version: 3.27.1(@tiptap/extension-table@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1))
- '@tiptap/extension-typography':
- specifier: 3.27.1
- version: 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))
- '@tiptap/markdown':
- specifier: 3.27.1
- version: 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)
- '@tiptap/pm':
- specifier: 3.27.1
- version: 3.27.1
- '@tiptap/react':
- specifier: 3.27.1
- version: 3.27.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- '@tiptap/starter-kit':
- specifier: 3.27.1
- version: 3.27.1
- '@tiptap/suggestion':
- specifier: 3.27.1
- version: 3.27.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)
- '@types/linkify-it':
- specifier: ^5.0.0
- version: 5.0.0
- class-variance-authority:
- specifier: ^0.7.1
- version: 0.7.1
- clsx:
- specifier: ^2.1.1
- version: 2.1.1
- cmdk:
- specifier: ^1.1.1
- version: 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- date-fns:
- specifier: ^4.1.0
- version: 4.1.0
dotenv:
specifier: ^17.4.1
version: 17.4.1
- embla-carousel-react:
- specifier: ^8.6.0
- version: 8.6.0(react@19.2.3)
- emoji-mart:
- specifier: ^5.6.0
- version: 5.6.0
fumadocs-core:
specifier: ^15.5.2
version: 15.8.5(@types/react@19.2.14)(lucide-react@1.0.1(react@19.2.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.58.2)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react-router@7.14.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)
fumadocs-mdx:
specifier: ^12.0.3
version: 12.0.3(fumadocs-core@15.8.5(@types/react@19.2.14)(lucide-react@1.0.1(react@19.2.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.58.2)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react-router@7.14.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3))(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.58.2)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)
- input-otp:
- specifier: ^1.4.2
- version: 1.4.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- linkify-it:
- specifier: ^5.0.0
- version: 5.0.0
- lowlight:
- specifier: ^3.3.0
- version: 3.3.0
lucide-react:
specifier: 'catalog:'
version: 1.0.1(react@19.2.3)
next:
specifier: ^16.2.5
version: 16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.58.2)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- next-themes:
- specifier: ^0.4.6
- version: 0.4.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
react:
specifier: 'catalog:'
version: 19.2.3
- react-day-picker:
- specifier: ^9.14.0
- version: 9.14.0(react@19.2.3)
react-dom:
specifier: 'catalog:'
version: 19.2.3(react@19.2.3)
- react-markdown:
- specifier: ^10.1.0
- version: 10.1.0(@types/react@19.2.14)(react@19.2.3)
- react-resizable-panels:
- specifier: ^4.7.5
- version: 4.7.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- recharts:
- specifier: 3.8.0
- version: 3.8.0(@types/react@19.2.14)(react-dom@19.2.3(react@19.2.3))(react-is@19.2.6)(react@19.2.3)(redux@5.0.1)
- rehype-raw:
- specifier: ^7.0.0
- version: 7.0.0
- remark-gfm:
- specifier: ^4.0.1
- version: 4.0.1
shadcn:
specifier: ^4.1.0
version: 4.1.0(@types/node@25.5.0)(typescript@5.9.3)
- shiki:
- specifier: ^3.21.0
- version: 3.23.0
- sonner:
- specifier: ^2.0.7
- version: 2.0.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- tailwind-merge:
- specifier: ^3.5.0
- version: 3.5.0
tw-animate-css:
specifier: ^1.4.0
version: 1.4.0
- vaul:
- specifier: ^1.1.2
- version: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
zod:
specifier: 'catalog:'
version: 4.3.6
- zustand:
- specifier: 'catalog:'
- version: 5.0.12(@types/react@19.2.14)(immer@11.1.4)(react@19.2.3)(use-sync-external-store@1.6.0(react@19.2.3))
devDependencies:
'@multica/eslint-config':
specifier: workspace:*
@@ -726,7 +597,7 @@ importers:
version: 19.2.3(@types/react@19.2.14)
'@vitejs/plugin-react':
specifier: 'catalog:'
- version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@2.6.1)(terser@5.47.1)(yaml@2.9.0))
+ version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@2.7.0)(terser@5.47.1)(yaml@2.9.0))
jsdom:
specifier: 'catalog:'
version: 29.0.1(@noble/hashes@1.8.0)
@@ -741,7 +612,7 @@ importers:
version: 5.9.3
vitest:
specifier: 'catalog:'
- version: 4.1.0(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(jsdom@29.0.1(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@1.21.7)(terser@5.47.1)(yaml@2.9.0))
+ version: 4.1.0(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(jsdom@29.0.1(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@1.21.7)(terser@5.47.1)(yaml@2.9.0))
packages/core:
dependencies:
@@ -751,9 +622,6 @@ importers:
'@tanstack/react-query':
specifier: 'catalog:'
version: 5.96.2(react@19.2.3)
- '@tanstack/react-query-devtools':
- specifier: ^5.96.2
- version: 5.96.2(@tanstack/react-query@5.96.2(react@19.2.3))(react@19.2.3)
i18next:
specifier: 'catalog:'
version: 26.0.8(typescript@5.9.3)
@@ -799,7 +667,7 @@ importers:
version: 5.9.3
vitest:
specifier: 'catalog:'
- version: 4.1.0(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(jsdom@29.0.1(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@2.6.1)(terser@5.47.1)(yaml@2.9.0))
+ version: 4.1.0(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(jsdom@29.0.1(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@2.7.0)(terser@5.47.1)(yaml@2.9.0))
packages/eslint-config:
dependencies:
@@ -811,19 +679,19 @@ importers:
version: 16.2.3
eslint:
specifier: ^9.0.0
- version: 9.39.4(jiti@2.6.1)
+ version: 9.39.4(jiti@2.7.0)
eslint-plugin-import-x:
specifier: ^4.12.0
- version: 4.16.2(@typescript-eslint/utils@8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.6.1))
+ version: 4.16.2(@typescript-eslint/utils@8.58.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0))
eslint-plugin-react:
specifier: ^7.37.0
- version: 7.37.5(eslint@9.39.4(jiti@2.6.1))
+ version: 7.37.5(eslint@9.39.4(jiti@2.7.0))
eslint-plugin-react-hooks:
specifier: ^5.2.0
- version: 5.2.0(eslint@9.39.4(jiti@2.6.1))
+ version: 5.2.0(eslint@9.39.4(jiti@2.7.0))
typescript-eslint:
specifier: ^8.35.0
- version: 8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)
+ version: 8.58.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)
packages/tsconfig: {}
@@ -853,12 +721,6 @@ importers:
cmdk:
specifier: ^1.1.1
version: 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- date-fns:
- specifier: ^4.1.0
- version: 4.1.0
- embla-carousel-react:
- specifier: ^8.6.0
- version: 8.6.0(react@19.2.3)
emoji-mart:
specifier: ^5.6.0
version: 5.6.0
@@ -877,9 +739,6 @@ importers:
lucide-react:
specifier: 'catalog:'
version: 1.0.1(react@19.2.3)
- motion:
- specifier: ^12.38.0
- version: 12.38.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
next-themes:
specifier: ^0.4.6
version: 0.4.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
@@ -931,15 +790,9 @@ importers:
tailwind-merge:
specifier: 'catalog:'
version: 3.5.0
- tw-animate-css:
- specifier: ^1.4.0
- version: 1.4.0
unicode-animations:
specifier: 'catalog:'
version: 1.0.3
- vaul:
- specifier: ^1.1.2
- version: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
devDependencies:
'@multica/eslint-config':
specifier: workspace:*
@@ -1161,6 +1014,9 @@ importers:
'@testing-library/user-event':
specifier: 'catalog:'
version: 14.6.1(@testing-library/dom@10.4.1)
+ '@types/hast':
+ specifier: ^3.0.4
+ version: 3.0.4
'@types/mdast':
specifier: ^4.0.4
version: 4.0.4
@@ -1172,7 +1028,7 @@ importers:
version: 19.2.3(@types/react@19.2.14)
'@vitejs/plugin-react':
specifier: 'catalog:'
- version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@2.6.1)(terser@5.47.1)(yaml@2.9.0))
+ version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@2.7.0)(terser@5.47.1)(yaml@2.9.0))
eslint-plugin-i18next:
specifier: 'catalog:'
version: 6.1.4
@@ -1184,7 +1040,7 @@ importers:
version: 5.9.3
vitest:
specifier: 'catalog:'
- version: 4.1.0(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(jsdom@29.0.1(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@2.6.1)(terser@5.47.1)(yaml@2.9.0))
+ version: 4.1.0(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(jsdom@29.0.1(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@2.7.0)(terser@5.47.1)(yaml@2.9.0))
packages:
@@ -1924,12 +1780,21 @@ packages:
'@emnapi/core@1.10.0':
resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==}
+ '@emnapi/core@1.11.2':
+ resolution: {integrity: sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==}
+
'@emnapi/runtime@1.10.0':
resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==}
+ '@emnapi/runtime@1.11.2':
+ resolution: {integrity: sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==}
+
'@emnapi/wasi-threads@1.2.1':
resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==}
+ '@emnapi/wasi-threads@1.2.2':
+ resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==}
+
'@emoji-mart/data@1.2.1':
resolution: {integrity: sha512-no2pQMWiBy6gpBEiqGeU77/bFejDqUTRY7KX+0+iur13op3bqUsXdnwoZs6Xb1zbv0gAj5VvS1PWoUUckSr5Dw==}
@@ -2657,6 +2522,13 @@ packages:
'@emnapi/core': ^1.7.1
'@emnapi/runtime': ^1.7.1
+ '@napi-rs/wasm-runtime@1.2.3':
+ resolution: {integrity: sha512-UMduMbqO5s5zF2NkNacMT/yK5Y5QiKvWr2+50bzIIxFDwVJ2h49b+oyjaCGPhJxd2/gC2x39EHv/gHVuu36x2Q==}
+ engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0}
+ peerDependencies:
+ '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.4
+ '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.4
+
'@next/env@15.5.18':
resolution: {integrity: sha512-hAV85Ckd9QR6RvH04MEKwsfLTksvFpO47j9xwtoIuvuPnlwecpSi+uZTtm8HirVbtlI2Fnz//xpcSTjFdyJk+g==}
@@ -2897,9 +2769,237 @@ packages:
resolution: {integrity: sha512-a61ljmRVVyG5MC/698C8/FfFDw5a8LOIvyOLW5fztgUXqUpc1jOfQzOitSCbge657OgXXThmY3Tk8fpiDb4UcA==}
engines: {node: '>= 20.0.0'}
+ '@oxc-parser/binding-android-arm-eabi@0.143.0':
+ resolution: {integrity: sha512-n9uozULWflPqBtdmI8lAabLqGKNgLVNN0ZH8HfgCwpKGNtzRzauB76jTiW/3YLkcA7N1zskpi9GdVnZuu1SAvg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm]
+ os: [android]
+
+ '@oxc-parser/binding-android-arm64@0.143.0':
+ resolution: {integrity: sha512-9BbdjHETk6O3zH/DDid9IgBtF0GlpLabNKN231uraXpRDSfY+iiZxTP5bk1Z63GBownVdhdINFIeddmMz4MzpQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [android]
+
+ '@oxc-parser/binding-darwin-arm64@0.143.0':
+ resolution: {integrity: sha512-gh+6ecoHUy4/sUcolBl/1qPXKBbYNxFY0Pk0ujgQvINTMSftJY7o4yb8gOkDJPeZeB8+a+u7xTe6umoP8N5HFA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@oxc-parser/binding-darwin-x64@0.143.0':
+ resolution: {integrity: sha512-qd1hl2d+lXgHv/VQ/M9qm8TrMC5T4RqDBwtOnl+1D0QMjwcz+8AaB4JSg8STgeag0GP6a6L74XEGAsrTSJWNzQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [darwin]
+
+ '@oxc-parser/binding-freebsd-x64@0.143.0':
+ resolution: {integrity: sha512-M5XXcNa7aOqLPKTR41msfghKu2yQ4xWvCm11/gwU0JzOzHNk5sgW//rVEjJ+LO48+VDAMzXTSzurUVxIDKwozw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@oxc-parser/binding-linux-arm-gnueabihf@0.143.0':
+ resolution: {integrity: sha512-T/GXusuOkPNQhCQCSBbcU/N8j0rAypuDBl1IyFK+lyYT594XsVz80clPC/OtbSSpBGyJxj8uYEfctxVuxVYoww==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm]
+ os: [linux]
+
+ '@oxc-parser/binding-linux-arm-musleabihf@0.143.0':
+ resolution: {integrity: sha512-oKu4RcBlXSqo3OC62dp6YTnQaZIurNDpCX3BnAM3+bJxt7s8J2TJKMnC0UYer1qhlRaDCg6wkTaTw+2IlsZ12w==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm]
+ os: [linux]
+
+ '@oxc-parser/binding-linux-arm64-gnu@0.143.0':
+ resolution: {integrity: sha512-WJBbD186AZmMGaSIhlktC+rPl8L3peCTXAh88Ih9uEvK0en2mPojGyCGYiL6mHtV1RPV3JyfJW5t6n5hh0lXhA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@oxc-parser/binding-linux-arm64-musl@0.143.0':
+ resolution: {integrity: sha512-t1AcYOwEzgceadT4v5e+vaCCb0AncCA3v5AyzfBAz/tMq11qzVccXKzNHtkWdjBsgvTKwRkaUF3QvT4kot8vcQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@oxc-parser/binding-linux-ppc64-gnu@0.143.0':
+ resolution: {integrity: sha512-RsnO/NoD8376LMJq8JS8TwI0ieNaFRTuNe2GVJntQg6gwZNMENZsEbknHdVwjpOmxdGLGodcwaGSbAeRr5Bgjw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [ppc64]
+ os: [linux]
+ libc: [glibc]
+
+ '@oxc-parser/binding-linux-riscv64-gnu@0.143.0':
+ resolution: {integrity: sha512-48fSVfR9TZi5CASZFyv0VC6z6BCoeihFsX031mAD/oSH7d9PYsPgIqza7d9mjP7Z2KTEpTFyH6SIu0Ui6R1vdg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [riscv64]
+ os: [linux]
+ libc: [glibc]
+
+ '@oxc-parser/binding-linux-riscv64-musl@0.143.0':
+ resolution: {integrity: sha512-T8CpdD+SfE01DnIOD4HpVxu0ZJOfMJ/VhCvikKfaXAxkZ+9veyLM/D2hpi7Y2hFUyPmVQO3FNZHmYzV/WlVR4g==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [riscv64]
+ os: [linux]
+ libc: [musl]
+
+ '@oxc-parser/binding-linux-s390x-gnu@0.143.0':
+ resolution: {integrity: sha512-QLdeMsCcacenPEFsfxnBUDF1y6opyz5+fmOz9bfD5Y7fiGCMupUCuB3KTPQhNwshIG1P9fPqar9MHxuBDd4bwQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [s390x]
+ os: [linux]
+ libc: [glibc]
+
+ '@oxc-parser/binding-linux-x64-gnu@0.143.0':
+ resolution: {integrity: sha512-659ujfqLy6k7cuH3sbzhd8b+ztSq+i6E2E9pG78Q0BmHjAExfGIdgc8cGgMdwAozDXeZFHkJ+LXYJdWsaGdgyw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@oxc-parser/binding-linux-x64-musl@0.143.0':
+ resolution: {integrity: sha512-/Mw/9j4TfZcnKphPrzOE6t4MMknXadcAAuVUlDRTF/ETWB5xOgQvOJV2Mh9We/bWxZdoxaGAdc+hy4GuYwQ2yQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@oxc-parser/binding-openharmony-arm64@0.143.0':
+ resolution: {integrity: sha512-8rIKWR2BFuifbIK/1XB9wTaSdtuJ25dlE7ZQYDnEwj/2xH2vHsxnvIjHT3ZjSVuLLwGGlSslIG/fbOJ8TV8rTw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@oxc-parser/binding-win32-arm64-msvc@0.143.0':
+ resolution: {integrity: sha512-5U9kQYMfRRI6Zq7KDxgbIP0RMnKrfn3gLepRMgJuRkPSUALTiRCk9d/uyhb4lGDjUdzwK7mBkKqhLgzBPCmLpQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [win32]
+
+ '@oxc-parser/binding-win32-ia32-msvc@0.143.0':
+ resolution: {integrity: sha512-25P7AaHk4R88Yv2XH4gToDVmh0cOu+bEURQU10CRrmvgabfRArSGAP5osmwUKeSUHj0VS50upbpbRWWW/m7mHA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [ia32]
+ os: [win32]
+
+ '@oxc-parser/binding-win32-x64-msvc@0.143.0':
+ resolution: {integrity: sha512-ORMh3JE1s6V7ySicdRK7vgaDQnn5o+UHg9ct989PlWHbel8O9ARrmWXM6kZjrBMtNucxNayQ8g69G0VfWzhANw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [win32]
+
'@oxc-project/types@0.120.0':
resolution: {integrity: sha512-k1YNu55DuvAip/MGE1FTsIuU3FUCn6v/ujG9V7Nq5Df/kX2CWb13hhwD0lmJGMGqE+bE1MXvv9SZVnMzEXlWcg==}
+ '@oxc-project/types@0.143.0':
+ resolution: {integrity: sha512-u6JZdLBTLotrNC9Vd6vPssINdzcCzleKAH6EJKImQb7GtYvX5keN2dxkoK44stCc4tffE6QQRtZTXVSzsLUlWA==}
+
+ '@oxc-resolver/binding-android-arm-eabi@11.24.2':
+ resolution: {integrity: sha512-y09e0L0SRI2OA2tUIrjBgoV3eH5hvUKXNkJqXmNo5V2WxIjyC7I7aJfRLMEVpA8yi95f90gFDvO0VMgrDw+vwA==}
+ cpu: [arm]
+ os: [android]
+
+ '@oxc-resolver/binding-android-arm64@11.24.2':
+ resolution: {integrity: sha512-cl4icWaZFnLdg8m6qtnh5rBMuGbxc/ptStFHLeCNwr+2cZjkjNwQu/jYRS0CHlnPecOJMpuS5M6/BH+0J/YkEg==}
+ cpu: [arm64]
+ os: [android]
+
+ '@oxc-resolver/binding-darwin-arm64@11.24.2':
+ resolution: {integrity: sha512-At29QEMF6HajbQvgY8K6OXnHD1x9rad74xBEfmCB6ZqCGsdq75aK7tOYcTbOanMy8qdIBrfL3SMr3p/lfSlb9w==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@oxc-resolver/binding-darwin-x64@11.24.2':
+ resolution: {integrity: sha512-A5Kqr1EUj4oIL5CF4WRssq/o5P0Y11cwoFouMRmQ7YnC/A8V93nv1nb7aSU8HwcgmXropjLNkVTl4MN87cu28Q==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@oxc-resolver/binding-freebsd-x64@11.24.2':
+ resolution: {integrity: sha512-R5xkRBRRz7ceH/P5Jrc6G7FmdUdgpLYyESFAUDVTNQ9K0sGPxcp4ljiwEwEqsvNcQ4sYbMRrWcHHBCu7ksAJVw==}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@oxc-resolver/binding-linux-arm-gnueabihf@11.24.2':
+ resolution: {integrity: sha512-k/RuYL4L/R58IBn3wT5ma3Wh4k62bp1eYCFRWCmMsasUOqL+H6sW0VGFadEzKWXFFlz+2uIMoeMk9ySSZJHgbg==}
+ cpu: [arm]
+ os: [linux]
+
+ '@oxc-resolver/binding-linux-arm-musleabihf@11.24.2':
+ resolution: {integrity: sha512-bnHAak3ujYfH5pKk4NieFNbvYvernfoQDgwLddbZ3OtMYrem87/qjlA+u+aKG0oZcqSLGCful/6/CEA+aeAgaA==}
+ cpu: [arm]
+ os: [linux]
+
+ '@oxc-resolver/binding-linux-arm64-gnu@11.24.2':
+ resolution: {integrity: sha512-vDT3KHgzYp47gmtNOqL2VNhCyl5Zv643eyxm//A68J8DeUGXrvD1pZFiaT4jSfe+RInfnn1R2yVHye4enx6RnA==}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@oxc-resolver/binding-linux-arm64-musl@11.24.2':
+ resolution: {integrity: sha512-+kMlQvbzfyEYtu5FcjE4p+ttBLpKW4d/AsAsuE69BxV6V4twZJeIQZFfD8gh/wqglY0MkPSezWXQH0jBV13MUw==}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@oxc-resolver/binding-linux-ppc64-gnu@11.24.2':
+ resolution: {integrity: sha512-shjfMhmZ3gq9fv/w7bi3PnZlgOPG+2QAOFf0BJF0EgBSIGZ6PMLN2zbGEblTUYB/NKVDRyYhE2ff3dJ1QqNPkA==}
+ cpu: [ppc64]
+ os: [linux]
+ libc: [glibc]
+
+ '@oxc-resolver/binding-linux-riscv64-gnu@11.24.2':
+ resolution: {integrity: sha512-zGelwFR5oRo+b69k8Lrzun86DyUHzfKN6cnjbR9l7Z7NIRznOE/2ZvPa1IUKqAL2PzAXOdwkfVqNvO1H2RlpAw==}
+ cpu: [riscv64]
+ os: [linux]
+ libc: [glibc]
+
+ '@oxc-resolver/binding-linux-riscv64-musl@11.24.2':
+ resolution: {integrity: sha512-qxZ1SWCXJY0eyhAlP6Lmo9F2Nrtx7EkYj9oCgL8apDPCwXwCEDA2U697bbT81JIc2IrVjxO4KX6WU2N+oN9Z4w==}
+ cpu: [riscv64]
+ os: [linux]
+ libc: [musl]
+
+ '@oxc-resolver/binding-linux-s390x-gnu@11.24.2':
+ resolution: {integrity: sha512-sGCecF3cx2DFlH4t/z7ApnOnXqN48p5p5mlHDEnHTAukQa2P+qMVE4CwyWE9W+q/m3QJ7kKfGrIjax31f44oFQ==}
+ cpu: [s390x]
+ os: [linux]
+ libc: [glibc]
+
+ '@oxc-resolver/binding-linux-x64-gnu@11.24.2':
+ resolution: {integrity: sha512-k/VlMMcSzMlahb3/fENM4rTlsJ0s3fFROA0KXPBmKggqmTSaE383sl8F3KCOXPLmVsYfW6hCitMhXCEtNeZxxg==}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@oxc-resolver/binding-linux-x64-musl@11.24.2':
+ resolution: {integrity: sha512-8hbnZyNi97b/8wapYaIF9+t9GmZKBW2vunaOc3h9HGJptH7b7XpvZqOTBSm/MpTjr7H497BlgOaSfLUdhmy2bw==}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@oxc-resolver/binding-openharmony-arm64@11.24.2':
+ resolution: {integrity: sha512-MvyGik3a6pVgZ0t/kWlbmFxFLmXQJwgLsY2eYFHLpy0wGwRbfzeIGgDwQ3kXqE30z+kSXennRkCrT7TUvkptNg==}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@oxc-resolver/binding-wasm32-wasi@11.24.2':
+ resolution: {integrity: sha512-vHcssMPwO08RTvj/c0iOBz90attxyG3wQJ0dTcyEQK43LRpcdLWZlV5feBhv6Isn6ahbQIzHbCgfa81+RiML0Q==}
+ engines: {node: '>=14.0.0'}
+ cpu: [wasm32]
+
+ '@oxc-resolver/binding-win32-arm64-msvc@11.24.2':
+ resolution: {integrity: sha512-uokJqro2iBqkFvJdKQLP7d8/BUmFwESQFVmIJUQKj1Xn1a/LysJoe1vmeECLF5b3jsV8CAL5sEMJXX6SdK9Nhg==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@oxc-resolver/binding-win32-x64-msvc@11.24.2':
+ resolution: {integrity: sha512-UqGPmo56KDfLlfXFAFIrNflHT8tFxWGEivWg3Zeyp4Uy2NlKN1FGPr6/BxcLGG3+kZ6Wp14g5Uj+n71boqZfiw==}
+ cpu: [x64]
+ os: [win32]
+
'@package-json/types@0.0.12':
resolution: {integrity: sha512-uu43FGU34B5VM9mCNjXCwLaGHYjXdNincqKLaraaCW+7S2+SmiBg1Nv8bPnmschrIfZmfKNY9f3fC376MRrObw==}
@@ -3983,15 +4083,6 @@ packages:
'@tanstack/query-core@5.96.2':
resolution: {integrity: sha512-hzI6cTVh4KNRk8UtoIBS7Lv9g6BnJPXvBKsvYH1aGWvv0347jT3BnSvztOE+kD76XGvZnRC/t6qdW1CaIfwCeA==}
- '@tanstack/query-devtools@5.96.2':
- resolution: {integrity: sha512-vBTB1Qhbm3nHSbEUtQwks/EdcAtFfEapr1WyBW4w2ExYKuXVi3jIxUIHf5MlSltiHuL7zNyUuanqT/7sI2sb6g==}
-
- '@tanstack/react-query-devtools@5.96.2':
- resolution: {integrity: sha512-nTFKLGuTOFvmFRvcyZ3ArWC/DnMNPoBh6h/2yD6rsf7TCTJCQt+oUWOp2uKPTIuEPtF/vN9Kw5tl5mD1Kbposw==}
- peerDependencies:
- '@tanstack/react-query': ^5.96.2
- react: ^18 || ^19
-
'@tanstack/react-query@5.96.2':
resolution: {integrity: sha512-sYyzzJT4G0g02azzJ8o55VFFV31XvFpdUpG+unxS0vSaYsJnSPKGoI6WdPwUucJL1wpgGfwfmntNX/Ub1uOViA==}
peerDependencies:
@@ -4301,6 +4392,9 @@ packages:
'@tybys/wasm-util@0.10.1':
resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
+ '@tybys/wasm-util@0.10.3':
+ resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==}
+
'@types/aria-query@5.0.4':
resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==}
@@ -5950,19 +6044,6 @@ packages:
engines: {node: '>= 12.20.55'}
hasBin: true
- embla-carousel-react@8.6.0:
- resolution: {integrity: sha512-0/PjqU7geVmo6F734pmPqpyHqiM99olvyecY7zdweCw+6tKEXnrE90pBiBbMMU8s5tICemzpQ3hi5EpxzGW+JA==}
- peerDependencies:
- react: ^16.8.0 || ^17.0.1 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
-
- embla-carousel-reactive-utils@8.6.0:
- resolution: {integrity: sha512-fMVUDUEx0/uIEDM0Mz3dHznDhfX+znCCDCeIophYb1QGVM7YThSWX+wz11zlYwWFOr74b4QLGg0hrGPJeG2s4A==}
- peerDependencies:
- embla-carousel: 8.6.0
-
- embla-carousel@8.6.0:
- resolution: {integrity: sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==}
-
emoji-mart@5.6.0:
resolution: {integrity: sha512-eJp3QRe79pjwa+duv+n7+5YsNhRcMl812EcFVwrnRvYKoNPoQb5qxU8DG6Bgwji0akHdp6D4Ln6tYLG58MFSow==}
@@ -6580,6 +6661,9 @@ packages:
fbjs@3.0.5:
resolution: {integrity: sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==}
+ fd-package-json@2.0.0:
+ resolution: {integrity: sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ==}
+
fd-slicer@1.1.0:
resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==}
@@ -6666,6 +6750,11 @@ packages:
resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==}
engines: {node: '>= 6'}
+ formatly@0.3.0:
+ resolution: {integrity: sha512-9XNj/o4wrRFyhSMJOvsuyMwy8aUfBaZ1VrqHVfohyXf0Sw0e+yfKG+xZaY3arGCOMdwFsqObtzVOc1gU9KiT9w==}
+ engines: {node: '>=18.3.0'}
+ hasBin: true
+
formdata-polyfill@4.0.10:
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
engines: {node: '>=12.20.0'}
@@ -6874,6 +6963,9 @@ packages:
get-tsconfig@4.14.0:
resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==}
+ get-tsconfig@4.14.1:
+ resolution: {integrity: sha512-Dz/6HxkrxgNehhxLVeyv8sad9UzF2xBVeaKBQNDfJ5XiSXmp2gTR0eO0RWiT2NCKS5aGP9jjkOMggTN90qU50A==}
+
getenv@2.0.0:
resolution: {integrity: sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ==}
engines: {node: '>=6'}
@@ -7497,6 +7589,10 @@ packages:
resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==}
hasBin: true
+ jiti@2.7.0:
+ resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==}
+ hasBin: true
+
jose@6.2.2:
resolution: {integrity: sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ==}
@@ -7586,6 +7682,11 @@ packages:
resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
engines: {node: '>=6'}
+ knip@6.32.2:
+ resolution: {integrity: sha512-WXTXbmocrw7gqm1A1TQvFN0OgJ7hUSU6E1g6SPRIzzHFogUBhXByc7cYeOFVtJ2uODg7DP4VbESYBYnfbtBYsg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ hasBin: true
+
lan-network@0.2.1:
resolution: {integrity: sha512-ONPnazC96VKDntab9j9JKwIWhZ4ZUceB4A9Epu4Ssg0hYFmtHZSeQ+n15nIwTFmcBUKtExOer8WTJ4GF9MO64A==}
hasBin: true
@@ -8619,6 +8720,13 @@ packages:
resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==}
engines: {node: '>= 0.4'}
+ oxc-parser@0.143.0:
+ resolution: {integrity: sha512-ov0NzaDCOInknS7mP1cwKdJERt3utPW8ldjtdUXQ8Ty0GEFD08wk422vCUN0d7pST6kqtV7dxoI9w1Zi0l/9TA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+
+ oxc-resolver@11.24.2:
+ resolution: {integrity: sha512-FY91FiDBj7ls5MsFS9jN3tjz2o0/zsdSsymlakySaBwVJZorHhkWyICLZMKxlu1R9vYo+sd3z1jwb4J8x7bNDw==}
+
p-cancelable@2.1.1:
resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==}
engines: {node: '>=8'}
@@ -8776,6 +8884,10 @@ packages:
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
engines: {node: '>=12'}
+ picomatch@4.0.5:
+ resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==}
+ engines: {node: '>=12'}
+
pify@2.3.0:
resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
engines: {node: '>=0.10.0'}
@@ -9780,6 +9892,10 @@ packages:
resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==}
engines: {node: '>= 6.0.0', npm: '>= 3.0.0'}
+ smol-toml@1.8.0:
+ resolution: {integrity: sha512-kCZr2V3ch9i00x8zXRhjUNVcjG9ijES5dDudkXvUVCT5QlJNQWElSJdZqyPemffHoLNUYwOcou0Fy+ojN0uHSQ==}
+ engines: {node: '>= 18'}
+
socks-proxy-agent@8.0.5:
resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==}
engines: {node: '>= 14'}
@@ -9962,6 +10078,10 @@ packages:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
+ strip-json-comments@5.0.3:
+ resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==}
+ engines: {node: '>=14.16'}
+
structured-headers@0.4.1:
resolution: {integrity: sha512-0MP/Cxx5SzeeZ10p/bZI0S6MpgD+yxAhi1BOQ34jgnMXsCq3j1t6tQnZu+KdlL7dvJTLT3g9xN8tl10TqgFMcg==}
@@ -10106,6 +10226,10 @@ packages:
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
engines: {node: '>=12.0.0'}
+ tinyglobby@0.2.17:
+ resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==}
+ engines: {node: '>=12.0.0'}
+
tinyrainbow@3.1.0:
resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==}
engines: {node: '>=14.0.0'}
@@ -10257,6 +10381,10 @@ packages:
ufo@1.6.3:
resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==}
+ unbash@4.0.10:
+ resolution: {integrity: sha512-b7zoBQvpWp0vuN5q2vK2RRBR2SvuruQAs50DApdDveBSn3eSYd84IaHodFqQIMlvY9K2VnyBUEXgwOBuGU9GBg==}
+ engines: {node: '>=14'}
+
unbox-primitive@1.1.0:
resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}
engines: {node: '>= 0.4'}
@@ -10547,6 +10675,10 @@ packages:
resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
engines: {node: '>=18'}
+ walk-up-path@4.0.0:
+ resolution: {integrity: sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==}
+ engines: {node: 20 || >=22}
+
walker@1.0.8:
resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==}
@@ -10757,6 +10889,9 @@ packages:
zod@4.3.6:
resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
+ zod@4.4.3:
+ resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==}
+
zustand@5.0.12:
resolution: {integrity: sha512-i77ae3aZq4dhMlRhJVCYgMLKuSiZAaUPAct2AksxQ+gOtimhGMdXljRT21P5BNpeT4kXlLIckvkPM029OljD7g==}
engines: {node: '>=12.20.0'}
@@ -11698,16 +11833,32 @@ snapshots:
tslib: 2.8.1
optional: true
+ '@emnapi/core@1.11.2':
+ dependencies:
+ '@emnapi/wasi-threads': 1.2.2
+ tslib: 2.8.1
+ optional: true
+
'@emnapi/runtime@1.10.0':
dependencies:
tslib: 2.8.1
optional: true
+ '@emnapi/runtime@1.11.2':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
'@emnapi/wasi-threads@1.2.1':
dependencies:
tslib: 2.8.1
optional: true
+ '@emnapi/wasi-threads@1.2.2':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
'@emoji-mart/data@1.2.1': {}
'@esbuild/aix-ppc64@0.25.12':
@@ -11793,9 +11944,9 @@ snapshots:
eslint: 9.39.4(jiti@1.21.7)
eslint-visitor-keys: 3.4.3
- '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.6.1))':
+ '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.7.0))':
dependencies:
- eslint: 9.39.4(jiti@2.6.1)
+ eslint: 9.39.4(jiti@2.7.0)
eslint-visitor-keys: 3.4.3
'@eslint-community/regexpp@4.12.2': {}
@@ -12570,6 +12721,13 @@ snapshots:
'@tybys/wasm-util': 0.10.1
optional: true
+ '@napi-rs/wasm-runtime@1.2.3(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)':
+ dependencies:
+ '@emnapi/core': 1.11.2
+ '@emnapi/runtime': 1.11.2
+ '@tybys/wasm-util': 0.10.3
+ optional: true
+
'@next/env@15.5.18': {}
'@next/env@16.2.6': {}
@@ -12756,8 +12914,128 @@ snapshots:
'@orama/orama@3.1.18': {}
+ '@oxc-parser/binding-android-arm-eabi@0.143.0':
+ optional: true
+
+ '@oxc-parser/binding-android-arm64@0.143.0':
+ optional: true
+
+ '@oxc-parser/binding-darwin-arm64@0.143.0':
+ optional: true
+
+ '@oxc-parser/binding-darwin-x64@0.143.0':
+ optional: true
+
+ '@oxc-parser/binding-freebsd-x64@0.143.0':
+ optional: true
+
+ '@oxc-parser/binding-linux-arm-gnueabihf@0.143.0':
+ optional: true
+
+ '@oxc-parser/binding-linux-arm-musleabihf@0.143.0':
+ optional: true
+
+ '@oxc-parser/binding-linux-arm64-gnu@0.143.0':
+ optional: true
+
+ '@oxc-parser/binding-linux-arm64-musl@0.143.0':
+ optional: true
+
+ '@oxc-parser/binding-linux-ppc64-gnu@0.143.0':
+ optional: true
+
+ '@oxc-parser/binding-linux-riscv64-gnu@0.143.0':
+ optional: true
+
+ '@oxc-parser/binding-linux-riscv64-musl@0.143.0':
+ optional: true
+
+ '@oxc-parser/binding-linux-s390x-gnu@0.143.0':
+ optional: true
+
+ '@oxc-parser/binding-linux-x64-gnu@0.143.0':
+ optional: true
+
+ '@oxc-parser/binding-linux-x64-musl@0.143.0':
+ optional: true
+
+ '@oxc-parser/binding-openharmony-arm64@0.143.0':
+ optional: true
+
+ '@oxc-parser/binding-win32-arm64-msvc@0.143.0':
+ optional: true
+
+ '@oxc-parser/binding-win32-ia32-msvc@0.143.0':
+ optional: true
+
+ '@oxc-parser/binding-win32-x64-msvc@0.143.0':
+ optional: true
+
'@oxc-project/types@0.120.0': {}
+ '@oxc-project/types@0.143.0': {}
+
+ '@oxc-resolver/binding-android-arm-eabi@11.24.2':
+ optional: true
+
+ '@oxc-resolver/binding-android-arm64@11.24.2':
+ optional: true
+
+ '@oxc-resolver/binding-darwin-arm64@11.24.2':
+ optional: true
+
+ '@oxc-resolver/binding-darwin-x64@11.24.2':
+ optional: true
+
+ '@oxc-resolver/binding-freebsd-x64@11.24.2':
+ optional: true
+
+ '@oxc-resolver/binding-linux-arm-gnueabihf@11.24.2':
+ optional: true
+
+ '@oxc-resolver/binding-linux-arm-musleabihf@11.24.2':
+ optional: true
+
+ '@oxc-resolver/binding-linux-arm64-gnu@11.24.2':
+ optional: true
+
+ '@oxc-resolver/binding-linux-arm64-musl@11.24.2':
+ optional: true
+
+ '@oxc-resolver/binding-linux-ppc64-gnu@11.24.2':
+ optional: true
+
+ '@oxc-resolver/binding-linux-riscv64-gnu@11.24.2':
+ optional: true
+
+ '@oxc-resolver/binding-linux-riscv64-musl@11.24.2':
+ optional: true
+
+ '@oxc-resolver/binding-linux-s390x-gnu@11.24.2':
+ optional: true
+
+ '@oxc-resolver/binding-linux-x64-gnu@11.24.2':
+ optional: true
+
+ '@oxc-resolver/binding-linux-x64-musl@11.24.2':
+ optional: true
+
+ '@oxc-resolver/binding-openharmony-arm64@11.24.2':
+ optional: true
+
+ '@oxc-resolver/binding-wasm32-wasi@11.24.2':
+ dependencies:
+ '@emnapi/core': 1.11.2
+ '@emnapi/runtime': 1.11.2
+ '@napi-rs/wasm-runtime': 1.2.3(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)
+ optional: true
+
+ '@oxc-resolver/binding-win32-arm64-msvc@11.24.2':
+ optional: true
+
+ '@oxc-resolver/binding-win32-x64-msvc@11.24.2':
+ optional: true
+
'@package-json/types@0.0.12': {}
'@pkgjs/parseargs@0.11.0':
@@ -13908,9 +14186,9 @@ snapshots:
'@rolldown/binding-openharmony-arm64@1.0.0-rc.10':
optional: true
- '@rolldown/binding-wasm32-wasi@1.0.0-rc.10(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)':
+ '@rolldown/binding-wasm32-wasi@1.0.0-rc.10(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)':
dependencies:
- '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)
+ '@napi-rs/wasm-runtime': 1.2.3(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)
transitivePeerDependencies:
- '@emnapi/core'
- '@emnapi/runtime'
@@ -14110,23 +14388,15 @@ snapshots:
postcss: 8.5.10
tailwindcss: 4.2.2
- '@tailwindcss/vite@4.2.2(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@2.6.1)(terser@5.47.1)(yaml@2.9.0))':
+ '@tailwindcss/vite@4.2.2(vite@8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@2.7.0)(terser@5.47.1)(yaml@2.9.0))':
dependencies:
'@tailwindcss/node': 4.2.2
'@tailwindcss/oxide': 4.2.2
tailwindcss: 4.2.2
- vite: 8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@2.6.1)(terser@5.47.1)(yaml@2.9.0)
+ vite: 8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@2.7.0)(terser@5.47.1)(yaml@2.9.0)
'@tanstack/query-core@5.96.2': {}
- '@tanstack/query-devtools@5.96.2': {}
-
- '@tanstack/react-query-devtools@5.96.2(@tanstack/react-query@5.96.2(react@19.2.3))(react@19.2.3)':
- dependencies:
- '@tanstack/query-devtools': 5.96.2
- '@tanstack/react-query': 5.96.2(react@19.2.3)
- react: 19.2.3
-
'@tanstack/react-query@5.96.2(react@19.2.0)':
dependencies:
'@tanstack/query-core': 5.96.2
@@ -14447,6 +14717,11 @@ snapshots:
tslib: 2.8.1
optional: true
+ '@tybys/wasm-util@0.10.3':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
'@types/aria-query@5.0.4': {}
'@types/babel__core@7.20.5':
@@ -14736,15 +15011,15 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/eslint-plugin@8.58.1(@typescript-eslint/parser@8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)':
+ '@typescript-eslint/eslint-plugin@8.58.1(@typescript-eslint/parser@8.58.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)':
dependencies:
'@eslint-community/regexpp': 4.12.2
- '@typescript-eslint/parser': 8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)
+ '@typescript-eslint/parser': 8.58.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)
'@typescript-eslint/scope-manager': 8.58.1
- '@typescript-eslint/type-utils': 8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)
- '@typescript-eslint/utils': 8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)
+ '@typescript-eslint/type-utils': 8.58.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)
+ '@typescript-eslint/utils': 8.58.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)
'@typescript-eslint/visitor-keys': 8.58.1
- eslint: 9.39.4(jiti@2.6.1)
+ eslint: 9.39.4(jiti@2.7.0)
ignore: 7.0.5
natural-compare: 1.4.0
ts-api-utils: 2.5.0(typescript@5.9.3)
@@ -14764,14 +15039,14 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/parser@8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)':
+ '@typescript-eslint/parser@8.58.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)':
dependencies:
'@typescript-eslint/scope-manager': 8.58.1
'@typescript-eslint/types': 8.58.1
'@typescript-eslint/typescript-estree': 8.58.1(typescript@5.9.3)
'@typescript-eslint/visitor-keys': 8.58.1
debug: 4.4.3
- eslint: 9.39.4(jiti@2.6.1)
+ eslint: 9.39.4(jiti@2.7.0)
typescript: 5.9.3
transitivePeerDependencies:
- supports-color
@@ -14806,13 +15081,13 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/type-utils@8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)':
+ '@typescript-eslint/type-utils@8.58.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)':
dependencies:
'@typescript-eslint/types': 8.58.1
'@typescript-eslint/typescript-estree': 8.58.1(typescript@5.9.3)
- '@typescript-eslint/utils': 8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)
+ '@typescript-eslint/utils': 8.58.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)
debug: 4.4.3
- eslint: 9.39.4(jiti@2.6.1)
+ eslint: 9.39.4(jiti@2.7.0)
ts-api-utils: 2.5.0(typescript@5.9.3)
typescript: 5.9.3
transitivePeerDependencies:
@@ -14846,13 +15121,13 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/utils@8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)':
+ '@typescript-eslint/utils@8.58.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)':
dependencies:
- '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.6.1))
+ '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0))
'@typescript-eslint/scope-manager': 8.58.1
'@typescript-eslint/types': 8.58.1
'@typescript-eslint/typescript-estree': 8.58.1(typescript@5.9.3)
- eslint: 9.39.4(jiti@2.6.1)
+ eslint: 9.39.4(jiti@2.7.0)
typescript: 5.9.3
transitivePeerDependencies:
- supports-color
@@ -14933,7 +15208,7 @@ snapshots:
d3-selection: 3.0.0
d3-transition: 3.0.1(d3-selection@3.0.0)
- '@vitejs/plugin-react@5.2.0(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@2.6.1)(terser@5.47.1)(yaml@2.9.0))':
+ '@vitejs/plugin-react@5.2.0(vite@8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@2.7.0)(terser@5.47.1)(yaml@2.9.0))':
dependencies:
'@babel/core': 7.29.0
'@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0)
@@ -14941,14 +15216,14 @@ snapshots:
'@rolldown/pluginutils': 1.0.0-rc.3
'@types/babel__core': 7.20.5
react-refresh: 0.18.0
- vite: 8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@2.6.1)(terser@5.47.1)(yaml@2.9.0)
+ vite: 8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@2.7.0)(terser@5.47.1)(yaml@2.9.0)
transitivePeerDependencies:
- supports-color
- '@vitejs/plugin-react@6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@2.6.1)(terser@5.47.1)(yaml@2.9.0))':
+ '@vitejs/plugin-react@6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@2.7.0)(terser@5.47.1)(yaml@2.9.0))':
dependencies:
'@rolldown/pluginutils': 1.0.0-rc.7
- vite: 8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@2.6.1)(terser@5.47.1)(yaml@2.9.0)
+ vite: 8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@2.7.0)(terser@5.47.1)(yaml@2.9.0)
optionalDependencies:
babel-plugin-react-compiler: 1.0.0
@@ -14961,23 +15236,23 @@ snapshots:
chai: 6.2.2
tinyrainbow: 3.1.0
- '@vitest/mocker@4.1.0(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@1.21.7)(terser@5.47.1)(yaml@2.9.0))':
+ '@vitest/mocker@4.1.0(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@1.21.7)(terser@5.47.1)(yaml@2.9.0))':
dependencies:
'@vitest/spy': 4.1.0
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
msw: 2.12.14(@types/node@25.5.0)(typescript@5.9.3)
- vite: 8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@1.21.7)(terser@5.47.1)(yaml@2.9.0)
+ vite: 8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@1.21.7)(terser@5.47.1)(yaml@2.9.0)
- '@vitest/mocker@4.1.0(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@2.6.1)(terser@5.47.1)(yaml@2.9.0))':
+ '@vitest/mocker@4.1.0(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@2.7.0)(terser@5.47.1)(yaml@2.9.0))':
dependencies:
'@vitest/spy': 4.1.0
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
msw: 2.12.14(@types/node@25.5.0)(typescript@5.9.3)
- vite: 8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@2.6.1)(terser@5.47.1)(yaml@2.9.0)
+ vite: 8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@2.7.0)(terser@5.47.1)(yaml@2.9.0)
'@vitest/pretty-format@4.1.0':
dependencies:
@@ -16355,7 +16630,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
- electron-vite@5.0.0(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@2.6.1)(terser@5.47.1)(yaml@2.9.0)):
+ electron-vite@5.0.0(vite@8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@2.7.0)(terser@5.47.1)(yaml@2.9.0)):
dependencies:
'@babel/core': 7.29.0
'@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.29.0)
@@ -16363,7 +16638,7 @@ snapshots:
esbuild: 0.25.12
magic-string: 0.30.21
picocolors: 1.1.1
- vite: 8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@2.6.1)(terser@5.47.1)(yaml@2.9.0)
+ vite: 8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@2.7.0)(terser@5.47.1)(yaml@2.9.0)
transitivePeerDependencies:
- supports-color
@@ -16387,18 +16662,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- embla-carousel-react@8.6.0(react@19.2.3):
- dependencies:
- embla-carousel: 8.6.0
- embla-carousel-reactive-utils: 8.6.0(embla-carousel@8.6.0)
- react: 19.2.3
-
- embla-carousel-reactive-utils@8.6.0(embla-carousel@8.6.0):
- dependencies:
- embla-carousel: 8.6.0
-
- embla-carousel@8.6.0: {}
-
emoji-mart@5.6.0: {}
emoji-regex@10.6.0: {}
@@ -16698,13 +16961,13 @@ snapshots:
- supports-color
optional: true
- eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.6.1)):
+ eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.58.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint@9.39.4(jiti@2.7.0)):
dependencies:
'@package-json/types': 0.0.12
'@typescript-eslint/types': 8.58.1
comment-parser: 1.4.7
debug: 4.4.3
- eslint: 9.39.4(jiti@2.6.1)
+ eslint: 9.39.4(jiti@2.7.0)
eslint-import-context: 0.1.9(unrs-resolver@1.12.0)
is-glob: 4.0.3
minimatch: 10.2.4
@@ -16712,7 +16975,7 @@ snapshots:
stable-hash-x: 0.2.0
unrs-resolver: 1.12.0
optionalDependencies:
- '@typescript-eslint/utils': 8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)
+ '@typescript-eslint/utils': 8.58.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)
eslint-import-resolver-node: 0.3.10
transitivePeerDependencies:
- supports-color
@@ -16750,9 +17013,9 @@ snapshots:
dependencies:
eslint: 9.39.4(jiti@1.21.7)
- eslint-plugin-react-hooks@5.2.0(eslint@9.39.4(jiti@2.6.1)):
+ eslint-plugin-react-hooks@5.2.0(eslint@9.39.4(jiti@2.7.0)):
dependencies:
- eslint: 9.39.4(jiti@2.6.1)
+ eslint: 9.39.4(jiti@2.7.0)
eslint-plugin-react@7.37.5(eslint@9.39.4(jiti@1.21.7)):
dependencies:
@@ -16776,7 +17039,7 @@ snapshots:
string.prototype.matchall: 4.0.12
string.prototype.repeat: 1.0.0
- eslint-plugin-react@7.37.5(eslint@9.39.4(jiti@2.6.1)):
+ eslint-plugin-react@7.37.5(eslint@9.39.4(jiti@2.7.0)):
dependencies:
array-includes: 3.1.9
array.prototype.findlast: 1.2.5
@@ -16784,7 +17047,7 @@ snapshots:
array.prototype.tosorted: 1.1.4
doctrine: 2.1.0
es-iterator-helpers: 1.3.1
- eslint: 9.39.4(jiti@2.6.1)
+ eslint: 9.39.4(jiti@2.7.0)
estraverse: 5.3.0
hasown: 2.0.2
jsx-ast-utils: 3.3.5
@@ -16850,9 +17113,9 @@ snapshots:
transitivePeerDependencies:
- supports-color
- eslint@9.39.4(jiti@2.6.1):
+ eslint@9.39.4(jiti@2.7.0):
dependencies:
- '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.6.1))
+ '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0))
'@eslint-community/regexpp': 4.12.2
'@eslint/config-array': 0.21.2
'@eslint/config-helpers': 0.4.2
@@ -16887,7 +17150,7 @@ snapshots:
natural-compare: 1.4.0
optionator: 0.9.4
optionalDependencies:
- jiti: 2.6.1
+ jiti: 2.7.0
transitivePeerDependencies:
- supports-color
@@ -17363,6 +17626,10 @@ snapshots:
transitivePeerDependencies:
- encoding
+ fd-package-json@2.0.0:
+ dependencies:
+ walk-up-path: 4.0.0
+
fd-slicer@1.1.0:
dependencies:
pend: 1.2.0
@@ -17371,6 +17638,10 @@ snapshots:
optionalDependencies:
picomatch: 4.0.3
+ fdir@6.5.0(picomatch@4.0.5):
+ optionalDependencies:
+ picomatch: 4.0.5
+
fetch-blob@3.2.0:
dependencies:
node-domexception: 1.0.0
@@ -17464,6 +17735,10 @@ snapshots:
hasown: 2.0.2
mime-types: 2.1.35
+ formatly@0.3.0:
+ dependencies:
+ fd-package-json: 2.0.0
+
formdata-polyfill@4.0.10:
dependencies:
fetch-blob: 3.2.0
@@ -17586,7 +17861,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
- fumadocs-mdx@12.0.3(fumadocs-core@15.8.5(@types/react@19.2.14)(lucide-react@1.0.1(react@19.2.3))(next@15.5.18(@opentelemetry/api@1.9.1)(@playwright/test@1.58.2)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react-router@7.14.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3))(next@15.5.18(@opentelemetry/api@1.9.1)(@playwright/test@1.58.2)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@2.6.1)(terser@5.47.1)(yaml@2.9.0)):
+ fumadocs-mdx@12.0.3(fumadocs-core@15.8.5(@types/react@19.2.14)(lucide-react@1.0.1(react@19.2.3))(next@15.5.18(@opentelemetry/api@1.9.1)(@playwright/test@1.58.2)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react-router@7.14.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3))(next@15.5.18(@opentelemetry/api@1.9.1)(@playwright/test@1.58.2)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)(vite@8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@2.7.0)(terser@5.47.1)(yaml@2.9.0)):
dependencies:
'@mdx-js/mdx': 3.1.1
'@standard-schema/spec': 1.1.0
@@ -17608,7 +17883,7 @@ snapshots:
optionalDependencies:
next: 15.5.18(@opentelemetry/api@1.9.1)(@playwright/test@1.58.2)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
react: 19.2.3
- vite: 8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@2.6.1)(terser@5.47.1)(yaml@2.9.0)
+ vite: 8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@2.7.0)(terser@5.47.1)(yaml@2.9.0)
transitivePeerDependencies:
- supports-color
@@ -17742,6 +18017,10 @@ snapshots:
dependencies:
resolve-pkg-maps: 1.0.0
+ get-tsconfig@4.14.1:
+ dependencies:
+ resolve-pkg-maps: 1.0.0
+
getenv@2.0.0: {}
github-slugger@2.0.0: {}
@@ -18463,6 +18742,8 @@ snapshots:
jiti@2.6.1: {}
+ jiti@2.7.0: {}
+
jose@6.2.2: {}
js-tokens@4.0.0: {}
@@ -18558,6 +18839,22 @@ snapshots:
kleur@4.1.5: {}
+ knip@6.32.2:
+ dependencies:
+ fdir: 6.5.0(picomatch@4.0.5)
+ formatly: 0.3.0
+ get-tsconfig: 4.14.1
+ jiti: 2.7.0
+ oxc-parser: 0.143.0
+ oxc-resolver: 11.24.2
+ picomatch: 4.0.5
+ smol-toml: 1.8.0
+ strip-json-comments: 5.0.3
+ tinyglobby: 0.2.17
+ unbash: 4.0.10
+ yaml: 2.9.0
+ zod: 4.4.3
+
lan-network@0.2.1: {}
langium@4.2.2:
@@ -19987,6 +20284,52 @@ snapshots:
object-keys: 1.1.1
safe-push-apply: 1.0.0
+ oxc-parser@0.143.0:
+ dependencies:
+ '@oxc-project/types': 0.143.0
+ optionalDependencies:
+ '@oxc-parser/binding-android-arm-eabi': 0.143.0
+ '@oxc-parser/binding-android-arm64': 0.143.0
+ '@oxc-parser/binding-darwin-arm64': 0.143.0
+ '@oxc-parser/binding-darwin-x64': 0.143.0
+ '@oxc-parser/binding-freebsd-x64': 0.143.0
+ '@oxc-parser/binding-linux-arm-gnueabihf': 0.143.0
+ '@oxc-parser/binding-linux-arm-musleabihf': 0.143.0
+ '@oxc-parser/binding-linux-arm64-gnu': 0.143.0
+ '@oxc-parser/binding-linux-arm64-musl': 0.143.0
+ '@oxc-parser/binding-linux-ppc64-gnu': 0.143.0
+ '@oxc-parser/binding-linux-riscv64-gnu': 0.143.0
+ '@oxc-parser/binding-linux-riscv64-musl': 0.143.0
+ '@oxc-parser/binding-linux-s390x-gnu': 0.143.0
+ '@oxc-parser/binding-linux-x64-gnu': 0.143.0
+ '@oxc-parser/binding-linux-x64-musl': 0.143.0
+ '@oxc-parser/binding-openharmony-arm64': 0.143.0
+ '@oxc-parser/binding-win32-arm64-msvc': 0.143.0
+ '@oxc-parser/binding-win32-ia32-msvc': 0.143.0
+ '@oxc-parser/binding-win32-x64-msvc': 0.143.0
+
+ oxc-resolver@11.24.2:
+ optionalDependencies:
+ '@oxc-resolver/binding-android-arm-eabi': 11.24.2
+ '@oxc-resolver/binding-android-arm64': 11.24.2
+ '@oxc-resolver/binding-darwin-arm64': 11.24.2
+ '@oxc-resolver/binding-darwin-x64': 11.24.2
+ '@oxc-resolver/binding-freebsd-x64': 11.24.2
+ '@oxc-resolver/binding-linux-arm-gnueabihf': 11.24.2
+ '@oxc-resolver/binding-linux-arm-musleabihf': 11.24.2
+ '@oxc-resolver/binding-linux-arm64-gnu': 11.24.2
+ '@oxc-resolver/binding-linux-arm64-musl': 11.24.2
+ '@oxc-resolver/binding-linux-ppc64-gnu': 11.24.2
+ '@oxc-resolver/binding-linux-riscv64-gnu': 11.24.2
+ '@oxc-resolver/binding-linux-riscv64-musl': 11.24.2
+ '@oxc-resolver/binding-linux-s390x-gnu': 11.24.2
+ '@oxc-resolver/binding-linux-x64-gnu': 11.24.2
+ '@oxc-resolver/binding-linux-x64-musl': 11.24.2
+ '@oxc-resolver/binding-openharmony-arm64': 11.24.2
+ '@oxc-resolver/binding-wasm32-wasi': 11.24.2
+ '@oxc-resolver/binding-win32-arm64-msvc': 11.24.2
+ '@oxc-resolver/binding-win32-x64-msvc': 11.24.2
+
p-cancelable@2.1.1: {}
p-limit@2.3.0:
@@ -20125,6 +20468,8 @@ snapshots:
picomatch@4.0.3: {}
+ picomatch@4.0.5: {}
+
pify@2.3.0: {}
pinyin-pro@3.26.0: {}
@@ -21116,7 +21461,7 @@ snapshots:
robust-predicates@3.0.3: {}
- rolldown@1.0.0-rc.10(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0):
+ rolldown@1.0.0-rc.10(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2):
dependencies:
'@oxc-project/types': 0.120.0
'@rolldown/pluginutils': 1.0.0-rc.10
@@ -21133,7 +21478,7 @@ snapshots:
'@rolldown/binding-linux-x64-gnu': 1.0.0-rc.10
'@rolldown/binding-linux-x64-musl': 1.0.0-rc.10
'@rolldown/binding-openharmony-arm64': 1.0.0-rc.10
- '@rolldown/binding-wasm32-wasi': 1.0.0-rc.10(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)
+ '@rolldown/binding-wasm32-wasi': 1.0.0-rc.10(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)
'@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.10
'@rolldown/binding-win32-x64-msvc': 1.0.0-rc.10
transitivePeerDependencies:
@@ -21479,6 +21824,8 @@ snapshots:
smart-buffer@4.2.0: {}
+ smol-toml@1.8.0: {}
+
socks-proxy-agent@8.0.5:
dependencies:
agent-base: 7.1.4
@@ -21663,6 +22010,8 @@ snapshots:
strip-json-comments@3.1.1: {}
+ strip-json-comments@5.0.3: {}
+
structured-headers@0.4.1: {}
style-to-js@1.1.21:
@@ -21826,6 +22175,11 @@ snapshots:
fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3
+ tinyglobby@0.2.17:
+ dependencies:
+ fdir: 6.5.0(picomatch@4.0.5)
+ picomatch: 4.0.5
+
tinyrainbow@3.1.0: {}
tldts-core@7.0.27: {}
@@ -21963,13 +22317,13 @@ snapshots:
possible-typed-array-names: 1.1.0
reflect.getprototypeof: 1.0.10
- typescript-eslint@8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3):
+ typescript-eslint@8.58.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3):
dependencies:
- '@typescript-eslint/eslint-plugin': 8.58.1(@typescript-eslint/parser@8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)
- '@typescript-eslint/parser': 8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)
+ '@typescript-eslint/eslint-plugin': 8.58.1(@typescript-eslint/parser@8.58.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)
+ '@typescript-eslint/parser': 8.58.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)
'@typescript-eslint/typescript-estree': 8.58.1(typescript@5.9.3)
- '@typescript-eslint/utils': 8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)
- eslint: 9.39.4(jiti@2.6.1)
+ '@typescript-eslint/utils': 8.58.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)
+ eslint: 9.39.4(jiti@2.7.0)
typescript: 5.9.3
transitivePeerDependencies:
- supports-color
@@ -21982,6 +22336,8 @@ snapshots:
ufo@1.6.3: {}
+ unbash@4.0.10: {}
+
unbox-primitive@1.1.0:
dependencies:
call-bound: 1.0.4
@@ -22173,15 +22529,6 @@ snapshots:
- '@types/react'
- '@types/react-dom'
- vaul@1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
- dependencies:
- '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- react: 19.2.3
- react-dom: 19.2.3(react@19.2.3)
- transitivePeerDependencies:
- - '@types/react'
- - '@types/react-dom'
-
verror@1.10.1:
dependencies:
assert-plus: 1.0.0
@@ -22221,13 +22568,13 @@ snapshots:
d3-time: 3.1.0
d3-timer: 3.0.1
- vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@1.21.7)(terser@5.47.1)(yaml@2.9.0):
+ vite@8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@1.21.7)(terser@5.47.1)(yaml@2.9.0):
dependencies:
lightningcss: 1.32.0
- picomatch: 4.0.3
+ picomatch: 4.0.5
postcss: 8.5.10
- rolldown: 1.0.0-rc.10(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)
- tinyglobby: 0.2.15
+ rolldown: 1.0.0-rc.10(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)
+ tinyglobby: 0.2.17
optionalDependencies:
'@types/node': 25.5.0
fsevents: 2.3.3
@@ -22238,27 +22585,27 @@ snapshots:
- '@emnapi/core'
- '@emnapi/runtime'
- vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@2.6.1)(terser@5.47.1)(yaml@2.9.0):
+ vite@8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@2.7.0)(terser@5.47.1)(yaml@2.9.0):
dependencies:
lightningcss: 1.32.0
- picomatch: 4.0.3
+ picomatch: 4.0.5
postcss: 8.5.10
- rolldown: 1.0.0-rc.10(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)
- tinyglobby: 0.2.15
+ rolldown: 1.0.0-rc.10(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)
+ tinyglobby: 0.2.17
optionalDependencies:
'@types/node': 25.5.0
fsevents: 2.3.3
- jiti: 2.6.1
+ jiti: 2.7.0
terser: 5.47.1
yaml: 2.9.0
transitivePeerDependencies:
- '@emnapi/core'
- '@emnapi/runtime'
- vitest@4.1.0(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(jsdom@29.0.1(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@1.21.7)(terser@5.47.1)(yaml@2.9.0)):
+ vitest@4.1.0(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(jsdom@29.0.1(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@1.21.7)(terser@5.47.1)(yaml@2.9.0)):
dependencies:
'@vitest/expect': 4.1.0
- '@vitest/mocker': 4.1.0(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@1.21.7)(terser@5.47.1)(yaml@2.9.0))
+ '@vitest/mocker': 4.1.0(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@1.21.7)(terser@5.47.1)(yaml@2.9.0))
'@vitest/pretty-format': 4.1.0
'@vitest/runner': 4.1.0
'@vitest/snapshot': 4.1.0
@@ -22275,7 +22622,7 @@ snapshots:
tinyexec: 1.0.4
tinyglobby: 0.2.15
tinyrainbow: 3.1.0
- vite: 8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@1.21.7)(terser@5.47.1)(yaml@2.9.0)
+ vite: 8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@1.21.7)(terser@5.47.1)(yaml@2.9.0)
why-is-node-running: 2.3.0
optionalDependencies:
'@opentelemetry/api': 1.9.1
@@ -22284,10 +22631,10 @@ snapshots:
transitivePeerDependencies:
- msw
- vitest@4.1.0(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(jsdom@29.0.1(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@2.6.1)(terser@5.47.1)(yaml@2.9.0)):
+ vitest@4.1.0(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(jsdom@29.0.1(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@2.7.0)(terser@5.47.1)(yaml@2.9.0)):
dependencies:
'@vitest/expect': 4.1.0
- '@vitest/mocker': 4.1.0(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@2.6.1)(terser@5.47.1)(yaml@2.9.0))
+ '@vitest/mocker': 4.1.0(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@2.7.0)(terser@5.47.1)(yaml@2.9.0))
'@vitest/pretty-format': 4.1.0
'@vitest/runner': 4.1.0
'@vitest/snapshot': 4.1.0
@@ -22304,7 +22651,7 @@ snapshots:
tinyexec: 1.0.4
tinyglobby: 0.2.15
tinyrainbow: 3.1.0
- vite: 8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.5.0)(jiti@2.6.1)(terser@5.47.1)(yaml@2.9.0)
+ vite: 8.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.5.0)(jiti@2.7.0)(terser@5.47.1)(yaml@2.9.0)
why-is-node-running: 2.3.0
optionalDependencies:
'@opentelemetry/api': 1.9.1
@@ -22340,6 +22687,8 @@ snapshots:
dependencies:
xml-name-validator: 5.0.0
+ walk-up-path@4.0.0: {}
+
walker@1.0.8:
dependencies:
makeerror: 1.0.12
@@ -22534,6 +22883,8 @@ snapshots:
zod@4.3.6: {}
+ zod@4.4.3: {}
+
zustand@5.0.12(@types/react@19.2.14)(immer@11.1.4)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)):
optionalDependencies:
'@types/react': 19.2.14
diff --git a/scripts/check-ui-wildcard-exports.mjs b/scripts/check-ui-wildcard-exports.mjs
new file mode 100755
index 000000000..3b27a9167
--- /dev/null
+++ b/scripts/check-ui-wildcard-exports.mjs
@@ -0,0 +1,225 @@
+#!/usr/bin/env node
+/**
+ * Reports files in packages/ui that nothing reaches.
+ *
+ * This exists because knip structurally cannot see them. knip derives entry
+ * points from a workspace's package.json `exports` (graph/build.js calls
+ * `getEntrySpecifiersFromManifest` unconditionally — there is no config flag to
+ * opt out), and packages/ui exports four wildcards:
+ *
+ * "./components/ui/*" -> "./components/ui/*.tsx"
+ * "./components/common/*" -> "./components/common/*.tsx"
+ * "./markdown/*" -> "./markdown/*.tsx"
+ * "./hooks/*" -> "./hooks/*.ts"
+ *
+ * Each expands to a glob covering every file in the directory, so all of them
+ * register as entry points and none can ever be reported unused. Setting
+ * `entry: []`, negating the paths in `entry`, and `--production` were all
+ * tried; manifest entries are a separate code path from configured ones and
+ * none of them subtract from it. packages/views is unaffected — 44 of its 45
+ * exports name a specific file — which is why knip does flag dead files there.
+ *
+ * That blind spot is exactly where the 16 dead components removed in MUL-6353
+ * lived, so without this check the cleanup has no regression guard at all.
+ *
+ * Specifiers are resolved against the importing file's own directory, never
+ * matched by basename. 17 of the 59 files guarded here share a basename with
+ * some other file in the repo (`button`, `card`, `input`, `label`, …), so
+ * basename matching would silently pass a dead file whenever any unrelated
+ * module imported a same-named sibling.
+ *
+ * Liveness is reachability, not a reference count: the walk starts from every
+ * file outside the guarded directories and follows imports inward, so a pair
+ * of dead components importing only each other stays dead.
+ *
+ * Edges come from real syntax nodes via the TypeScript parser, not from a
+ * regex over source text. Text matching counts a commented-out import as a
+ * live edge, which is precisely the state a file passes through when its last
+ * real importer is removed. 52 specifiers in this repo appear only in comments
+ * or prose today; none currently point into packages/ui, but that is a
+ * coincidence rather than a property.
+ *
+ * Run: node scripts/check-ui-wildcard-exports.mjs
+ */
+
+import { readdirSync, readFileSync, statSync } from "node:fs";
+import { dirname, join, relative, resolve, sep } from "node:path";
+import ts from "typescript";
+
+const repoRoot = resolve(import.meta.dirname, "..");
+const uiRoot = join(repoRoot, "packages", "ui");
+const pkgName = "@multica/ui";
+
+const SOURCE_EXTENSIONS = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"];
+const SKIP_DIRS = new Set(["node_modules", ".git", ".next", ".turbo", "out", "dist", "build"]);
+
+/**
+ * Module specifiers this file really depends on: static import/export,
+ * `import()`, `require()`, and `import("x")` type nodes. A bare string that
+ * happens to sit next to the word `from` is not one of them.
+ *
+ * `vi.mock("...")` is deliberately excluded. It names a module without
+ * importing it, so a component whose only remaining mention is a test mock is
+ * dead — counting it would let a component outlive its last real use.
+ */
+function importedSpecifiers(sourceText, filePath) {
+ const source = ts.createSourceFile(filePath, sourceText, ts.ScriptTarget.Latest, true);
+ const specifiers = new Set();
+
+ const visit = (node) => {
+ if (
+ (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) &&
+ node.moduleSpecifier &&
+ ts.isStringLiteral(node.moduleSpecifier)
+ ) {
+ specifiers.add(node.moduleSpecifier.text);
+ } else if (
+ ts.isCallExpression(node) &&
+ (node.expression.kind === ts.SyntaxKind.ImportKeyword ||
+ (ts.isIdentifier(node.expression) && node.expression.text === "require")) &&
+ node.arguments.length > 0 &&
+ ts.isStringLiteral(node.arguments[0])
+ ) {
+ specifiers.add(node.arguments[0].text);
+ } else if (
+ ts.isImportTypeNode(node) &&
+ ts.isLiteralTypeNode(node.argument) &&
+ ts.isStringLiteral(node.argument.literal)
+ ) {
+ specifiers.add(node.argument.literal.text);
+ }
+ ts.forEachChild(node, visit);
+ };
+
+ visit(source);
+ return specifiers;
+}
+
+function walk(dir, out = []) {
+ for (const dirent of readdirSync(dir, { withFileTypes: true })) {
+ if (dirent.name.startsWith(".")) continue;
+ const full = join(dir, dirent.name);
+ if (dirent.isDirectory()) {
+ if (!SKIP_DIRS.has(dirent.name)) walk(full, out);
+ } else if (SOURCE_EXTENSIONS.some((ext) => dirent.name.endsWith(ext))) {
+ out.push(full);
+ }
+ }
+ return out;
+}
+
+/** Every on-disk path a specifier could mean, extensionless forms included. */
+function resolutionCandidates(base) {
+ return [base, ...SOURCE_EXTENSIONS.flatMap((ext) => [`${base}${ext}`, join(base, `index${ext}`)])];
+}
+
+const manifest = JSON.parse(readFileSync(join(uiRoot, "package.json"), "utf8"));
+const exportEntries = Object.entries(manifest.exports ?? {});
+
+// Derived from the manifest rather than hard-coded: narrow a wildcard export
+// and this check narrows with it instead of going quietly stale.
+const wildcards = exportEntries
+ .filter(([subpath, target]) => subpath.includes("*") && String(target).includes("*"))
+ .map(([subpath, target]) => {
+ const targetPath = String(target).replace(/^\.\//, "");
+ return {
+ dir: targetPath.slice(0, targetPath.lastIndexOf("/")),
+ extension: targetPath.slice(targetPath.lastIndexOf("*") + 1),
+ prefix: subpath.replace(/^\.\//, "").replace("*", ""),
+ };
+ });
+
+if (wildcards.length === 0) {
+ console.log("No wildcard exports in packages/ui — knip covers this workspace on its own.");
+ process.exit(0);
+}
+
+// A file named by a non-wildcard export is an entry point in its own right, so
+// it is exempt. This is what makes the remedy the failure message suggests
+// actually work.
+const exactExportTargets = new Set(
+ exportEntries
+ .filter(([subpath, target]) => !subpath.includes("*") && !String(target).includes("*"))
+ .map(([, target]) => join(uiRoot, String(target).replace(/^\.\//, ""))),
+);
+
+const guarded = new Set();
+for (const { dir, extension } of wildcards) {
+ let entries;
+ try {
+ entries = readdirSync(join(uiRoot, dir));
+ } catch {
+ continue; // Exported directory does not exist yet.
+ }
+ for (const entry of entries) {
+ if (!entry.endsWith(extension)) continue;
+ const file = join(uiRoot, dir, entry);
+ if (statSync(file).isFile() && !exactExportTargets.has(file)) guarded.add(file);
+ }
+}
+
+const sourceFiles = walk(repoRoot);
+const known = new Set(sourceFiles);
+
+/** Resolve one specifier from one importer to a guarded file, or null. */
+function resolveSpecifier(specifier, importer) {
+ let base;
+ if (specifier.startsWith(".")) {
+ base = resolve(dirname(importer), specifier);
+ } else if (specifier === pkgName || specifier.startsWith(`${pkgName}/`)) {
+ const subpath = specifier.slice(pkgName.length + 1);
+ const wildcard = wildcards.find((w) => subpath.startsWith(w.prefix) && w.prefix !== "");
+ if (!wildcard) return null;
+ base = join(uiRoot, wildcard.dir, subpath.slice(wildcard.prefix.length));
+ } else {
+ return null; // A bare external package.
+ }
+ for (const candidate of resolutionCandidates(base)) {
+ if (known.has(candidate)) return candidate;
+ }
+ return null;
+}
+
+// Reachability: roots are everything outside the guarded set, so a guarded file
+// counts as live only when the walk actually arrives at it.
+const imports = new Map();
+for (const file of sourceFiles) {
+ const found = new Set();
+ for (const specifier of importedSpecifiers(readFileSync(file, "utf8"), file)) {
+ const target = resolveSpecifier(specifier, file);
+ if (target !== null) found.add(target);
+ }
+ imports.set(file, found);
+}
+
+const reached = new Set();
+const queue = sourceFiles.filter((file) => !guarded.has(file));
+while (queue.length > 0) {
+ for (const target of imports.get(queue.pop()) ?? []) {
+ if (!reached.has(target)) {
+ reached.add(target);
+ queue.push(target);
+ }
+ }
+}
+
+const dead = [...guarded]
+ .filter((file) => !reached.has(file))
+ .map((file) => relative(repoRoot, file).split(sep).join("/"))
+ .sort();
+
+if (dead.length > 0) {
+ console.error(`Unused files in packages/ui wildcard exports (${dead.length})`);
+ for (const file of dead) console.error(` ${file}`);
+ console.error(
+ "\nNothing imports these. Delete them — shadcn components come back with" +
+ "\n`pnpm ui:add `. If a file is genuinely entry-like, give it a" +
+ "\nnon-wildcard entry in packages/ui/package.json `exports`.",
+ );
+ process.exit(1);
+}
+
+console.log(
+ `packages/ui wildcard exports clean (${guarded.size} files under ` +
+ `${wildcards.map((w) => w.dir).join(", ")}).`,
+);
diff --git a/scripts/check-ui-wildcard-exports.test.sh b/scripts/check-ui-wildcard-exports.test.sh
new file mode 100755
index 000000000..bc16b44fe
--- /dev/null
+++ b/scripts/check-ui-wildcard-exports.test.sh
@@ -0,0 +1,128 @@
+#!/usr/bin/env bash
+# Proves check-ui-wildcard-exports.mjs actually fails on the cases it exists for.
+#
+# The check guards a blind spot that is invisible by construction: a component
+# under a wildcard export registers as a knip entry point, so knip reports it
+# as used no matter what. A guard for an invisible failure is worth exactly as
+# much as its proof that it still fires, hence this test.
+set -euo pipefail
+
+root_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
+check="$root_dir/scripts/check-ui-wildcard-exports.mjs"
+ui_dir="$root_dir/packages/ui/components/ui"
+out="$(mktemp)"
+scratch=()
+
+cleanup() {
+ rm -f "${scratch[@]+"${scratch[@]}"}" "$out"
+}
+trap cleanup EXIT
+
+track() {
+ scratch+=("$1")
+}
+
+fail() {
+ echo "FAIL: $*" >&2
+ echo "Observed:" >&2
+ cat "$out" >&2
+ exit 1
+}
+
+expect_pass() {
+ if ! node "$check" >"$out" 2>&1; then fail "$1"; fi
+}
+
+expect_fail_naming() {
+ if node "$check" >"$out" 2>&1; then fail "$2"; fi
+ if ! grep -Fq "$1" "$out"; then fail "check failed but did not name $1"; fi
+}
+
+# 1. Clean tree passes. Runs first so a pre-existing dead file is reported as
+# itself rather than surfacing later as a confusing probe failure.
+expect_pass "check should pass on a clean tree"
+
+# 2. A component nothing imports fails the check and is named.
+probe="$ui_dir/zz-unused-export-probe.tsx"
+track "$probe"
+cat >"$probe" <<'EOF'
+export function UnusedExportProbe() {
+ return null
+}
+EOF
+expect_fail_naming "zz-unused-export-probe.tsx" \
+ "check should fail when packages/ui gains a zero-reference component"
+
+# 3. Importing it from a consumer clears the check — the guard tracks real
+# usage rather than just counting files.
+importer="$root_dir/packages/views/zz-probe-importer.tsx"
+track "$importer"
+cat >"$importer" <<'EOF'
+export { UnusedExportProbe } from "@multica/ui/components/ui/zz-unused-export-probe";
+EOF
+expect_pass "check should pass once a consumer imports the component"
+rm -f "$importer" "$probe"
+
+# 4. Basename collision. 17 of the 59 guarded files share a name with some
+# other file in the repo, so a check that matched relative imports by
+# basename would pass this dead component. `option-card` is real:
+# packages/views/onboarding/components/option-card.tsx is imported as
+# `../components/option-card` and must not vouch for the packages/ui file.
+collide="$ui_dir/option-card.tsx"
+track "$collide"
+cat >"$collide" <<'EOF'
+export function OptionCard() {
+ return null
+}
+EOF
+expect_fail_naming "components/ui/option-card.tsx" \
+ "a same-named file elsewhere must not mark a dead ui component as used"
+rm -f "$collide"
+
+# 5. Two dead components importing only each other are still dead. Liveness is
+# reachability from outside the guarded directories, not a reference count.
+pair_a="$ui_dir/zz-cycle-a.tsx"
+pair_b="$ui_dir/zz-cycle-b.tsx"
+track "$pair_a"
+track "$pair_b"
+cat >"$pair_a" <<'EOF'
+import { CycleB } from "./zz-cycle-b";
+export function CycleA() {
+ return CycleB();
+}
+EOF
+cat >"$pair_b" <<'EOF'
+export function CycleB() {
+ return null;
+}
+EOF
+expect_fail_naming "zz-cycle-a.tsx" "a mutually-importing dead pair must not vouch for itself"
+if ! grep -Fq "zz-cycle-b.tsx" "$out"; then
+ fail "both halves of a dead import cycle should be reported"
+fi
+rm -f "$pair_a" "$pair_b"
+
+# 6. A commented-out import is not an edge. This is the state a component
+# passes through the moment its last real importer is deleted, so a text
+# scan would keep vouching for it exactly when it stops being used.
+comment_probe="$ui_dir/zz-comment-probe.tsx"
+mention="$root_dir/packages/views/zz-probe-mention.ts"
+track "$comment_probe"
+track "$mention"
+cat >"$comment_probe" <<'EOF'
+export function CommentProbe() {
+ return null
+}
+EOF
+cat >"$mention" <<'EOF'
+// import { CommentProbe } from "@multica/ui/components/ui/zz-comment-probe";
+const note = 'import { CommentProbe } from "@multica/ui/components/ui/zz-comment-probe"';
+export const probeNote = note;
+EOF
+expect_fail_naming "zz-comment-probe.tsx" \
+ "a commented-out or stringified import must not count as a real edge"
+rm -f "$comment_probe" "$mention"
+
+expect_pass "check should pass again once every probe is removed"
+
+echo "PASS: check-ui-wildcard-exports parses real imports, survives name collisions, dead cycles, and commented-out imports"