Skip to content

React Review Audit #7

Description

@react-doctor

Score: 73/100 · 2 errors · 178 warnings

Copy as prompt
Fix the following React Review diagnostics in my codebase.

## Errors (2)

1. [error] effect-needs-cleanup — src/lib/hooks/use-has-primary-touch.tsx:6
   useEffect subscribes via `addEventListener(...)` but never returns a cleanup — leaks the registration on every re-run and on unmount. Return a cleanup function that calls the matching remove/unsubscribe call

2. [error] effect-needs-cleanup — src/components/ui/scroll-area.tsx:75
   useEffect subscribes via `addEventListener(...)` but never returns a cleanup — leaks the registration on every re-run and on unmount. Return a cleanup function that calls the matching remove/unsubscribe call

## Warnings (178)

3. [warning] no-react19-deprecated-apis — src/components/spinner.tsx:7
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

4. [warning] use-lazy-motion — src/components/spaces/settings-dialog.tsx:11
   Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size

5. [warning] no-prevent-default — src/components/spaces/settings-dialog.tsx:116
   preventDefault() on <form> onSubmit — form won't work without JavaScript. Consider using a server action for progressive enhancement

6. [warning] react-compiler-destructure-method — src/components/spaces/settings-dialog.tsx:360
   Destructure for clarity: `const { push } = useRouter()` then call `push(...)` directly — easier for React Compiler to memoize and clearer about which methods this component depends on

7. [warning] design-no-redundant-padding-axes — src/app/(auth)/sign-in/page.tsx:50
   px-4 py-4 → use the shorthand p-4

8. [warning] design-no-three-period-ellipsis — src/components/chat/tools/knowledge-search-tool.tsx:170
   Three-period ellipsis ("...") in JSX text — use the actual ellipsis character "…" (or `&hellip;`)

9. [warning] no-prevent-default — src/components/spaces/knowledge-table.tsx:172
   preventDefault() on <form> onSubmit — form won't work without JavaScript. Consider using a server action for progressive enhancement

10. [warning] design-no-redundant-size-axes — src/components/spaces/knowledge-table.tsx:515
   w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)

11. [warning] design-no-redundant-size-axes — src/components/spaces/knowledge-table.tsx:532
   w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)

12. [warning] design-no-redundant-size-axes — src/components/spaces/knowledge-table.tsx:552
   w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)

13. [warning] design-no-redundant-size-axes — src/components/spaces/knowledge-table.tsx:565
   w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)

14. [warning] design-no-three-period-ellipsis — src/components/chat/tools/finance-search-tool.tsx:154
   Three-period ellipsis ("...") in JSX text — use the actual ellipsis character "…" (or `&hellip;`)

15. [warning] no-react19-deprecated-apis — src/components/ui/form.tsx:45
   useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`

16. [warning] no-react19-deprecated-apis — src/components/ui/form.tsx:46
   useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`

17. [warning] no-react19-deprecated-apis — src/components/ui/form.tsx:75
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

18. [warning] no-react19-deprecated-apis — src/components/ui/form.tsx:89
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

19. [warning] no-react19-deprecated-apis — src/components/ui/form.tsx:106
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

20. [warning] no-react19-deprecated-apis — src/components/ui/form.tsx:129
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

21. [warning] no-react19-deprecated-apis — src/components/ui/form.tsx:146
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

22. [warning] use-lazy-motion — src/components/spaces/knowledge-dialog.tsx:5
   Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size

23. [warning] async-await-in-loop — src/components/spaces/knowledge-dialog.tsx:129
   await inside a for…of loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently

24. [warning] no-pure-black-background — src/components/spaces/knowledge-dialog.tsx:249
   Pure black background (bg-black) looks harsh — use a near-black tinted toward your brand hue (e.g. bg-gray-950)

25. [warning] design-no-space-on-flex-children — src/components/spaces/knowledge-dialog.tsx:254
   space-y-6 on a flex/grid parent — use gap-y-6 instead. Per-sibling margins phantom-gap on conditional render and don't mirror in RTL

26. [warning] design-no-space-on-flex-children — src/components/spaces/knowledge-dialog.tsx:268
   space-y-6 on a flex/grid parent — use gap-y-6 instead. Per-sibling margins phantom-gap on conditional render and don't mirror in RTL

27. [warning] use-lazy-motion — src/components/spaces/header.tsx:9
   Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size

28. [warning] async-parallel — src/workflows/knowledge-process.ts:51
   3 sequential await statements that appear independent — use Promise.all() for parallel execution

29. [warning] design-no-three-period-ellipsis — src/components/chat/tools/academic-search-tool.tsx:178
   Three-period ellipsis ("...") in JSX text — use the actual ellipsis character "…" (or `&hellip;`)

