@qazuor/claude-code-config 0.5.0 → 0.6.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 (57) hide show
  1. package/README.md +106 -41
  2. package/dist/bin.cjs +963 -84
  3. package/dist/bin.cjs.map +1 -1
  4. package/dist/bin.js +963 -84
  5. package/dist/bin.js.map +1 -1
  6. package/dist/index.cjs +73 -56
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.d.cts +2 -0
  9. package/dist/index.d.ts +2 -0
  10. package/dist/index.js +73 -56
  11. package/dist/index.js.map +1 -1
  12. package/package.json +23 -24
  13. package/templates/CLAUDE.md.template +60 -5
  14. package/templates/agents/README.md +58 -39
  15. package/templates/agents/_registry.json +43 -202
  16. package/templates/agents/engineering/{hono-engineer.md → api-engineer.md} +61 -70
  17. package/templates/agents/engineering/database-engineer.md +253 -0
  18. package/templates/agents/engineering/frontend-engineer.md +302 -0
  19. package/templates/hooks/on-notification.sh +0 -0
  20. package/templates/scripts/add-changelogs.sh +0 -0
  21. package/templates/scripts/generate-code-registry.ts +0 -0
  22. package/templates/scripts/health-check.sh +0 -0
  23. package/templates/scripts/sync-registry.sh +0 -0
  24. package/templates/scripts/telemetry-report.ts +0 -0
  25. package/templates/scripts/validate-docs.sh +0 -0
  26. package/templates/scripts/validate-registry.sh +0 -0
  27. package/templates/scripts/validate-structure.sh +0 -0
  28. package/templates/scripts/worktree-cleanup.sh +0 -0
  29. package/templates/scripts/worktree-create.sh +0 -0
  30. package/templates/skills/README.md +99 -90
  31. package/templates/skills/_registry.json +323 -16
  32. package/templates/skills/api-frameworks/express-patterns.md +411 -0
  33. package/templates/skills/api-frameworks/fastify-patterns.md +419 -0
  34. package/templates/skills/api-frameworks/hono-patterns.md +388 -0
  35. package/templates/skills/api-frameworks/nestjs-patterns.md +497 -0
  36. package/templates/skills/database/drizzle-patterns.md +449 -0
  37. package/templates/skills/database/mongoose-patterns.md +503 -0
  38. package/templates/skills/database/prisma-patterns.md +487 -0
  39. package/templates/skills/frontend-frameworks/astro-patterns.md +415 -0
  40. package/templates/skills/frontend-frameworks/nextjs-patterns.md +470 -0
  41. package/templates/skills/frontend-frameworks/react-patterns.md +516 -0
  42. package/templates/skills/frontend-frameworks/tanstack-start-patterns.md +469 -0
  43. package/templates/skills/patterns/atdd-methodology.md +364 -0
  44. package/templates/skills/patterns/bdd-methodology.md +281 -0
  45. package/templates/skills/patterns/clean-architecture.md +444 -0
  46. package/templates/skills/patterns/hexagonal-architecture.md +567 -0
  47. package/templates/skills/patterns/vertical-slice-architecture.md +502 -0
  48. package/templates/agents/engineering/astro-engineer.md +0 -293
  49. package/templates/agents/engineering/db-drizzle-engineer.md +0 -360
  50. package/templates/agents/engineering/express-engineer.md +0 -316
  51. package/templates/agents/engineering/fastify-engineer.md +0 -399
  52. package/templates/agents/engineering/mongoose-engineer.md +0 -473
  53. package/templates/agents/engineering/nestjs-engineer.md +0 -429
  54. package/templates/agents/engineering/nextjs-engineer.md +0 -451
  55. package/templates/agents/engineering/prisma-engineer.md +0 -432
  56. package/templates/agents/engineering/react-senior-dev.md +0 -394
  57. package/templates/agents/engineering/tanstack-start-engineer.md +0 -447
