@yuaone/core 0.3.3 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/dist/agent-loop.d.ts +62 -0
  2. package/dist/agent-loop.d.ts.map +1 -1
  3. package/dist/agent-loop.js +705 -18
  4. package/dist/agent-loop.js.map +1 -1
  5. package/dist/background-agent.d.ts +110 -0
  6. package/dist/background-agent.d.ts.map +1 -0
  7. package/dist/background-agent.js +255 -0
  8. package/dist/background-agent.js.map +1 -0
  9. package/dist/coding-standards.d.ts +45 -0
  10. package/dist/coding-standards.d.ts.map +1 -0
  11. package/dist/coding-standards.js +1152 -0
  12. package/dist/coding-standards.js.map +1 -0
  13. package/dist/constants.d.ts.map +1 -1
  14. package/dist/constants.js +2 -6
  15. package/dist/constants.js.map +1 -1
  16. package/dist/context-manager.d.ts +6 -0
  17. package/dist/context-manager.d.ts.map +1 -1
  18. package/dist/context-manager.js +23 -4
  19. package/dist/context-manager.js.map +1 -1
  20. package/dist/index.d.ts +28 -4
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +26 -2
  23. package/dist/index.js.map +1 -1
  24. package/dist/llm-client.d.ts +8 -3
  25. package/dist/llm-client.d.ts.map +1 -1
  26. package/dist/llm-client.js +64 -13
  27. package/dist/llm-client.js.map +1 -1
  28. package/dist/plugin-auto-loader.d.ts +108 -0
  29. package/dist/plugin-auto-loader.d.ts.map +1 -0
  30. package/dist/plugin-auto-loader.js +743 -0
  31. package/dist/plugin-auto-loader.js.map +1 -0
  32. package/dist/plugin-registry.d.ts +112 -0
  33. package/dist/plugin-registry.d.ts.map +1 -0
  34. package/dist/plugin-registry.js +319 -0
  35. package/dist/plugin-registry.js.map +1 -0
  36. package/dist/plugin-types.d.ts +388 -0
  37. package/dist/plugin-types.d.ts.map +1 -0
  38. package/dist/plugin-types.js +8 -0
  39. package/dist/plugin-types.js.map +1 -0
  40. package/dist/plugin-validator.d.ts +54 -0
  41. package/dist/plugin-validator.d.ts.map +1 -0
  42. package/dist/plugin-validator.js +129 -0
  43. package/dist/plugin-validator.js.map +1 -0
  44. package/dist/repo-knowledge-graph.d.ts +112 -0
  45. package/dist/repo-knowledge-graph.d.ts.map +1 -0
  46. package/dist/repo-knowledge-graph.js +561 -0
  47. package/dist/repo-knowledge-graph.js.map +1 -0
  48. package/dist/role-registry.js +1 -1
  49. package/dist/role-registry.js.map +1 -1
  50. package/dist/self-debug-loop.d.ts +257 -0
  51. package/dist/self-debug-loop.d.ts.map +1 -0
  52. package/dist/self-debug-loop.js +870 -0
  53. package/dist/self-debug-loop.js.map +1 -0
  54. package/dist/skill-learner.d.ts +136 -0
  55. package/dist/skill-learner.d.ts.map +1 -0
  56. package/dist/skill-learner.js +382 -0
  57. package/dist/skill-learner.js.map +1 -0
  58. package/dist/skill-loader.d.ts +90 -0
  59. package/dist/skill-loader.d.ts.map +1 -0
  60. package/dist/skill-loader.js +309 -0
  61. package/dist/skill-loader.js.map +1 -0
  62. package/dist/specialist-registry.d.ts +132 -0
  63. package/dist/specialist-registry.d.ts.map +1 -0
  64. package/dist/specialist-registry.js +413 -0
  65. package/dist/specialist-registry.js.map +1 -0
  66. package/dist/sub-agent-prompts.d.ts +45 -0
  67. package/dist/sub-agent-prompts.d.ts.map +1 -0
  68. package/dist/sub-agent-prompts.js +177 -0
  69. package/dist/sub-agent-prompts.js.map +1 -0
  70. package/dist/sub-agent-router.d.ts +75 -0
  71. package/dist/sub-agent-router.d.ts.map +1 -0
  72. package/dist/sub-agent-router.js +174 -0
  73. package/dist/sub-agent-router.js.map +1 -0
  74. package/dist/sub-agent.d.ts +48 -0
  75. package/dist/sub-agent.d.ts.map +1 -1
  76. package/dist/sub-agent.js +108 -5
  77. package/dist/sub-agent.js.map +1 -1
  78. package/dist/system-prompt.d.ts +26 -0
  79. package/dist/system-prompt.d.ts.map +1 -1
  80. package/dist/system-prompt.js +177 -7
  81. package/dist/system-prompt.js.map +1 -1
  82. package/dist/task-classifier.d.ts +25 -1
  83. package/dist/task-classifier.d.ts.map +1 -1
  84. package/dist/task-classifier.js +171 -1
  85. package/dist/task-classifier.js.map +1 -1
  86. package/dist/tool-planner.d.ts +160 -0
  87. package/dist/tool-planner.d.ts.map +1 -0
  88. package/dist/tool-planner.js +501 -0
  89. package/dist/tool-planner.js.map +1 -0
  90. package/dist/types.d.ts +1 -1
  91. package/dist/types.d.ts.map +1 -1
  92. package/package.json +2 -1
  93. package/plugins/git/patterns/branch-patterns.json +101 -0
  94. package/plugins/git/patterns/commit-patterns.json +186 -0
  95. package/plugins/git/plugin.yaml +128 -0
  96. package/plugins/git/skills/branch-strategy.md +172 -0
  97. package/plugins/git/skills/commit-conv.md +178 -0
  98. package/plugins/git/skills/conflict-resolve.md +159 -0
  99. package/plugins/git/skills/history-clean.md +199 -0
  100. package/plugins/git/skills/pr-review.md +196 -0
  101. package/plugins/git/strategies/conflict-resolve.json +244 -0
  102. package/plugins/git/strategies/release-flow.json +292 -0
  103. package/plugins/git/validators/rules.json +348 -0
  104. package/plugins/react/patterns/anti-patterns.json +88 -0
  105. package/plugins/react/patterns/components.json +80 -0
  106. package/plugins/react/patterns/hooks.json +72 -0
  107. package/plugins/react/plugin.yaml +229 -0
  108. package/plugins/react/skills/bugfix.md +208 -0
  109. package/plugins/react/skills/component-gen.md +206 -0
  110. package/plugins/react/skills/hook-extract.md +208 -0
  111. package/plugins/react/skills/ssr.md +256 -0
  112. package/plugins/react/skills/test.md +273 -0
  113. package/plugins/react/strategies/build-fix.json +43 -0
  114. package/plugins/react/strategies/hook-loop-fix.json +36 -0
  115. package/plugins/react/strategies/hydration-fix.json +42 -0
  116. package/plugins/react/validators/rules.json +92 -0
  117. package/plugins/typescript/patterns/best-practices.json +25 -0
  118. package/plugins/typescript/patterns/common-errors.json +32 -0
  119. package/plugins/typescript/plugin.yaml +74 -0
  120. package/plugins/typescript/skills/debug.md +23 -0
  121. package/plugins/typescript/skills/migration.md +24 -0
  122. package/plugins/typescript/skills/refactor.md +22 -0
  123. package/plugins/typescript/skills/strict-mode.md +23 -0
  124. package/plugins/typescript/strategies/strict-migration.json +37 -0
  125. package/plugins/typescript/strategies/type-error-fix.json +37 -0
  126. package/plugins/typescript/validators/rules.json +28 -0