30. [warning] use-lazy-motion — src/components/spaces/cards.tsx:4
   Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size

31. [warning] rerender-memo-with-default-value — src/components/chat/space-intro.tsx:22
   Default prop value [] creates a new array reference every render — extract to a module-level constant

32. [warning] design-no-bold-heading — src/components/chat/space-intro.tsx:35
   font-bold on <h1> crushes counter shapes at display sizes — use font-semibold (600) or font-medium (500)

33. [warning] use-lazy-motion — src/components/ui/disclosure.tsx:3
   Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size

34. [warning] no-react19-deprecated-apis — src/components/ui/disclosure.tsx:12
   useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`

35. [warning] no-derived-useState — src/components/ui/disclosure.tsx:38
   useState initialized from prop "openProp" — if this value should stay in sync with the prop, derive it during render instead

36. [warning] no-many-boolean-props — src/components/sidebar/chats-list.tsx:45
   Component "ChatItem" takes 4 boolean-like props (isActive, isConfirming, isPending…) — consider compound components or explicit variants instead of stacking flags

37. [warning] react-compiler-destructure-method — src/components/sidebar/chats-list.tsx:216
   Destructure for clarity: `const { replace } = useRouter()` then call `replace(...)` directly — easier for React Compiler to memoize and clearer about which methods this component depends on

38. [warning] design-no-redundant-padding-axes — src/components/sidebar/chats-list.tsx:320
   px-1 py-1 → use the shorthand p-1

39. [warning] design-no-redundant-padding-axes — src/components/sidebar/chats-list.tsx:334
   px-1 py-1 → use the shorthand p-1

40. [warning] design-no-redundant-padding-axes — src/components/sidebar/chats-list.tsx:336
   px-1 py-1 → use the shorthand p-1

41. [warning] design-no-three-period-ellipsis — src/components/sidebar/chats-list.tsx:338
   Three-period ellipsis ("...") in JSX text — use the actual ellipsis character "…" (or `&hellip;`)

42. [warning] design-no-three-period-ellipsis — src/components/sidebar/chats-list.tsx:370
   Three-period ellipsis ("...") in JSX text — use the actual ellipsis character "…" (or `&hellip;`)

43. [warning] use-lazy-motion — src/components/sidebar.tsx:11
   Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size

44. [warning] use-lazy-motion — src/components/chat/message.tsx:5
   Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size

45. [warning] no-array-index-as-key — src/components/chat/message.tsx:452
   Array index "index" used as key — causes bugs when list is reordered or filtered

46. [warning] no-array-index-as-key — src/components/chat/message.tsx:497
   Array index "index" used as key — causes bugs when list is reordered or filtered

47. [warning] no-array-index-as-key — src/components/chat/message.tsx:523
   Array index "index" used as key — causes bugs when list is reordered or filtered

48. [warning] no-array-index-as-key — src/components/chat/message.tsx:545
   Array index "index" used as key — causes bugs when list is reordered or filtered

49. [warning] no-render-in-render — src/components/chat/message.tsx:601
   Inline render function "renderAttachments()" — extract to a separate component for proper reconciliation

50. [warning] use-lazy-motion — src/components/chat/header.tsx:4
   Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size

51. [warning] use-lazy-motion — src/components/chat/display-chats.tsx:10
   Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size

52. [warning] design-no-redundant-size-axes — src/components/chat/display-chats.tsx:264
   w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)

53. [warning] use-lazy-motion — src/components/profile.tsx:5
   Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size

54. [warning] design-no-redundant-size-axes — src/components/profile.tsx:48
   w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)

55. [warning] rerender-state-only-in-handlers — src/components/profile.tsx:222
   useState "isHydrated" is updated but never read in the component's return — use useRef so updates don't trigger re-renders

56. [warning] rendering-hydration-no-flicker — src/components/profile.tsx:224
   useEffect(setState, []) on mount causes a flash — consider useSyncExternalStore or suppressHydrationWarning

57. [warning] react-compiler-destructure-method — src/components/profile.tsx:235
   Destructure for clarity: `const { push } = useRouter()` then call `push(...)` directly — easier for React Compiler to memoize and clearer about which methods this component depends on

58. [warning] react-compiler-destructure-method — src/components/profile.tsx:247
   Destructure for clarity: `const { push } = useRouter()` then call `push(...)` directly — easier for React Compiler to memoize and clearer about which methods this component depends on

59. [warning] react-compiler-destructure-method — src/components/profile.tsx:252
   Destructure for clarity: `const { push } = useRouter()` then call `push(...)` directly — easier for React Compiler to memoize and clearer about which methods this component depends on

60. [warning] no-react19-deprecated-apis — src/components/chat/code-block.tsx:5
   useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`