@@ -0,0 +1,516 @@
1
+ # React Patterns
2
+
3
+ ## Overview
4
+
5
+ React is a JavaScript library for building user interfaces. This skill provides patterns for building React applications.
6
+
7
+ ---
8
+
9
+ ## Component Patterns
10
+
11
+ ### Functional Component with Props
12
+
13
+ ```typescript
14
+ /**
15
+ * Item card component
16
+ * Displays item summary with image, title, and price
17
+ */
18
+ interface ItemCardProps {
19
+ item: Item;
20
+ onSelect?: (id: string) => void;
21
+ priority?: boolean;
22
+ }
23
+
24
+ export function ItemCard({
25
+ item,
26
+ onSelect,
27
+ priority = false,
28
+ }: ItemCardProps) {
29
+ const handleClick = () => {
30
+ onSelect?.(item.id);
31
+ };
32
+
33
+ return (
34
+ <article
35
+ onClick={handleClick}
36
+ className="cursor-pointer hover:shadow-lg"
37
+ aria-label={`Item: ${item.title}`}
38
+ >
39
+ <img
40
+ src={item.image}
41
+ alt={item.title}
42
+ loading={priority ? 'eager' : 'lazy'}
43
+ />
44
+ <h3>{item.title}</h3>
45
+ <p>${item.price}</p>
46
+ </article>
47
+ );
48
+ }
49
+ ```
50
+
51
+ ### Memoized Component
52
+
53
+ ```typescript
54
+ import { memo } from 'react';
55
+
56
+ interface ExpensiveListProps {
57
+ items: Item[];
58
+ onItemSelect: (id: string) => void;
59
+ }
60
+
61
+ function ExpensiveListComponent({ items, onItemSelect }: ExpensiveListProps) {
62
+ return (
63
+ <ul>
64
+ {items.map((item) => (
65
+ <li key={item.id} onClick={() => onItemSelect(item.id)}>
66
+ {item.title}
67
+ </li>
68
+ ))}
69
+ </ul>
70
+ );
71
+ }
72
+
73
+ // Memoize to prevent re-renders when props haven't changed
74
+ export const ExpensiveList = memo(ExpensiveListComponent);
75
+ ```
76
+
77
+ ### Compound Components
78
+
79
+ ```typescript
80
+ import { createContext, useContext, useState, type ReactNode } from 'react';
81
+
82
+ // Context
83
+ interface AccordionContextValue {
84
+ openItems: Set<string>;
85
+ toggle: (id: string) => void;
86
+ }
87
+
88
+ const AccordionContext = createContext<AccordionContextValue | undefined>(undefined);
89
+
90
+ function useAccordion() {
91
+ const context = useContext(AccordionContext);
92
+ if (!context) {
93
+ throw new Error('Accordion components must be used within Accordion');
94
+ }
95
+ return context;
96
+ }
97
+
98
+ // Root
99
+ interface AccordionProps {
100
+ children: ReactNode;
101
+ defaultOpen?: string[];
102
+ }
103
+
104
+ function Accordion({ children, defaultOpen = [] }: AccordionProps) {
105
+ const [openItems, setOpenItems] = useState(new Set(defaultOpen));
106
+
107
+ const toggle = (id: string) => {
108
+ setOpenItems((prev) => {
109
+ const next = new Set(prev);
110
+ if (next.has(id)) {
111
+ next.delete(id);
112
+ } else {
113
+ next.add(id);
114
+ }
115
+ return next;
116
+ });
117
+ };
118
+
119
+ return (
120
+ <AccordionContext.Provider value={{ openItems, toggle }}>
121
+ <div className="accordion">{children}</div>
122
+ </AccordionContext.Provider>
123
+ );
124
+ }
125
+
126
+ // Item
127
+ interface AccordionItemProps {
128
+ id: string;
129
+ children: ReactNode;
130
+ }
131
+
132
+ Accordion.Item = function Item({ id, children }: AccordionItemProps) {
133
+ const { openItems } = useAccordion();
134
+ const isOpen = openItems.has(id);
135
+
136
+ return (
137
+ <div className="accordion-item" data-open={isOpen}>
138
+ {children}
139
+ </div>
140
+ );
141
+ };
142
+
143
+ // Trigger
144
+ Accordion.Trigger = function Trigger({ id, children }: AccordionItemProps) {
145
+ const { toggle } = useAccordion();
146
+
147
+ return (
148
+ <button onClick={() => toggle(id)} className="accordion-trigger">
149
+ {children}
150
+ </button>
151
+ );
152
+ };
153
+
154
+ // Content
155
+ Accordion.Content = function Content({ id, children }: AccordionItemProps) {
156
+ const { openItems } = useAccordion();
157
+
158
+ if (!openItems.has(id)) return null;
159
+
160
+ return <div className="accordion-content">{children}</div>;
161
+ };
162
+
163
+ export { Accordion };
164
+ ```
165
+
166
+ ---
167
+
168
+ ## Custom Hooks
169
+
170
+ ### Data Fetching Hook
171
+
172
+ ```typescript
173
+ import { useState, useEffect } from 'react';
174
+
175
+ interface UseFetchResult<T> {
176
+ data: T | null;
177
+ loading: boolean;
178
+ error: Error | null;
179
+ refetch: () => void;
180
+ }
181
+
182
+ export function useFetch<T>(url: string): UseFetchResult<T> {
183
+ const [data, setData] = useState<T | null>(null);
184
+ const [loading, setLoading] = useState(true);
185
+ const [error, setError] = useState<Error | null>(null);
186
+
187
+ const fetchData = async () => {
188
+ setLoading(true);
189
+ setError(null);
190
+
191
+ try {
192
+ const response = await fetch(url);
193
+ if (!response.ok) {
194
+ throw new Error(`HTTP error! status: ${response.status}`);
195
+ }
196
+ const json = await response.json();
197
+ setData(json);
198
+ } catch (e) {
199
+ setError(e instanceof Error ? e : new Error('Unknown error'));
200
+ } finally {
201
+ setLoading(false);
202
+ }
203
+ };
204
+
205
+ useEffect(() => {
206
+ fetchData();
207
+ }, [url]);
208
+
209
+ return { data, loading, error, refetch: fetchData };
210
+ }
211
+ ```
212
+
213
+ ### Local Storage Hook
214
+
215
+ ```typescript
216
+ import { useState, useEffect } from 'react';
217
+
218
+ export function useLocalStorage<T>(
219
+ key: string,
220
+ initialValue: T
221
+ ): [T, (value: T | ((prev: T) => T)) => void] {
222
+ const [storedValue, setStoredValue] = useState<T>(() => {
223
+ if (typeof window === 'undefined') {
224
+ return initialValue;
225
+ }
226
+
227
+ try {
228
+ const item = window.localStorage.getItem(key);
229
+ return item ? JSON.parse(item) : initialValue;
230
+ } catch {
231
+ return initialValue;
232
+ }
233
+ });
234
+
235
+ const setValue = (value: T | ((prev: T) => T)) => {
236
+ const valueToStore = value instanceof Function ? value(storedValue) : value;
237
+ setStoredValue(valueToStore);
238
+
239
+ if (typeof window !== 'undefined') {
240
+ window.localStorage.setItem(key, JSON.stringify(valueToStore));
241
+ }
242
+ };
243
+
244
+ return [storedValue, setValue];
245
+ }
246
+ ```
247
+
248
+ ### Debounce Hook
249
+
250
+ ```typescript
251
+ import { useState, useEffect } from 'react';
252
+
253
+ export function useDebounce<T>(value: T, delay: number): T {
254
+ const [debouncedValue, setDebouncedValue] = useState<T>(value);
255
+
256
+ useEffect(() => {
257
+ const handler = setTimeout(() => {
258
+ setDebouncedValue(value);
259
+ }, delay);
260
+
261
+ return () => {
262
+ clearTimeout(handler);
263
+ };
264
+ }, [value, delay]);
265
+
266
+ return debouncedValue;
267
+ }
268
+
269
+ // Usage
270
+ function SearchInput() {
271
+ const [query, setQuery] = useState('');
272
+ const debouncedQuery = useDebounce(query, 300);
273
+
274
+ useEffect(() => {
275
+ if (debouncedQuery) {
276
+ // Perform search
277
+ }
278
+ }, [debouncedQuery]);
279
+
280
+ return <input value={query} onChange={(e) => setQuery(e.target.value)} />;
281
+ }
282
+ ```
283
+
284
+ ---
285
+
286
+ ## Performance Patterns
287
+
288
+ ### useMemo and useCallback
289
+
290
+ ```typescript
291
+ import { useMemo, useCallback, useState } from 'react';
292
+
293
+ function ItemList({ items }: { items: Item[] }) {
294
+ const [filter, setFilter] = useState('');
295
+
296
+ // Memoize expensive calculation
297
+ const filteredItems = useMemo(() => {
298
+ return items.filter((item) =>
299
+ item.title.toLowerCase().includes(filter.toLowerCase())
300
+ );
301
+ }, [items, filter]);
302
+
303
+ // Memoize callback to prevent child re-renders
304
+ const handleSelect = useCallback((id: string) => {
305
+ console.log('Selected:', id);
306
+ }, []);
307
+
308
+ return (
309
+ <div>
310
+ <input
311
+ value={filter}
312
+ onChange={(e) => setFilter(e.target.value)}
313
+ placeholder="Filter items..."
314
+ />
315
+ {filteredItems.map((item) => (
316
+ <ItemCard key={item.id} item={item} onSelect={handleSelect} />
317
+ ))}
318
+ </div>
319
+ );
320
+ }
321
+ ```
322
+
323
+ ### Code Splitting
324
+
325
+ ```typescript
326
+ import { lazy, Suspense } from 'react';
327
+
328
+ // Lazy load components
329
+ const HeavyChart = lazy(() => import('./HeavyChart'));
330
+ const AdminPanel = lazy(() => import('./AdminPanel'));
331
+
332
+ function App() {
333
+ return (
334
+ <Suspense fallback={<LoadingSpinner />}>
335
+ <Routes>
336
+ <Route path="/analytics" element={<HeavyChart />} />
337
+ <Route path="/admin" element={<AdminPanel />} />
338
+ </Routes>
339
+ </Suspense>
340
+ );
341
+ }
342
+ ```
343
+
344
+ ### Virtual Lists
345
+
346
+ ```typescript
347
+ import { useVirtualizer } from '@tanstack/react-virtual';
348
+ import { useRef } from 'react';
349
+
350
+ function VirtualList({ items }: { items: Item[] }) {
351
+ const parentRef = useRef<HTMLDivElement>(null);
352
+
353
+ const virtualizer = useVirtualizer({
354
+ count: items.length,
355
+ getScrollElement: () => parentRef.current,
356
+ estimateSize: () => 50,
357
+ });
358
+
359
+ return (
360
+ <div
361
+ ref={parentRef}
362
+ style={{ height: '400px', overflow: 'auto' }}
363
+ >
364
+ <div
365
+ style={{
366
+ height: `${virtualizer.getTotalSize()}px`,
367
+ position: 'relative',
368
+ }}
369
+ >
370
+ {virtualizer.getVirtualItems().map((virtualItem) => (
371
+ <div
372
+ key={virtualItem.key}
373
+ style={{
374
+ position: 'absolute',
375
+ top: 0,
376
+ left: 0,
377
+ width: '100%',
378
+ height: `${virtualItem.size}px`,
379
+ transform: `translateY(${virtualItem.start}px)`,
380
+ }}
381
+ >
382
+ {items[virtualItem.index].title}
383
+ </div>
384
+ ))}
385
+ </div>
386
+ </div>
387
+ );
388
+ }
389
+ ```
390
+
391
+ ---
392
+
393
+ ## Error Handling
394
+
395
+ ### Error Boundary
396
+
397
+ ```typescript
398
+ import { Component, type ReactNode } from 'react';
399
+
400
+ interface Props {
401
+ children: ReactNode;
402
+ fallback?: ReactNode;
403
+ }
404
+
405
+ interface State {
406
+ hasError: boolean;
407
+ error: Error | null;
408
+ }
409
+
410
+ export class ErrorBoundary extends Component<Props, State> {
411
+ constructor(props: Props) {
412
+ super(props);
413
+ this.state = { hasError: false, error: null };
414
+ }
415
+
416
+ static getDerivedStateFromError(error: Error): State {
417
+ return { hasError: true, error };
418
+ }
419
+
420
+ componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
421
+ console.error('Error caught by boundary:', error, errorInfo);
422
+ }
423
+
424
+ render() {
425
+ if (this.state.hasError) {
426
+ return this.props.fallback || (
427
+ <div className="error-fallback">
428
+ <h2>Something went wrong</h2>
429
+ <button onClick={() => this.setState({ hasError: false, error: null })}>
430
+ Try again
431
+ </button>
432
+ </div>
433
+ );
434
+ }
435
+
436
+ return this.props.children;
437
+ }
438
+ }
439
+ ```
440
+
441
+ ---
442
+
443
+ ## Testing
444
+
445
+ ```typescript
446
+ import { render, screen, fireEvent, waitFor } from '@testing-library/react';
447
+ import { describe, it, expect, vi } from 'vitest';
448
+ import { ItemCard } from './ItemCard';
449
+
450
+ const mockItem = {
451
+ id: '1',
452
+ title: 'Test Item',
453
+ price: 100,
454
+ image: '/test.jpg',
455
+ };
456
+
457
+ describe('ItemCard', () => {
458
+ it('should render item data', () => {
459
+ render(<ItemCard item={mockItem} />);
460
+
461
+ expect(screen.getByText('Test Item')).toBeInTheDocument();
462
+ expect(screen.getByText('$100')).toBeInTheDocument();
463
+ });
464
+
465
+ it('should call onSelect when clicked', () => {
466
+ const onSelect = vi.fn();
467
+ render(<ItemCard item={mockItem} onSelect={onSelect} />);
468
+
469
+ fireEvent.click(screen.getByRole('article'));
470
+
471
+ expect(onSelect).toHaveBeenCalledWith('1');
472
+ });
473
+
474
+ it('should have proper accessibility attributes', () => {
475
+ render(<ItemCard item={mockItem} />);
476
+
477
+ expect(screen.getByRole('article')).toHaveAttribute(
478
+ 'aria-label',
479
+ 'Item: Test Item'
480
+ );
481
+ });
482
+
483
+ it('should use lazy loading by default', () => {
484
+ render(<ItemCard item={mockItem} />);
485
+
486
+ expect(screen.getByRole('img')).toHaveAttribute('loading', 'lazy');
487
+ });
488
+
489
+ it('should use eager loading when priority is true', () => {
490
+ render(<ItemCard item={mockItem} priority />);
491
+
492
+ expect(screen.getByRole('img')).toHaveAttribute('loading', 'eager');
493
+ });
494
+ });
495
+ ```
496
+
497
+ ---
498
+
499
+ ## Best Practices
500
+
501
+ ### Good
502
+
503
+ - Use functional components with hooks
504
+ - Extract reusable logic into custom hooks
505
+ - Memoize expensive calculations and callbacks
506
+ - Use proper TypeScript types for all props
507
+ - Implement error boundaries
508
+ - Use lazy loading for large components
509
+
510
+ ### Bad
511
+
512
+ - Inline function definitions in JSX (causes re-renders)
513
+ - Over-memoization (adds overhead when not needed)
514
+ - Prop drilling (use context or state management)
515
+ - Missing loading and error states
516
+ - Not cleaning up effects