@@ -0,0 +1,256 @@
1
+ # React SSR/Hydration Expert Skill
2
+
3
+ ## Identity
4
+ - domain: react
5
+ - type: ssr
6
+ - confidence: 0.85
7
+ - persona: Senior full-stack React engineer with deep expertise in server-side rendering, Next.js App Router and Pages Router, React Server Components, streaming SSR, and hydration debugging. Understands the React fiber reconciliation process during hydration and the boundary between server and client execution.
8
+
9
+ ## Known Error Patterns
10
+
11
+ ### 1. Hydration Mismatch — Client-Only APIs
12
+ - **symptoms**:
13
+ - "Text content does not match server-rendered HTML"
14
+ - "Hydration failed because the initial UI does not match"
15
+ - Content flickers on page load
16
+ - Different content shown before and after JavaScript loads
17
+ - "There was an error while hydrating" with full client re-render
18
+ - **causes**:
19
+ - Direct access to `window`, `document`, `navigator`, `localStorage` in render
20
+ - `typeof window !== 'undefined'` check causing different output on server vs client
21
+ - `Date.now()`, `new Date().toLocaleString()` producing different values
22
+ - `Math.random()` in render path
23
+ - `navigator.userAgent` conditional rendering
24
+ - Third-party scripts/components that assume browser environment
25
+ - **strategy**:
26
+ 1. Move client-only code into `useEffect`: renders null/placeholder on server, real content on client
27
+ 2. Create `useIsClient` hook:
28
+ ```
29
+ function useIsClient() {
30
+ const [isClient, setIsClient] = useState(false);
31
+ useEffect(() => setIsClient(true), []);
32
+ return isClient;
33
+ }
34
+ ```
35
+ 3. Use `next/dynamic` with `{ ssr: false }` for entire components that need browser APIs
36
+ 4. Use `suppressHydrationWarning` only for intentional mismatches (timestamps, user-specific content)
37
+ 5. For dates, render a stable format on server and enhance on client
38
+ 6. Wrap browser-API-dependent libraries in a client-only wrapper component
39
+ - **tools**: grep, file_read, file_edit, shell_exec
40
+ - **pitfalls**:
41
+ - `typeof window` checks in render cause hydration mismatches -- the check itself produces different branches
42
+ - `suppressHydrationWarning` only works on the direct element, not children
43
+ - Over-using `ssr: false` defeats the purpose of SSR -- only for truly client-only components
44
+
45
+ ### 2. useEffect vs useLayoutEffect in SSR
46
+ - **symptoms**:
47
+ - "useLayoutEffect does nothing on the server" warning
48
+ - Flash of unstyled content (FOUC)
49
+ - Layout shift after hydration
50
+ - Measurements (getBoundingClientRect) returning 0 on server
51
+ - **causes**:
52
+ - `useLayoutEffect` runs synchronously after DOM mutations -- not possible on server
53
+ - Using `useLayoutEffect` for client-side layout measurements
54
+ - CSS-in-JS libraries using `useLayoutEffect` for style injection
55
+ - Animation libraries using `useLayoutEffect` for initial measurements
56
+ - **strategy**:
57
+ 1. Use `useEffect` for most cases -- runs after paint, works on server
58
+ 2. Create `useIsomorphicLayoutEffect`:
59
+ ```
60
+ const useIsomorphicLayoutEffect =
61
+ typeof window !== 'undefined' ? useLayoutEffect : useEffect;
62
+ ```
63
+ 3. Only use `useLayoutEffect` when you need synchronous DOM measurement before paint
64
+ 4. For CSS-in-JS, ensure server-side style extraction is configured (styled-components: `ServerStyleSheet`)
65
+ 5. Accept minor layout shift vs. blocking paint -- `useEffect` is usually better for UX
66
+ - **tools**: grep, file_read, file_edit
67
+ - **pitfalls**:
68
+ - The `useIsomorphicLayoutEffect` pattern is a workaround, not a solution -- consider if you really need layout effect
69
+ - `useLayoutEffect` blocks paint -- use sparingly, even on client
70
+ - Most "layout" needs can be handled with CSS (grid, flexbox) without JS measurement
71
+
72
+ ### 3. Server Components vs Client Components (Next.js 13+)
73
+ - **symptoms**:
74
+ - "You're importing a component that needs useState/useEffect. It only works in a Client Component"
75
+ - "async/await is not yet supported in Client Components"
76
+ - Props serialization errors ("only plain objects can be passed to Client Components")
77
+ - "Functions cannot be passed directly to Client Components unless you explicitly expose it"
78
+ - Import errors when mixing server and client components
79
+ - **causes**:
80
+ - Using hooks (`useState`, `useEffect`, `useContext`) in a Server Component
81
+ - Using event handlers (`onClick`, `onChange`) in a Server Component
82
+ - Using browser-only APIs in a Server Component
83
+ - Passing non-serializable props (functions, classes, Dates) from Server to Client Component
84
+ - Importing a Client Component into a Server Component without `'use client'` boundary
85
+ - **strategy**:
86
+ 1. Add `'use client'` directive at the top of files that need hooks, events, or browser APIs
87
+ 2. Keep Server Components as the default -- only add `'use client'` when needed
88
+ 3. Push `'use client'` boundary as low as possible in the tree
89
+ 4. For non-serializable props, restructure: pass IDs instead of objects, use server actions
90
+ 5. Use the "donut pattern": Server Component wraps Client Component which wraps Server Component (via children)
91
+ 6. Server Components can import Client Components, but not vice versa (except via children)
92
+ 7. Fetch data in Server Components, pass serializable data to Client Components
93
+ - **tools**: grep, file_read, file_edit
94
+ - **pitfalls**:
95
+ - `'use client'` does NOT make it client-only -- it creates a boundary. The component still renders on server for SSR
96
+ - Do NOT add `'use client'` to a layout file unless absolutely necessary -- it opts out all children from Server Components
97
+ - `'use server'` is for Server Actions (mutations), NOT for making a Server Component
98
+
99
+ ### 4. Dynamic Imports and Code Splitting
100
+ - **symptoms**:
101
+ - Large initial bundle size
102
+ - Slow Time to Interactive (TTI)
103
+ - Components that only show on interaction loaded upfront
104
+ - SSR errors from client-only libraries
105
+ - Flash of loading state on navigation
106
+ - **causes**:
107
+ - All components loaded eagerly in the initial bundle
108
+ - Heavy libraries (charts, editors, maps) included in server bundle
109
+ - No code splitting for route-level or feature-level components
110
+ - Client-only libraries imported at top level
111
+ - **strategy**:
112
+ 1. Use `next/dynamic` for heavy or client-only components:
113
+ ```
114
+ const Chart = dynamic(() => import('./Chart'), {
115
+ loading: () => <ChartSkeleton />,
116
+ ssr: false,
117
+ });
118
+ ```
119
+ 2. Use `React.lazy` + `Suspense` for CSR-only apps:
120
+ ```
121
+ const LazyComponent = React.lazy(() => import('./Heavy'));
122
+ <Suspense fallback={<Skeleton />}><LazyComponent /></Suspense>
123
+ ```
124
+ 3. Route-level code splitting is automatic in Next.js App Router
125
+ 4. Use `loading.tsx` files for route-level loading UI in App Router
126
+ 5. For shared layouts, use route groups `(group)` to avoid unnecessary re-renders
127
+ 6. Analyze bundle with `@next/bundle-analyzer` to identify split opportunities
128
+ - **tools**: file_read, file_edit, shell_exec, grep
129
+ - **pitfalls**:
130
+ - `React.lazy` does NOT work with SSR -- use `next/dynamic` in Next.js
131
+ - Do NOT lazy-load components that appear above the fold -- they should be in the initial bundle
132
+ - `ssr: false` means the component renders nothing until JS loads -- bad for SEO-critical content
133
+
134
+ ### 5. Streaming SSR Patterns
135
+ - **symptoms**:
136
+ - Slow Time to First Byte (TTFB)
137
+ - Entire page blocks on slowest data fetch
138
+ - Users see blank page until all data loads
139
+ - Waterfall data fetching pattern
140
+ - Long server response times
141
+ - **causes**:
142
+ - All data fetched before any HTML is sent (`getServerSideProps` blocking pattern)
143
+ - No Suspense boundaries to enable streaming
144
+ - Monolithic page component that needs all data at once
145
+ - Database queries running sequentially instead of in parallel
146
+ - **strategy**:
147
+ 1. Use Suspense boundaries to stream parts of the page:
148
+ ```
149
+ <Suspense fallback={<HeaderSkeleton />}>
150
+ <Header />
151
+ </Suspense>
152
+ <Suspense fallback={<ContentSkeleton />}>
153
+ <SlowContent /> <!-- Streams in when ready -->
154
+ </Suspense>
155
+ ```
156
+ 2. In App Router, use `async` Server Components with Suspense for streaming
157
+ 3. Run independent data fetches in parallel with `Promise.all`
158
+ 4. Use `loading.tsx` for route-level streaming boundaries
159
+ 5. Critical content (header, hero) should be fast -- wrap slow content in Suspense
160
+ 6. Use `generateStaticParams` for static generation when data is known at build time
161
+ 7. Consider ISR (Incremental Static Regeneration) with `revalidate` for semi-static pages
162
+ - **tools**: file_read, file_edit, shell_exec
163
+ - **pitfalls**:
164
+ - Streaming only works with Node.js runtime, not Edge runtime for all cases
165
+ - Too many Suspense boundaries can cause visual "popcorn" effect -- group related content
166
+ - `loading.tsx` applies to the entire route segment -- be intentional about placement
167
+
168
+ ### 6. Data Fetching in Server Components
169
+ - **symptoms**:
170
+ - Using `useEffect` for data fetching in App Router
171
+ - Unnecessary client-side waterfalls
172
+ - Duplicate requests (server + client fetching same data)
173
+ - Stale data issues with client-side caching
174
+ - N+1 query patterns
175
+ - **causes**:
176
+ - Migrating Pages Router patterns to App Router without adaptation
177
+ - Not leveraging Server Component data fetching
178
+ - Missing Request Memoization (same URL fetched multiple times in same request)
179
+ - Not using `cache()` for database queries
180
+ - **strategy**:
181
+ 1. Fetch data directly in Server Components (no hooks needed):
182
+ ```
183
+ async function UserPage({ params }) {
184
+ const user = await getUser(params.id); // runs on server
185
+ return <UserProfile user={user} />;
186
+ }
187
+ ```
188
+ 2. Use `cache()` from React for request-level deduplication:
189
+ ```
190
+ const getUser = cache(async (id: string) => {
191
+ return db.user.findUnique({ where: { id } });
192
+ });
193
+ ```
194
+ 3. Parallel fetching: `const [user, posts] = await Promise.all([getUser(id), getPosts(id)])`
195
+ 4. Use Server Actions for mutations (forms, button clicks)
196
+ 5. Revalidate with `revalidatePath` or `revalidateTag` after mutations
197
+ 6. Use `unstable_cache` for cross-request caching (with tags for invalidation)
198
+ - **tools**: file_read, file_edit, grep
199
+ - **pitfalls**:
200
+ - `fetch` in Server Components is auto-memoized in Next.js -- manual dedup may not be needed
201
+ - `cache()` is request-scoped -- it does NOT cache across requests
202
+ - Do NOT use `getServerSideProps` in App Router -- use Server Components instead
203
+ - Server Actions are NOT GET requests -- do not use them for data fetching
204
+
205
+ ### 7. Metadata and SEO in SSR
206
+ - **symptoms**:
207
+ - Missing or incorrect meta tags in page source
208
+ - Social media previews not working (Open Graph)
209
+ - Search engines not indexing dynamic content
210
+ - Duplicate title tags
211
+ - Missing canonical URLs
212
+ - **causes**:
213
+ - Using client-side `document.title` instead of framework metadata
214
+ - Not using `generateMetadata` in App Router
215
+ - Missing `Head` component in Pages Router
216
+ - Dynamic OG images not configured
217
+ - **strategy**:
218
+ 1. App Router: export `metadata` or `generateMetadata` from page/layout:
219
+ ```
220
+ export async function generateMetadata({ params }) {
221
+ const post = await getPost(params.id);
222
+ return { title: post.title, description: post.excerpt };
223
+ }
224
+ ```
225
+ 2. Pages Router: use `next/head` in every page
226
+ 3. Configure OG images with `opengraph-image.tsx` or `generateImageMetadata`
227
+ 4. Use `robots.txt` and `sitemap.xml` (App Router: `app/robots.ts`, `app/sitemap.ts`)
228
+ 5. Add structured data (JSON-LD) in Server Components
229
+ - **tools**: file_read, file_edit, grep
230
+ - **pitfalls**:
231
+ - `<title>` in client components does not affect SSR HTML -- crawlers may not see it
232
+ - `generateMetadata` runs on the server -- do not use hooks or browser APIs in it
233
+ - Test with `curl` or "View Source" to verify server-rendered HTML, not browser DevTools
234
+
235
+ ## Tool Sequence
236
+ 1. **grep** -- Search for hydration-related errors, `'use client'` directives, and SSR patterns
237
+ 2. **file_read** -- Read the problematic component and its parent chain
238
+ 3. **grep** -- Search for `window`, `document`, `localStorage`, `navigator` usage in render paths
239
+ 4. **grep** -- Search for `useEffect`, `useLayoutEffect`, `useState` to understand client/server split
240
+ 5. **file_read** -- Read Next.js config (`next.config.js`) and layout files
241
+ 6. **file_edit** -- Apply SSR-safe fixes (useEffect wrapping, dynamic imports, use client directive)
242
+ 7. **shell_exec** -- Run `next build` to verify no build errors
243
+ 8. **shell_exec** -- Run `next dev` and check browser console for hydration warnings
244
+ 9. **grep** -- Verify no remaining hydration mismatches in build output
245
+
246
+ ## Validation Checklist
247
+ - [ ] No hydration mismatch warnings in browser console
248
+ - [ ] `next build` passes without errors
249
+ - [ ] Server-rendered HTML contains expected content (check with `curl` or View Source)
250
+ - [ ] Client-only components properly wrapped with `dynamic({ ssr: false })` or `useEffect`
251
+ - [ ] `'use client'` directives are at the lowest possible level
252
+ - [ ] No `useLayoutEffect` warnings on server
253
+ - [ ] SEO meta tags present in server-rendered HTML
254
+ - [ ] Page loads meaningfully without JavaScript (progressive enhancement)
255
+ - [ ] Streaming Suspense boundaries placed around slow content
256
+ - [ ] No unnecessary client-side data fetching that could be done on server
@@ -0,0 +1,273 @@
1
+ # React Test Generator Skill
2
+
3
+ ## Identity
4
+ - domain: react
5
+ - type: testing
6
+ - confidence: 0.85
7
+ - persona: Senior test engineer specializing in React Testing Library, MSW for API mocking, and user-centric testing philosophy. Expert in writing tests that resemble how users interact with software, avoiding implementation detail testing.
8
+
9
+ ## Known Error Patterns
10
+
11
+ ### 1. Testing Implementation Details
12
+ - **symptoms**:
13
+ - Tests break when refactoring internal component structure
14
+ - Tests use `wrapper.instance()` or access internal state
15
+ - Tests assert on class names, CSS properties, or DOM structure
16
+ - Tests mock internal hooks or child component rendering
17
+ - Tests break from renaming internal variables
18
+ - **causes**:
19
+ - Using Enzyme-style testing patterns with RTL
20
+ - Testing "how" instead of "what" the component does
21
+ - Excessive mocking of internal modules
22
+ - Selecting elements by class name or test ID instead of role
23
+ - **strategy**:
24
+ 1. Query by role: `getByRole('button', { name: /submit/i })`
25
+ 2. Query by label: `getByLabelText(/email/i)`
26
+ 3. Query by text: `getByText(/welcome/i)`
27
+ 4. Use `getByTestId` only as last resort
28
+ 5. Assert on visible output, not internal state
29
+ 6. Test user interactions, not method calls
30
+ - **tools**: file_read, file_edit, shell_exec
31
+ - **pitfalls**:
32
+ - If you need `getByTestId` often, your component may lack proper accessibility
33
+ - Do NOT test that `setState` was called -- test that the UI changed
34
+ - Do NOT snapshot test frequently-changing components
35
+
36
+ ### 2. Async Testing Failures
37
+ - **symptoms**:
38
+ - "not wrapped in act(...)" warnings
39
+ - Tests pass/fail intermittently (flaky tests)
40
+ - Assertion runs before async operation completes
41
+ - `waitFor` times out unexpectedly
42
+ - State updates after test cleanup
43
+ - **causes**:
44
+ - Not awaiting async operations
45
+ - Using `getBy*` for elements that appear asynchronously (should use `findBy*`)
46
+ - Missing `await` on `userEvent` calls (v14+)
47
+ - Timer-dependent code without fake timers
48
+ - Missing MSW handlers causing real network requests
49
+ - **strategy**:
50
+ 1. Use `findBy*` for elements that appear after async work: `await screen.findByText(/loaded/i)`
51
+ 2. Use `waitFor` for assertions that need retrying: `await waitFor(() => expect(...).toBe(...))`
52
+ 3. Always `await` userEvent calls: `await user.click(button)`
53
+ 4. Use `vi.useFakeTimers()` for timer-dependent code
54
+ 5. Set up MSW handlers for all API calls in tests
55
+ 6. Clean up with `afterEach` -- reset handlers, clear timers
56
+ - **tools**: file_read, file_edit, shell_exec
57
+ - **pitfalls**:
58
+ - `waitFor` should contain only assertions, not side effects
59
+ - Do NOT use `waitFor` with a `timeout` > 5000ms -- your test is probably wrong
60
+ - `findBy*` already wraps `waitFor` -- do not nest them
61
+
62
+ ### 3. Improper Mocking
63
+ - **symptoms**:
64
+ - Tests pass but component fails in production
65
+ - Mocks do not match real API shape (type mismatch)
66
+ - Every test has extensive mock setup boilerplate
67
+ - Changing API requires updating dozens of mock files
68
+ - Tests do not catch real integration issues
69
+ - **causes**:
70
+ - Manual mocking of `fetch`/`axios` instead of using MSW
71
+ - Mock data not matching actual API response types
72
+ - Over-mocking (mocking things that should be tested)
73
+ - Not using TypeScript-typed mock factories
74
+ - **strategy**:
75
+ 1. Use MSW for API mocking -- intercepts at network level
76
+ 2. Define handlers per API endpoint: `rest.get('/api/users', (req, res, ctx) => ...)`
77
+ 3. Create typed mock factories: `function createMockUser(overrides?: Partial<User>): User`
78
+ 4. Share handlers across tests with a `handlers.ts` file
79
+ 5. Override individual handlers per test: `server.use(rest.get('/api/users', errorHandler))`
80
+ 6. Use `msw/node` for Vitest/Jest, `msw/browser` for Storybook
81
+ - **tools**: file_read, file_edit, grep
82
+ - **pitfalls**:
83
+ - MSW v2 uses a different API than v1 -- check which version is installed
84
+ - Do NOT mock `React.useState` or `React.useEffect` -- test the behavior they produce
85
+ - Mock at the highest appropriate level (network > module > function)
86
+
87
+ ### 4. Missing Edge Case Coverage
88
+ - **symptoms**:
89
+ - Tests only cover the happy path
90
+ - No tests for loading states, error states, empty states
91
+ - No tests for boundary conditions (empty list, max length, special characters)
92
+ - No tests for keyboard navigation or screen reader
93
+ - Bugs found in production that should have been caught
94
+ - **causes**:
95
+ - Rushing to meet coverage targets with superficial tests
96
+ - Not thinking about failure modes during test design
97
+ - No test plan or checklist
98
+ - Only testing what was explicitly specified
99
+ - **strategy**:
100
+ 1. For each component, test: render, interaction, loading, error, empty, edge
101
+ 2. Test error boundaries: what happens when child throws
102
+ 3. Test with empty data, null data, maximum data
103
+ 4. Test keyboard interactions: Tab, Enter, Escape, Arrow keys
104
+ 5. Test responsive behavior if component adapts to screen size
105
+ 6. Test with slow network (MSW delay) for loading states
106
+ - **tools**: file_read, file_edit, shell_exec
107
+ - **pitfalls**:
108
+ - 100% code coverage does not mean 100% bug coverage -- focus on behavior coverage
109
+ - Do NOT write tests just to increase coverage numbers
110
+ - Edge cases are where most production bugs live
111
+
112
+ ### 5. Snapshot Testing Misuse
113
+ - **symptoms**:
114
+ - Snapshot files are massive (1000+ lines)
115
+ - Developers blindly update snapshots with `--update`
116
+ - Snapshots break on every style change
117
+ - Snapshots do not catch meaningful regressions
118
+ - PR reviews skip snapshot diffs
119
+ - **causes**:
120
+ - Snapshotting entire page/component trees
121
+ - Using snapshots as primary testing strategy
122
+ - Not combining with behavioral assertions
123
+ - Snapshot of dynamic content (dates, random IDs)
124
+ - **strategy**:
125
+ 1. Use inline snapshots for small, stable output: `expect(result).toMatchInlineSnapshot()`
126
+ 2. Snapshot only the relevant portion, not the entire tree
127
+ 3. Combine with behavioral tests -- snapshots supplement, not replace
128
+ 4. Use `toMatchSnapshot` only for pure/stable components (icons, static layouts)
129
+ 5. Review every snapshot update carefully in PRs
130
+ 6. Prefer explicit assertions over snapshots for logic-heavy components
131
+ - **tools**: file_read, file_edit
132
+ - **pitfalls**:
133
+ - If you update snapshots without reviewing, you may be locking in a bug
134
+ - Snapshots with dynamic data (timestamps, UUIDs) will always fail -- mock or exclude
135
+ - Large snapshot files are a code smell -- your component may be too big
136
+
137
+ ## Test Structure Template
138
+
139
+ ### Basic Component Test
140
+ ```typescript
141
+ import { render, screen } from '@testing-library/react';
142
+ import userEvent from '@testing-library/user-event';
143
+ import { describe, it, expect } from 'vitest';
144
+ import { Button } from './Button';
145
+
146
+ describe('Button', () => {
147
+ it('renders with label text', () => {
148
+ render(<Button>Click me</Button>);
149
+ expect(screen.getByRole('button', { name: /click me/i })).toBeInTheDocument();
150
+ });
151
+
152
+ it('calls onClick when clicked', async () => {
153
+ const user = userEvent.setup();
154
+ const handleClick = vi.fn();
155
+ render(<Button onClick={handleClick}>Click</Button>);
156
+ await user.click(screen.getByRole('button'));
157
+ expect(handleClick).toHaveBeenCalledTimes(1);
158
+ });
159
+
160
+ it('is disabled when disabled prop is true', () => {
161
+ render(<Button disabled>Click</Button>);
162
+ expect(screen.getByRole('button')).toBeDisabled();
163
+ });
164
+ });
165
+ ```
166
+
167
+ ### Async Component Test with MSW
168
+ ```typescript
169
+ import { render, screen } from '@testing-library/react';
170
+ import { http, HttpResponse } from 'msw';
171
+ import { setupServer } from 'msw/node';
172
+ import { UserList } from './UserList';
173
+
174
+ const server = setupServer(
175
+ http.get('/api/users', () => {
176
+ return HttpResponse.json([
177
+ { id: '1', name: 'Alice' },
178
+ { id: '2', name: 'Bob' },
179
+ ]);
180
+ })
181
+ );
182
+
183
+ beforeAll(() => server.listen());
184
+ afterEach(() => server.resetHandlers());
185
+ afterAll(() => server.close());
186
+
187
+ describe('UserList', () => {
188
+ it('shows loading then users', async () => {
189
+ render(<UserList />);
190
+ expect(screen.getByText(/loading/i)).toBeInTheDocument();
191
+ expect(await screen.findByText('Alice')).toBeInTheDocument();
192
+ expect(screen.getByText('Bob')).toBeInTheDocument();
193
+ });
194
+
195
+ it('shows error on API failure', async () => {
196
+ server.use(
197
+ http.get('/api/users', () => {
198
+ return HttpResponse.json({ message: 'Server Error' }, { status: 500 });
199
+ })
200
+ );
201
+ render(<UserList />);
202
+ expect(await screen.findByText(/error/i)).toBeInTheDocument();
203
+ });
204
+
205
+ it('shows empty message when no users', async () => {
206
+ server.use(
207
+ http.get('/api/users', () => {
208
+ return HttpResponse.json([]);
209
+ })
210
+ );
211
+ render(<UserList />);
212
+ expect(await screen.findByText(/no users/i)).toBeInTheDocument();
213
+ });
214
+ });
215
+ ```
216
+
217
+ ### Custom Hook Test
218
+ ```typescript
219
+ import { renderHook, act } from '@testing-library/react';
220
+ import { useCounter } from './useCounter';
221
+
222
+ describe('useCounter', () => {
223
+ it('initializes with default value', () => {
224
+ const { result } = renderHook(() => useCounter(0));
225
+ expect(result.current.count).toBe(0);
226
+ });
227
+
228
+ it('increments', () => {
229
+ const { result } = renderHook(() => useCounter(0));
230
+ act(() => result.current.increment());
231
+ expect(result.current.count).toBe(1);
232
+ });
233
+
234
+ it('resets to initial value', () => {
235
+ const { result } = renderHook(() => useCounter(5));
236
+ act(() => result.current.increment());
237
+ act(() => result.current.reset());
238
+ expect(result.current.count).toBe(5);
239
+ });
240
+ });
241
+ ```
242
+
243
+ ## RTL Query Priority (Use in This Order)
244
+ 1. `getByRole` -- accessible role (button, heading, textbox, etc.)
245
+ 2. `getByLabelText` -- form elements with labels
246
+ 3. `getByPlaceholderText` -- input placeholders
247
+ 4. `getByText` -- visible text content
248
+ 5. `getByDisplayValue` -- current input value
249
+ 6. `getByAltText` -- images
250
+ 7. `getByTitle` -- title attribute
251
+ 8. `getByTestId` -- last resort, data-testid attribute
252
+
253
+ ## Tool Sequence
254
+ 1. **file_read** -- Read the target component to understand its behavior and props
255
+ 2. **grep** -- Search for existing test patterns in the project (test runner, assertion style)
256
+ 3. **grep** -- Check for MSW setup, test utilities, custom render wrappers
257
+ 4. **file_read** -- Read related hooks/stores that the component depends on
258
+ 5. **file_edit** -- Create the test file following project conventions
259
+ 6. **file_edit** -- Add MSW handlers if the component makes API calls
260
+ 7. **shell_exec** -- Run tests: `pnpm test` or `vitest run <file>`
261
+ 8. **shell_exec** -- Check coverage: `vitest run --coverage <file>`
262
+
263
+ ## Validation Checklist
264
+ - [ ] Tests use `getByRole` or `getByLabelText` as primary queries (not `getByTestId`)
265
+ - [ ] All async operations are properly awaited
266
+ - [ ] Loading, success, error, and empty states are tested
267
+ - [ ] User interactions are tested with `userEvent` (not `fireEvent`)
268
+ - [ ] API calls are mocked with MSW (not manual fetch/axios mocks)
269
+ - [ ] No "act(...)" warnings in test output
270
+ - [ ] Tests do not depend on implementation details (class names, internal state)
271
+ - [ ] All tests pass: `pnpm test`
272
+ - [ ] No flaky tests (run 3x to verify)
273
+ - [ ] Edge cases covered (empty input, max length, special characters)
@@ -0,0 +1,43 @@
1
+ {
2
+ "id": "build-fix",
3
+ "name": "React/Next.js Build Error Fix",
4
+ "description": "Four-phase strategy to collect, categorize, fix, and verify React/Next.js build errors",
5
+ "problemClass": "build_error",
6
+ "phases": [
7
+ {
8
+ "name": "Collect Build Errors",
9
+ "tools": ["shell_exec"],
10
+ "maxIterations": 2,
11
+ "successCriteria": "Full build output captured from 'pnpm build' or 'next build'. All error messages, file paths, and line numbers extracted. Error count documented."
12
+ },
13
+ {
14
+ "name": "Categorize Errors",
15
+ "tools": ["file_read", "grep"],
16
+ "maxIterations": 5,
17
+ "successCriteria": "Each error categorized as one of: (1) TypeScript type error — missing type, wrong type, generic inference failure, (2) Module not found — missing dependency, wrong import path, missing barrel export, (3) ESLint error — hooks rules, unused vars, import order, (4) Next.js specific — server/client boundary violation, metadata export error, route config issue, (5) Runtime error during SSG/ISR — data fetching failure, env var missing. Fix priority established (blocking errors first)."
18
+ },
19
+ {
20
+ "name": "Apply Fixes",
21
+ "tools": ["file_read", "file_edit", "shell_exec", "grep"],
22
+ "maxIterations": 10,
23
+ "successCriteria": "All categorized errors addressed. TypeScript errors fixed with proper types (no 'any' escape hatches). Missing modules installed or import paths corrected. ESLint errors fixed at source (not disabled). Next.js boundary issues resolved with 'use client'/'use server' directives. Each fix verified with incremental tsc --noEmit check."
24
+ },
25
+ {
26
+ "name": "Verify Clean Build",
27
+ "tools": ["shell_exec"],
28
+ "maxIterations": 3,
29
+ "successCriteria": "Full 'pnpm build' or 'next build' passes with zero errors. No new warnings introduced. Build output size is reasonable (no accidental bundle bloat). All existing tests pass. TypeScript strict mode passes (tsc --noEmit)."
30
+ }
31
+ ],
32
+ "exitCriteria": [
33
+ "pnpm build (or next build) passes with zero errors",
34
+ "tsc --noEmit passes",
35
+ "No new ESLint warnings or errors",
36
+ "All existing tests pass",
37
+ "No 'any' type escape hatches introduced",
38
+ "Bundle size has not increased significantly"
39
+ ],
40
+ "fallback": null,
41
+ "estimatedTokens": 4000,
42
+ "confidence": 0.80
43
+ }
@@ -0,0 +1,36 @@
1
+ {
2
+ "id": "hook-loop-fix",
3
+ "name": "useEffect Infinite Loop Fix",
4
+ "description": "Three-phase strategy to identify, fix, and verify useEffect infinite loop / maximum update depth issues",
5
+ "problemClass": "infinite_render_loop",
6
+ "phases": [
7
+ {
8
+ "name": "Identify Loop Source",
9
+ "tools": ["grep", "file_read"],
10
+ "maxIterations": 5,
11
+ "successCriteria": "Specific useEffect identified that causes the loop. Dependency array analyzed. Root cause classified as one of: (1) missing dependency array, (2) object/array reference in deps creating new reference each render, (3) state setter in effect body with that state in deps, (4) function reference in deps recreated each render, (5) mutual state updates between multiple effects. Call stack or component name identified."
12
+ },
13
+ {
14
+ "name": "Fix Dependencies",
15
+ "tools": ["file_read", "file_edit"],
16
+ "maxIterations": 5,
17
+ "successCriteria": "Fix applied using appropriate technique: (a) add missing dependency array, (b) stabilize object/array deps with useMemo, (c) use functional state updater to remove state from deps, (d) wrap function deps in useCallback, (e) extract primitive values from objects for deps, (f) refactor mutual updates into useReducer. No eslint-disable comments added for react-hooks/exhaustive-deps. No TypeScript errors."
18
+ },
19
+ {
20
+ "name": "Verify Stability",
21
+ "tools": ["shell_exec", "grep"],
22
+ "maxIterations": 3,
23
+ "successCriteria": "Build passes. No 'Maximum update depth exceeded' errors. No 'Too many re-renders' errors. Component renders expected number of times (verify with React DevTools Profiler or console.log count). All existing tests pass. No new ESLint warnings from react-hooks/exhaustive-deps."
24
+ }
25
+ ],
26
+ "exitCriteria": [
27
+ "No infinite loop or maximum update depth errors",
28
+ "Build passes without errors",
29
+ "Component renders correct number of times",
30
+ "eslint react-hooks/exhaustive-deps passes without disable comments",
31
+ "All existing tests pass"
32
+ ],
33
+ "fallback": null,
34
+ "estimatedTokens": 2000,
35
+ "confidence": 0.85
36
+ }
@@ -0,0 +1,42 @@
1
+ {
2
+ "id": "hydration-fix",
3
+ "name": "Hydration Mismatch Fix",
4
+ "description": "Multi-phase strategy to diagnose and resolve React hydration mismatches in SSR/Next.js applications",
5
+ "problemClass": "hydration_error",
6
+ "phases": [
7
+ {
8
+ "name": "Reproduce & Collect Evidence",
9
+ "tools": ["shell_exec", "grep", "file_read"],
10
+ "maxIterations": 3,
11
+ "successCriteria": "Hydration error message identified with specific component and line reference. Build output collected showing the exact mismatch text."
12
+ },
13
+ {
14
+ "name": "Diagnose Root Cause",
15
+ "tools": ["grep", "file_read"],
16
+ "maxIterations": 5,
17
+ "successCriteria": "Root cause identified: one of (1) browser API in render path, (2) date/random in render, (3) conditional rendering based on typeof window, (4) third-party component accessing browser globals, (5) data mismatch between server and client. Affected files and line numbers documented."
18
+ },
19
+ {
20
+ "name": "Apply Fix",
21
+ "tools": ["file_edit", "file_read"],
22
+ "maxIterations": 5,
23
+ "successCriteria": "Fix applied using appropriate strategy: (a) useEffect wrapper for client-only code, (b) next/dynamic with ssr:false for client-only components, (c) useIsClient hook for conditional rendering, (d) suppressHydrationWarning for intentional mismatches. No new TypeScript errors introduced."
24
+ },
25
+ {
26
+ "name": "Verify Fix",
27
+ "tools": ["shell_exec", "grep"],
28
+ "maxIterations": 3,
29
+ "successCriteria": "next build passes without errors. Dev server shows zero hydration warnings in console. Server-rendered HTML verified with curl to contain expected content. Existing tests pass."
30
+ }
31
+ ],
32
+ "exitCriteria": [
33
+ "next build completes successfully",
34
+ "Zero hydration mismatch warnings in browser console",
35
+ "Server-rendered HTML contains expected content",
36
+ "All existing tests pass",
37
+ "No new TypeScript errors"
38
+ ],
39
+ "fallback": "ssr-disable-component",
40
+ "estimatedTokens": 3000,
41
+ "confidence": 0.90
42
+ }