61. [warning] no-react19-deprecated-apis — src/components/ui/carousel.tsx:36
   useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`

62. [warning] no-prop-callback-in-effect — src/components/ui/carousel.tsx:97
   useEffect calls prop callback "setApi" with local state in deps — this is the "lift state via callback" anti-pattern; lift state into a shared Provider so both sides read the same source

63. [warning] advanced-event-handler-refs — src/components/ui/carousel.tsx:100
   useEffect re-subscribes a "onSelect" listener every time the handler identity changes — store the handler in a ref and have the listener read `handlerRef.current()`, then drop it from the deps

64. [warning] design-no-redundant-padding-axes — src/components/model-selector.tsx:272
   px-2 py-2 → use the shorthand p-2

65. [warning] rerender-state-only-in-handlers — src/components/chat.tsx:164
   useState "_hasOptimisticallyAdded" is updated but never read in the component's return — use useRef so updates don't trigger re-renders

66. [warning] no-giant-component — src/components/chat.tsx:53
   Component "Chat" is 355 lines — consider breaking it into smaller focused components

67. [warning] use-lazy-motion — src/components/mode-selector.tsx:4
   Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size

68. [warning] no-autofocus — src/components/chat-input.tsx:515
   The `autoFocus` attribute is found here, which can cause usability issues for sighted and non-sighted users.

69. [warning] use-lazy-motion — src/components/chat-input.tsx:13
   Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size

70. [warning] no-giant-component — src/components/chat-input.tsx:106
   Component "PureInput" is 513 lines — consider breaking it into smaller focused components

71. [warning] js-batch-dom-css — src/components/chat-input.tsx:147
   Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows

72. [warning] no-prop-callback-in-effect — src/components/chat-input.tsx:165
   useEffect calls prop callback "setInput" with local state in deps — this is the "lift state via callback" anti-pattern; lift state into a shared Provider so both sides read the same source

73. [warning] no-array-index-as-key — src/components/chat-input.tsx:481
   Array index "index" used as key — causes bugs when list is reordered or filtered

74. [warning] rendering-usetransition-loading — src/components/auth/sign-out-button.tsx:17
   useState for "isLoading" — if this guards a state transition (not an async fetch), consider useTransition instead

75. [warning] react-compiler-destructure-method — src/components/auth/sign-out-button.tsx:25
   Destructure for clarity: `const { push } = useRouter()` then call `push(...)` directly — easier for React Compiler to memoize and clearer about which methods this component depends on

76. [warning] use-lazy-motion — src/components/ui/border-trail.tsx:2
   Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size

77. [warning] no-permanent-will-change — src/components/ui/border-trail.tsx:40
   Permanent will-change wastes GPU memory — apply only during active animation and remove after

78. [warning] rendering-usetransition-loading — src/components/auth/sign-in-button.tsx:21
   useState for "isLoading" — if this guards a state transition (not an async fetch), consider useTransition instead

79. [warning] no-react19-deprecated-apis — src/components/ui/avatar.tsx:8
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

80. [warning] no-render-in-render — src/components/mcp-server-config.tsx:236
   Inline render function "renderStatusBadge()" — extract to a separate component for proper reconciliation

81. [warning] design-no-space-on-flex-children — src/components/mcp-server-config.tsx:239
   space-x-2 on a flex/grid parent — use gap-x-2 instead. Per-sibling margins phantom-gap on conditional render and don't mirror in RTL

82. [warning] no-prevent-default — src/components/mcp-server-config.tsx:429
   preventDefault() on <form> onSubmit — form won't work without JavaScript. Consider using a server action for progressive enhancement

83. [warning] design-no-space-on-flex-children — src/components/display-memories.tsx:125
   space-x-2 on a flex/grid parent — use gap-x-2 instead. Per-sibling margins phantom-gap on conditional render and don't mirror in RTL

84. [warning] design-no-redundant-size-axes — src/components/display-memories.tsx:127
   w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)

85. [warning] design-no-space-on-flex-children — src/components/display-memories.tsx:280
   space-x-2 on a flex/grid parent — use gap-x-2 instead. Per-sibling margins phantom-gap on conditional render and don't mirror in RTL

86. [warning] use-lazy-motion — src/components/ui/accordion.tsx:2
   Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size

87. [warning] no-react19-deprecated-apis — src/components/ui/accordion.tsx:13
   useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`

88. [warning] no-react19-deprecated-apis — src/components/ai-elements/inline-citation.tsx:8
   useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`

89. [warning] no-cascading-set-state — src/components/ai-elements/inline-citation.tsx:180
   3 setState calls in a single useEffect — consider using useReducer or deriving state

90. [warning] no-generic-handler-names — src/components/ai-elements/inline-citation.tsx:230
   Non-descriptive handler name "handleClick" — name should describe what it does, not when it runs

91. [warning] no-generic-handler-names — src/components/ai-elements/inline-citation.tsx:257
   Non-descriptive handler name "handleClick" — name should describe what it does, not when it runs

92. [warning] no-react19-deprecated-apis — src/components/data-stream-provider.tsx:5
   useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`

93. [warning] js-combine-iterations — src/components/ai-elements/conversation.tsx:131
   .filter().map() iterates the array twice — combine into a single loop with .reduce() or for...of

94. [warning] no-react19-deprecated-apis — src/components/copy-button.tsx:6
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

95. [warning] no-react19-deprecated-apis — src/components/ai-elements/attachments.tsx:6
   useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`

96. [warning] js-combine-iterations — src/components/chat/tools/web-search-tool.tsx:61
   .filter().map() iterates the array twice — combine into a single loop with .reduce() or for...of

97. [warning] js-combine-iterations — src/components/chat/tools/web-search-tool.tsx:61
   .flatMap().filter() iterates the array twice — combine into a single loop with .reduce() or for...of

98. [warning] design-no-three-period-ellipsis — src/components/chat/tools/web-search-tool.tsx:241
   Three-period ellipsis ("...") in JSX text — use the actual ellipsis character "…" (or `&hellip;`)

99. [warning] design-no-three-period-ellipsis — src/components/chat/tools/save-to-memories.tsx:35
   Three-period ellipsis ("...") in JSX text — use the actual ellipsis character "…" (or `&hellip;`)

100. [warning] nextjs-missing-metadata — src/app/(main)/(chat)/c/page.tsx:1
   Page without metadata or generateMetadata export — hurts SEO

101. [warning] js-combine-iterations — src/app/api/chat/_lib/tools.ts:53
   .filter().map() iterates the array twice — combine into a single loop with .reduce() or for...of

102. [warning] no-react19-deprecated-apis — src/lib/mobile-header-context.tsx:8
   useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`

103. [warning] no-derived-state-effect — src/lib/mobile-header-context.tsx:51
   Derived state in useEffect — compute during render instead

104. [warning] nextjs-missing-metadata — src/app/(main)/(chat)/c/[id]/page.tsx:1
   Page without metadata or generateMetadata export — hurts SEO

105. [warning] server-sequential-independent-await — src/app/(main)/(chat)/c/[id]/page.tsx:15
   Sequential `await` without a data dependency on the previous result — wrap the independent calls in `Promise.all([...])` so they race instead of waterfalling

106. [warning] server-sequential-independent-await — src/app/(main)/(chat)/c/[id]/page.tsx:20
   Sequential `await` without a data dependency on the previous result — wrap the independent calls in `Promise.all([...])` so they race instead of waterfalling

107. [warning] async-parallel — src/app/(main)/(chat)/c/[id]/page.tsx:13
   4 sequential await statements that appear independent — use Promise.all() for parallel execution

108. [warning] js-combine-iterations — src/lib/ai/utils.ts:44
   .filter().map() iterates the array twice — combine into a single loop with .reduce() or for...of

109. [warning] nextjs-missing-metadata — src/app/(main)/page.tsx:1
   Page without metadata or generateMetadata export — hurts SEO

110. [warning] async-parallel — src/app/api/chat/_lib/resumable-stream.ts:28
   3 sequential await statements that appear independent — use Promise.all() for parallel execution

111. [warning] js-combine-iterations — src/app/api/chat/_lib/request-logger.ts:42
   .filter().map() iterates the array twice — combine into a single loop with .reduce() or for...of

112. [warning] async-await-in-loop — src/lib/ai/tools/web-search.ts:69
   Async callback in .map — sequential awaits inside the callback waterfall. Use `await Promise.all(items.map(async (item) => {...}))` to run them concurrently

113. [warning] async-await-in-loop — src/lib/mcp/client.ts:135
   await inside a for…of loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently

114. [warning] async-await-in-loop — src/lib/mcp/client.ts:178
   await inside a for…of loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently

115. [warning] async-await-in-loop — src/lib/mcp/client.ts:196
   await inside a for…of loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently

116. [warning] async-await-in-loop — src/lib/mcp/client.ts:225
   await inside a for…of loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently

117. [warning] nextjs-missing-metadata — src/app/(main)/(spaces)/s/page.tsx:1
   Page without metadata or generateMetadata export — hurts SEO

118. [warning] server-sequential-independent-await — src/app/(main)/(spaces)/s/page.tsx:9
   Sequential `await` without a data dependency on the previous result — wrap the independent calls in `Promise.all([...])` so they race instead of waterfalling

119. [warning] async-await-in-loop — src/lib/ai/tools/save-to-memories.ts:53
   await inside a for-loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently

120. [warning] nextjs-missing-metadata — src/app/(main)/(spaces)/s/[id]/page.tsx:1
   Page without metadata or generateMetadata export — hurts SEO

121. [warning] server-sequential-independent-await — src/app/(main)/(spaces)/s/[id]/page.tsx:13
   Sequential `await` without a data dependency on the previous result — wrap the independent calls in `Promise.all([...])` so they race instead of waterfalling

122. [warning] server-sequential-independent-await — src/app/(main)/(spaces)/s/[id]/page.tsx:19
   Sequential `await` without a data dependency on the previous result — wrap the independent calls in `Promise.all([...])` so they race instead of waterfalling

123. [warning] async-await-in-loop — src/lib/ai/embedding.ts:68
   await inside a for-loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently

124. [warning] async-await-in-loop — src/lib/ai/tools/knowledge-search.ts:57
   Async callback in .map — sequential awaits inside the callback waterfall. Use `await Promise.all(items.map(async (item) => {...}))` to run them concurrently

125. [warning] async-await-in-loop — src/lib/ai/tools/finance-search.ts:41
   Async callback in .map — sequential awaits inside the callback waterfall. Use `await Promise.all(items.map(async (item) => {...}))` to run them concurrently

126. [warning] no-react19-deprecated-apis — src/components/ui/tooltip.tsx:15
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

127. [warning] client-passive-event-listeners — src/lib/hooks/use-click-outside.ts:17
   "touchstart" listener without { passive: true } — blocks scrolling performance. Only add { passive: true } if the handler does NOT call event.preventDefault() (passive listeners silently ignore preventDefault())

128. [warning] no-react19-deprecated-apis — src/components/ui/toggle-group.tsx:51
   useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`

129. [warning] use-lazy-motion — src/components/ui/theme-toggle.tsx:6
   Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size

130. [warning] rendering-hydration-no-flicker — src/components/ui/theme-toggle.tsx:32
   useEffect(setState, []) on mount causes a flash — consider useSyncExternalStore or suppressHydrationWarning

131. [warning] js-combine-iterations — src/lib/ai/mistral-ocr.ts:36
   .map().filter() iterates the array twice — combine into a single loop with .reduce() or for...of

132. [warning] use-lazy-motion — src/components/ui/text-loop.tsx:2
   Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size

133. [warning] no-permanent-will-change — src/components/ui/text-loop.tsx:68
   Permanent will-change wastes GPU memory — apply only during active animation and remove after

134. [warning] use-lazy-motion — src/components/ui/text-shimmer.tsx:2
   Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size

135. [warning] use-lazy-motion — src/components/ui/text-effect.tsx:3
   Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size

136. [warning] no-array-index-as-key — src/components/ui/text-effect.tsx:315
   Array index "index" used as key — causes bugs when list is reordered or filtered

137. [warning] no-react19-deprecated-apis — src/components/ui/sidebar.tsx:48
   useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`

138. [warning] no-react19-deprecated-apis — src/components/ui/sidebar.tsx:56
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

139. [warning] no-react19-deprecated-apis — src/components/ui/sidebar.tsx:166
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

140. [warning] no-react19-deprecated-apis — src/components/ui/sidebar.tsx:279
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

141. [warning] no-react19-deprecated-apis — src/components/ui/sidebar.tsx:305
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

142. [warning] no-react19-deprecated-apis — src/components/ui/sidebar.tsx:334
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

143. [warning] no-react19-deprecated-apis — src/components/ui/sidebar.tsx:352
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

144. [warning] no-react19-deprecated-apis — src/components/ui/sidebar.tsx:370
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

145. [warning] no-react19-deprecated-apis — src/components/ui/sidebar.tsx:385
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

146. [warning] no-react19-deprecated-apis — src/components/ui/sidebar.tsx:400
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

147. [warning] no-react19-deprecated-apis — src/components/ui/sidebar.tsx:418
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

148. [warning] no-react19-deprecated-apis — src/components/ui/sidebar.tsx:436
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

149. [warning] no-react19-deprecated-apis — src/components/ui/sidebar.tsx:454
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

150. [warning] no-react19-deprecated-apis — src/components/ui/sidebar.tsx:475
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

151. [warning] no-react19-deprecated-apis — src/components/ui/sidebar.tsx:498
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

152. [warning] no-react19-deprecated-apis — src/components/ui/sidebar.tsx:511
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

153. [warning] no-react19-deprecated-apis — src/components/ui/sidebar.tsx:524
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

154. [warning] no-react19-deprecated-apis — src/components/ui/sidebar.tsx:560
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

155. [warning] no-react19-deprecated-apis — src/components/ui/sidebar.tsx:622
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

156. [warning] no-react19-deprecated-apis — src/components/ui/sidebar.tsx:653
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

157. [warning] no-react19-deprecated-apis — src/components/ui/sidebar.tsx:674
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

158. [warning] no-react19-deprecated-apis — src/components/ui/sidebar.tsx:715
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

159. [warning] no-react19-deprecated-apis — src/components/ui/sidebar.tsx:732
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

160. [warning] no-react19-deprecated-apis — src/components/ui/sidebar.tsx:738
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

161. [warning] async-parallel — src/lib/db/queries.ts:181
   3 sequential await statements that appear independent — use Promise.all() for parallel execution

162. [warning] no-react19-deprecated-apis — src/components/ui/popover.tsx:15
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

163. [warning] no-react19-deprecated-apis — src/components/ui/sheet.tsx:19
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

164. [warning] no-react19-deprecated-apis — src/components/ui/sheet.tsx:55
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

165. [warning] design-no-redundant-size-axes — src/components/ui/sheet.tsx:67
   w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)

166. [warning] no-react19-deprecated-apis — src/components/ui/sheet.tsx:104
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

167. [warning] no-react19-deprecated-apis — src/components/ui/sheet.tsx:116
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

168. [warning] use-lazy-motion — src/components/ui/morphing-dialog.tsx:7
   Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size

169. [warning] no-react19-deprecated-apis — src/components/ui/morphing-dialog.tsx:16
   useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`

170. [warning] no-generic-handler-names — src/components/ui/morphing-dialog.tsx:131
   Non-descriptive handler name "handleClick" — name should describe what it does, not when it runs

171. [warning] no-effect-event-handler — src/components/ui/morphing-dialog.tsx:196
   useEffect simulating an event handler — move logic to an actual event handler instead

172. [warning] no-permanent-will-change — src/components/ui/morphing-dialog.tsx:234
   Permanent will-change wastes GPU memory — apply only during active animation and remove after

173. [warning] no-permanent-will-change — src/components/ui/morphing-dialog.tsx:301
   Permanent will-change wastes GPU memory — apply only during active animation and remove after

174. [warning] no-permanent-will-change — src/components/ui/morphing-dialog.tsx:334
   Permanent will-change wastes GPU memory — apply only during active animation and remove after

175. [warning] no-permanent-will-change — src/components/ui/morphing-dialog.tsx:388
   Permanent will-change wastes GPU memory — apply only during active animation and remove after

176. [warning] no-react19-deprecated-apis — src/components/ui/scroll-area.tsx:18
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

177. [warning] advanced-event-handler-refs — src/components/ui/scroll-area.tsx:75
   useEffect re-subscribes a "checkScrollability" listener every time the handler identity changes — store the handler in a ref and have the listener read `handlerRef.current()`, then drop it from the deps

178. [warning] client-passive-event-listeners — src/components/ui/scroll-area.tsx:91
   "scroll" listener without { passive: true } — blocks scrolling performance. Only add { passive: true } if the handler does NOT call event.preventDefault() (passive listeners silently ignore preventDefault())

179. [warning] no-react19-deprecated-apis — src/components/ui/scroll-area.tsx:170
   forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

180. [warning] no-react19-deprecated-apis — src/components/ui/scroll-area.tsx:176
   useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`

❌ Errors (2)

effect-needs-cleanup

useEffect subscribes via addEventListener(...) but never returns a cleanup — leaks the registration on every re-run and on unmount. Return a cleanup function that calls the matching remove/unsubscribe call

Return a cleanup function that releases the subscription / timer: return () =&gt; target.removeEventListener(name, handler) for listeners, return () =&gt; clearInterval(id) / clearTimeout(id) for timers, or return unsubscribe if the subscribe call already returned one

src/lib/hooks/use-has-primary-touch.tsx:6
src/components/ui/scroll-area.tsx:75


⚠️ Warnings (178)

no-react19-deprecated-apis

forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly

Pass ref as a regular prop on function components — forwardRef is no longer needed in React 19+. Replace useContext(X) with use(X) for branch-aware context reads. Only enabled on projects detected as React 19+.

src/components/spinner.tsx:7
src/components/ui/form.tsx:45
src/components/ui/form.tsx:46
src/components/ui/form.tsx:75
src/components/ui/form.tsx:89
src/components/ui/form.tsx:106
src/components/ui/form.tsx:129
src/components/ui/form.tsx:146
src/components/ui/disclosure.tsx:12
src/components/chat/code-block.tsx:5
src/components/ui/carousel.tsx:36
src/components/ui/avatar.tsx:8
src/components/ui/accordion.tsx:13
src/components/ai-elements/inline-citation.tsx:8
src/components/data-stream-provider.tsx:5
src/components/copy-button.tsx:6
src/components/ai-elements/attachments.tsx:6
src/lib/mobile-header-context.tsx:8
src/components/ui/tooltip.tsx:15
src/components/ui/toggle-group.tsx:51
src/components/ui/sidebar.tsx:48
src/components/ui/sidebar.tsx:56
src/components/ui/sidebar.tsx:166
src/components/ui/sidebar.tsx:279
src/components/ui/sidebar.tsx:305
src/components/ui/sidebar.tsx:334
src/components/ui/sidebar.tsx:352
src/components/ui/sidebar.tsx:370
src/components/ui/sidebar.tsx:385
src/components/ui/sidebar.tsx:400
src/components/ui/sidebar.tsx:418
src/components/ui/sidebar.tsx:436
src/components/ui/sidebar.tsx:454
src/components/ui/sidebar.tsx:475
src/components/ui/sidebar.tsx:498
src/components/ui/sidebar.tsx:511
src/components/ui/sidebar.tsx:524
src/components/ui/sidebar.tsx:560
src/components/ui/sidebar.tsx:622
src/components/ui/sidebar.tsx:653
src/components/ui/sidebar.tsx:674
src/components/ui/sidebar.tsx:715
src/components/ui/sidebar.tsx:732
src/components/ui/sidebar.tsx:738
src/components/ui/popover.tsx:15
src/components/ui/sheet.tsx:19
src/components/ui/sheet.tsx:55
src/components/ui/sheet.tsx:104
src/components/ui/sheet.tsx:116
src/components/ui/morphing-dialog.tsx:16
src/components/ui/scroll-area.tsx:18
src/components/ui/scroll-area.tsx:170
src/components/ui/scroll-area.tsx:176

use-lazy-motion

Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size

Use import { LazyMotion, m } from "framer-motion" with domAnimation features — saves ~30kb

src/components/spaces/settings-dialog.tsx:11
src/components/spaces/knowledge-dialog.tsx:5
src/components/spaces/header.tsx:9
src/components/spaces/cards.tsx:4
src/components/ui/disclosure.tsx:3
src/components/sidebar.tsx:11
src/components/chat/message.tsx:5
src/components/chat/header.tsx:4
src/components/chat/display-chats.tsx:10
src/components/profile.tsx:5
src/components/mode-selector.tsx:4
src/components/chat-input.tsx:13
src/components/ui/border-trail.tsx:2
src/components/ui/accordion.tsx:2
src/components/ui/theme-toggle.tsx:6
src/components/ui/text-loop.tsx:2
src/components/ui/text-shimmer.tsx:2
src/components/ui/text-effect.tsx:3
src/components/ui/morphing-dialog.tsx:7

async-await-in-loop

await inside a for…of loop runs the calls sequentially — for independent operations, collect them and use await Promise.all(items.map(...)) to run them concurrently

Collect the items and use await Promise.all(items.map(...)) to run independent operations concurrently

src/components/spaces/knowledge-dialog.tsx:129
src/lib/ai/tools/web-search.ts:69
src/lib/mcp/client.ts:135
src/lib/mcp/client.ts:178
src/lib/mcp/client.ts:196
src/lib/mcp/client.ts:225
src/lib/ai/tools/save-to-memories.ts:53
src/lib/ai/embedding.ts:68
src/lib/ai/tools/knowledge-search.ts:57
src/lib/ai/tools/finance-search.ts:41

design-no-redundant-size-axes

w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)

Collapse w-N h-N to size-N (Tailwind v3.4+) when both axes match

src/components/spaces/knowledge-table.tsx:515
src/components/spaces/knowledge-table.tsx:532
src/components/spaces/knowledge-table.tsx:552
src/components/spaces/knowledge-table.tsx:565
src/components/chat/display-chats.tsx:264
src/components/profile.tsx:48
src/components/display-memories.tsx:127
src/components/ui/sheet.tsx:67

design-no-three-period-ellipsis

Three-period ellipsis ("...") in JSX text — use the actual ellipsis character "…" (or &hellip;)

Use the typographic ellipsis "…" (or &hellip;) instead of three periods — pairs with action-with-followup labels ("Rename…", "Loading…")

src/components/chat/tools/knowledge-search-tool.tsx:170
src/components/chat/tools/finance-search-tool.tsx:154
src/components/chat/tools/academic-search-tool.tsx:178
src/components/sidebar/chats-list.tsx:338
src/components/sidebar/chats-list.tsx:370
src/components/chat/tools/web-search-tool.tsx:241
src/components/chat/tools/save-to-memories.tsx:35

js-combine-iterations

.filter().map() iterates the array twice — combine into a single loop with .reduce() or for...of

Combine .map().filter() (or similar chains) into a single pass with .reduce() or a for...of loop to avoid iterating the array twice

src/components/ai-elements/conversation.tsx:131
src/components/chat/tools/web-search-tool.tsx:61
src/components/chat/tools/web-search-tool.tsx:61
src/app/api/chat/_lib/tools.ts:53
src/lib/ai/utils.ts:44
src/app/api/chat/_lib/request-logger.ts:42
src/lib/ai/mistral-ocr.ts:36

react-compiler-destructure-method

Destructure for clarity: const { push } = useRouter() then call push(...) directly — easier for React Compiler to memoize and clearer about which methods this component depends on

Destructure the method up front: const { push } = useRouter() then call push(...) directly — clearer dependency graph and easier for React Compiler to memoize

src/components/spaces/settings-dialog.tsx:360
src/components/sidebar/chats-list.tsx:216
src/components/profile.tsx:235
src/components/profile.tsx:247
src/components/profile.tsx:252
src/components/auth/sign-out-button.tsx:25

no-array-index-as-key

Array index "index" used as key — causes bugs when list is reordered or filtered

Use a stable unique identifier: key={item.id} or key={item.slug} — index keys break on reorder/filter

src/components/chat/message.tsx:452
src/components/chat/message.tsx:497
src/components/chat/message.tsx:523
src/components/chat/message.tsx:545
src/components/chat-input.tsx:481
src/components/ui/text-effect.tsx:315

no-permanent-will-change

Permanent will-change wastes GPU memory — apply only during active animation and remove after

Add will-change on animation start (onMouseEnter) and remove on end (onAnimationEnd). Permanent promotion wastes GPU memory and can degrade performance

src/components/ui/border-trail.tsx:40
src/components/ui/text-loop.tsx:68
src/components/ui/morphing-dialog.tsx:234
src/components/ui/morphing-dialog.tsx:301
src/components/ui/morphing-dialog.tsx:334
src/components/ui/morphing-dialog.tsx:388

design-no-redundant-padding-axes

px-4 py-4 → use the shorthand p-4

Collapse px-N py-N to p-N when both axes match. Keep them split only when one axis varies at a breakpoint (py-2 md:py-3)

src/app/(auth)/sign-in/page.tsx:50
src/components/sidebar/chats-list.tsx:320
src/components/sidebar/chats-list.tsx:334
src/components/sidebar/chats-list.tsx:336
src/components/model-selector.tsx:272

design-no-space-on-flex-children

space-y-6 on a flex/grid parent — use gap-y-6 instead. Per-sibling margins phantom-gap on conditional render and don't mirror in RTL

Use gap-* on the flex/grid parent. space-x-* / space-y-* produce phantom gaps when a sibling is conditionally rendered, lose vertical spacing on wrapped lines, and don't mirror in RTL

src/components/spaces/knowledge-dialog.tsx:254
src/components/spaces/knowledge-dialog.tsx:268
src/components/mcp-server-config.tsx:239
src/components/display-memories.tsx:125
src/components/display-memories.tsx:280

nextjs-missing-metadata

Page without metadata or generateMetadata export — hurts SEO

Add export const metadata = { title: '...', description: '...' } or export async function generateMetadata()

src/app/(main)/(chat)/c/page.tsx:1
src/app/(main)/(chat)/c/[id]/page.tsx:1
src/app/(main)/page.tsx:1
src/app/(main)/(spaces)/s/page.tsx:1
src/app/(main)/(spaces)/s/[id]/page.tsx:1

server-sequential-independent-await

Sequential await without a data dependency on the previous result — wrap the independent calls in Promise.all([...]) so they race instead of waterfalling

Wrap independent awaits in Promise.all([...]) so they race instead of waterfalling — second call doesn't depend on the first

src/app/(main)/(chat)/c/[id]/page.tsx:15
src/app/(main)/(chat)/c/[id]/page.tsx:20
src/app/(main)/(spaces)/s/page.tsx:9
src/app/(main)/(spaces)/s/[id]/page.tsx:13
src/app/(main)/(spaces)/s/[id]/page.tsx:19

async-parallel

3 sequential await statements that appear independent — use Promise.all() for parallel execution

Use `const [a, b] = await Promise.all([fetchA(), fet


Issue body truncated. See the full report at react.review/dashboard.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions