@su-record/vibe 0.4.5 → 0.4.6

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 (35) hide show
  1. package/.claude/agents/simplifier.md +1 -1
  2. package/.claude/commands/vibe.analyze.md +1 -1
  3. package/.claude/commands/vibe.run.md +1 -1
  4. package/.claude/commands/vibe.spec.md +2 -2
  5. package/.claude/commands/vibe.verify.md +1 -1
  6. package/.claude/settings.local.json +3 -1
  7. package/README.md +4 -4
  8. package/bin/vibe +41 -13
  9. package/package.json +1 -1
  10. package/templates/hooks-template.json +1 -1
  11. package/.agent/rules/core/communication-guide.md +0 -104
  12. package/.agent/rules/core/development-philosophy.md +0 -53
  13. package/.agent/rules/core/quick-start.md +0 -121
  14. package/.agent/rules/languages/dart-flutter.md +0 -509
  15. package/.agent/rules/languages/go.md +0 -396
  16. package/.agent/rules/languages/java-spring.md +0 -586
  17. package/.agent/rules/languages/kotlin-android.md +0 -491
  18. package/.agent/rules/languages/python-django.md +0 -371
  19. package/.agent/rules/languages/python-fastapi.md +0 -386
  20. package/.agent/rules/languages/rust.md +0 -425
  21. package/.agent/rules/languages/swift-ios.md +0 -516
  22. package/.agent/rules/languages/typescript-nextjs.md +0 -441
  23. package/.agent/rules/languages/typescript-node.md +0 -375
  24. package/.agent/rules/languages/typescript-react-native.md +0 -446
  25. package/.agent/rules/languages/typescript-react.md +0 -525
  26. package/.agent/rules/languages/typescript-vue.md +0 -353
  27. package/.agent/rules/quality/bdd-contract-testing.md +0 -388
  28. package/.agent/rules/quality/checklist.md +0 -276
  29. package/.agent/rules/quality/testing-strategy.md +0 -437
  30. package/.agent/rules/standards/anti-patterns.md +0 -369
  31. package/.agent/rules/standards/code-structure.md +0 -291
  32. package/.agent/rules/standards/complexity-metrics.md +0 -312
  33. package/.agent/rules/standards/naming-conventions.md +0 -198
  34. package/.agent/rules/tools/mcp-hi-ai-guide.md +0 -665
  35. package/.agent/rules/tools/mcp-workflow.md +0 -51
@@ -1,525 +0,0 @@
1
- # ⚛️ TypeScript + React 품질 규칙
2
-
3
- ## 핵심 원칙 (core에서 상속)
4
-
5
- ```markdown
6
- ✅ 단일 책임 (SRP)
7
- ✅ 중복 제거 (DRY)
8
- ✅ 재사용성
9
- ✅ 낮은 복잡도
10
- ✅ 함수 ≤ 30줄, JSX ≤ 50줄
11
- ✅ 중첩 ≤ 3단계
12
- ✅ Cyclomatic complexity ≤ 10
13
- ```
14
-
15
- ## TypeScript/React 특화 규칙
16
-
17
- ### 1. 타입 안전성 100%
18
-
19
- ```typescript
20
- // ❌ any 사용
21
- function processData(data: any) {
22
- return data.value;
23
- }
24
-
25
- // ✅ 명확한 타입 정의
26
- interface User {
27
- id: string;
28
- name: string;
29
- email: string;
30
- age: number;
31
- }
32
-
33
- function processUser(user: User): string {
34
- return user.name;
35
- }
36
-
37
- // ✅ Generic 활용
38
- interface ApiResponse<T> {
39
- success: boolean;
40
- data: T;
41
- error?: string;
42
- }
43
-
44
- type UserResponse = ApiResponse<User>;
45
- type ProductResponse = ApiResponse<Product>;
46
- ```
47
-
48
- ### 2. 함수형 컴포넌트 + Hooks
49
-
50
- ```typescript
51
- // ✅ 함수형 컴포넌트 (권장)
52
- interface UserCardProps {
53
- user: User;
54
- onEdit?: (user: User) => void;
55
- }
56
-
57
- export function UserCard({ user, onEdit }: UserCardProps) {
58
- const [isEditing, setIsEditing] = useState(false);
59
-
60
- const handleEdit = useCallback(() => {
61
- if (onEdit) {
62
- onEdit(user);
63
- }
64
- }, [user, onEdit]);
65
-
66
- return (
67
- <div>
68
- <h2>{user.name}</h2>
69
- <button onClick={handleEdit}>Edit</button>
70
- </div>
71
- );
72
- }
73
-
74
- // ❌ 클래스 컴포넌트 (레거시)
75
- class UserCard extends React.Component<UserCardProps> {
76
- // 복잡하고 장황함
77
- }
78
- ```
79
-
80
- ### 3. Custom Hook으로 로직 분리
81
-
82
- ```typescript
83
- // ✅ Custom Hook (재사용 가능한 로직)
84
- interface UseUserOptions {
85
- userId: string;
86
- }
87
-
88
- interface UseUserReturn {
89
- user: User | null;
90
- isLoading: boolean;
91
- error: string | null;
92
- refetch: () => Promise<void>;
93
- }
94
-
95
- function useUser({ userId }: UseUserOptions): UseUserReturn {
96
- const [user, setUser] = useState<User | null>(null);
97
- const [isLoading, setIsLoading] = useState(false);
98
- const [error, setError] = useState<string | null>(null);
99
-
100
- const fetchUser = useCallback(async () => {
101
- setIsLoading(true);
102
- setError(null);
103
-
104
- try {
105
- const response = await fetch(`/api/users/${userId}`);
106
- const data = await response.json();
107
- setUser(data);
108
- } catch (err) {
109
- setError(err instanceof Error ? err.message : 'Unknown error');
110
- } finally {
111
- setIsLoading(false);
112
- }
113
- }, [userId]);
114
-
115
- useEffect(() => {
116
- fetchUser();
117
- }, [fetchUser]);
118
-
119
- return { user, isLoading, error, refetch: fetchUser };
120
- }
121
-
122
- // 사용
123
- function UserProfile({ userId }: { userId: string }) {
124
- const { user, isLoading, error } = useUser({ userId });
125
-
126
- if (isLoading) return <Spinner />;
127
- if (error) return <Error message={error} />;
128
- if (!user) return <NotFound />;
129
-
130
- return <UserCard user={user} />;
131
- }
132
- ```
133
-
134
- ### 4. Props 타입 정의
135
-
136
- ```typescript
137
- // ✅ Props 타입 명확히
138
- interface ButtonProps {
139
- variant?: 'primary' | 'secondary' | 'danger';
140
- size?: 'sm' | 'md' | 'lg';
141
- disabled?: boolean;
142
- loading?: boolean;
143
- onClick?: () => void;
144
- children: React.ReactNode;
145
- }
146
-
147
- export function Button({
148
- variant = 'primary',
149
- size = 'md',
150
- disabled = false,
151
- loading = false,
152
- onClick,
153
- children,
154
- }: ButtonProps) {
155
- return (
156
- <button
157
- className={`btn btn-${variant} btn-${size}`}
158
- disabled={disabled || loading}
159
- onClick={onClick}
160
- >
161
- {loading ? <Spinner /> : children}
162
- </button>
163
- );
164
- }
165
-
166
- // ✅ PropsWithChildren 활용
167
- import { PropsWithChildren } from 'react';
168
-
169
- interface CardProps {
170
- title: string;
171
- subtitle?: string;
172
- }
173
-
174
- export function Card({
175
- title,
176
- subtitle,
177
- children,
178
- }: PropsWithChildren<CardProps>) {
179
- return (
180
- <div>
181
- <h2>{title}</h2>
182
- {subtitle && <p>{subtitle}</p>}
183
- {children}
184
- </div>
185
- );
186
- }
187
- ```
188
-
189
- ### 5. React Query (서버 상태 관리)
190
-
191
- ```typescript
192
- // ✅ React Query로 서버 상태 관리
193
- import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
194
-
195
- function useUser(userId: string) {
196
- return useQuery({
197
- queryKey: ['user', userId],
198
- queryFn: () => fetchUser(userId),
199
- staleTime: 5 * 60 * 1000, // 5분
200
- });
201
- }
202
-
203
- function useUpdateUser() {
204
- const queryClient = useQueryClient();
205
-
206
- return useMutation({
207
- mutationFn: (data: UpdateUserData) => updateUser(data),
208
- onSuccess: (updatedUser) => {
209
- // 캐시 업데이트
210
- queryClient.setQueryData(['user', updatedUser.id], updatedUser);
211
- },
212
- });
213
- }
214
-
215
- // 사용
216
- function UserProfile({ userId }: { userId: string }) {
217
- const { data: user, isLoading, error } = useUser(userId);
218
- const updateMutation = useUpdateUser();
219
-
220
- if (isLoading) return <Spinner />;
221
- if (error) return <Error />;
222
-
223
- return (
224
- <div>
225
- <h1>{user.name}</h1>
226
- <button
227
- onClick={() => updateMutation.mutate({ id: userId, name: 'New Name' })}
228
- disabled={updateMutation.isPending}
229
- >
230
- Update
231
- </button>
232
- </div>
233
- );
234
- }
235
- ```
236
-
237
- ### 6. Zod로 Contract 정의
238
-
239
- ```typescript
240
- // ✅ Zod 스키마 (런타임 + 타입 검증)
241
- import { z } from 'zod';
242
-
243
- const createUserSchema = z.object({
244
- email: z.string().email(),
245
- username: z.string().min(3).max(50),
246
- password: z.string().min(8),
247
- age: z.number().min(0).max(150),
248
- });
249
-
250
- type CreateUserRequest = z.infer<typeof createUserSchema>;
251
-
252
- // 사용 (React Hook Form)
253
- import { useForm } from 'react-hook-form';
254
- import { zodResolver } from '@hookform/resolvers/zod';
255
-
256
- function SignUpForm() {
257
- const {
258
- register,
259
- handleSubmit,
260
- formState: { errors, isSubmitting },
261
- } = useForm<CreateUserRequest>({
262
- resolver: zodResolver(createUserSchema),
263
- });
264
-
265
- const onSubmit = async (data: CreateUserRequest) => {
266
- await registerUser(data);
267
- };
268
-
269
- return (
270
- <form onSubmit={handleSubmit(onSubmit)}>
271
- <input {...register('email')} />
272
- {errors.email && <span>{errors.email.message}</span>}
273
-
274
- <input {...register('username')} />
275
- {errors.username && <span>{errors.username.message}</span>}
276
-
277
- <input type="password" {...register('password')} />
278
- {errors.password && <span>{errors.password.message}</span>}
279
-
280
- <input type="number" {...register('age', { valueAsNumber: true })} />
281
- {errors.age && <span>{errors.age.message}</span>}
282
-
283
- <button type="submit" disabled={isSubmitting}>
284
- Sign Up
285
- </button>
286
- </form>
287
- );
288
- }
289
- ```
290
-
291
- ### 7. 컴포넌트 분리 (Extract Component)
292
-
293
- ```typescript
294
- // ❌ 긴 JSX (80줄)
295
- function UserDashboard() {
296
- return (
297
- <div>
298
- <header>
299
- <h1>Dashboard</h1>
300
- {/* 20줄 */}
301
- </header>
302
- <main>
303
- {/* 40줄 */}
304
- </main>
305
- <footer>
306
- {/* 20줄 */}
307
- </footer>
308
- </div>
309
- );
310
- }
311
-
312
- // ✅ 서브 컴포넌트 분리
313
- function UserDashboard() {
314
- return (
315
- <div>
316
- <DashboardHeader />
317
- <DashboardMain />
318
- <DashboardFooter />
319
- </div>
320
- );
321
- }
322
-
323
- function DashboardHeader() {
324
- return <header>{/* ... */}</header>;
325
- }
326
-
327
- function DashboardMain() {
328
- return <main>{/* ... */}</main>;
329
- }
330
-
331
- function DashboardFooter() {
332
- return <footer>{/* ... */}</footer>;
333
- }
334
- ```
335
-
336
- ### 8. useCallback + useMemo 최적화
337
-
338
- ```typescript
339
- // ✅ useCallback (함수 메모이제이션)
340
- function Parent() {
341
- const [count, setCount] = useState(0);
342
-
343
- // 매번 새 함수 생성 방지
344
- const handleClick = useCallback(() => {
345
- setCount(prev => prev + 1);
346
- }, []);
347
-
348
- return <Child onClick={handleClick} />;
349
- }
350
-
351
- const Child = React.memo<{ onClick: () => void }>(({ onClick }) => {
352
- return <button onClick={onClick}>Click</button>;
353
- });
354
-
355
- // ✅ useMemo (값 메모이제이션)
356
- function ExpensiveComponent({ data }: { data: number[] }) {
357
- const processedData = useMemo(() => {
358
- return data
359
- .map(expensiveCalculation)
360
- .filter(x => x > 0)
361
- .reduce((a, b) => a + b, 0);
362
- }, [data]);
363
-
364
- return <div>{processedData}</div>;
365
- }
366
- ```
367
-
368
- ### 9. Error Boundary
369
-
370
- ```typescript
371
- // ✅ Error Boundary (클래스 컴포넌트 필수)
372
- interface ErrorBoundaryProps {
373
- children: React.ReactNode;
374
- fallback?: React.ReactNode;
375
- }
376
-
377
- interface ErrorBoundaryState {
378
- hasError: boolean;
379
- error?: Error;
380
- }
381
-
382
- class ErrorBoundary extends React.Component<
383
- ErrorBoundaryProps,
384
- ErrorBoundaryState
385
- > {
386
- constructor(props: ErrorBoundaryProps) {
387
- super(props);
388
- this.state = { hasError: false };
389
- }
390
-
391
- static getDerivedStateFromError(error: Error): ErrorBoundaryState {
392
- return { hasError: true, error };
393
- }
394
-
395
- componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
396
- console.error('Error caught by boundary:', error, errorInfo);
397
- }
398
-
399
- render() {
400
- if (this.state.hasError) {
401
- return this.props.fallback || <ErrorFallback error={this.state.error} />;
402
- }
403
-
404
- return this.props.children;
405
- }
406
- }
407
-
408
- // 사용
409
- function App() {
410
- return (
411
- <ErrorBoundary fallback={<ErrorPage />}>
412
- <UserDashboard />
413
- </ErrorBoundary>
414
- );
415
- }
416
- ```
417
-
418
- ### 10. 타입 가드 활용
419
-
420
- ```typescript
421
- // ✅ 타입 가드
422
- interface Dog {
423
- type: 'dog';
424
- bark: () => void;
425
- }
426
-
427
- interface Cat {
428
- type: 'cat';
429
- meow: () => void;
430
- }
431
-
432
- type Animal = Dog | Cat;
433
-
434
- function isDog(animal: Animal): animal is Dog {
435
- return animal.type === 'dog';
436
- }
437
-
438
- function makeSound(animal: Animal) {
439
- if (isDog(animal)) {
440
- animal.bark(); // 타입 안전
441
- } else {
442
- animal.meow(); // 타입 안전
443
- }
444
- }
445
-
446
- // ✅ Discriminated Union
447
- function AnimalCard({ animal }: { animal: Animal }) {
448
- switch (animal.type) {
449
- case 'dog':
450
- return <DogCard dog={animal} />;
451
- case 'cat':
452
- return <CatCard cat={animal} />;
453
- }
454
- }
455
- ```
456
-
457
- ## 안티패턴
458
-
459
- ```typescript
460
- // ❌ Props drilling (3단계 이상)
461
- <GrandParent user={user}>
462
- <Parent user={user}>
463
- <Child user={user} />
464
- </Parent>
465
- </GrandParent>
466
-
467
- // ✅ Context 사용
468
- const UserContext = createContext<User | undefined>(undefined);
469
-
470
- <UserContext.Provider value={user}>
471
- <GrandParent />
472
- </UserContext.Provider>
473
-
474
- // ❌ useEffect 의존성 누락
475
- useEffect(() => {
476
- fetchUser(userId);
477
- }, []); // userId 의존성 누락!
478
-
479
- // ✅ 모든 의존성 명시
480
- useEffect(() => {
481
- fetchUser(userId);
482
- }, [userId]);
483
-
484
- // ❌ 인라인 객체/함수 (리렌더 유발)
485
- <Child config={{ theme: 'dark' }} onClick={() => {}} />
486
-
487
- // ✅ useMemo/useCallback
488
- const config = useMemo(() => ({ theme: 'dark' }), []);
489
- const handleClick = useCallback(() => {}, []);
490
- <Child config={config} onClick={handleClick} />
491
- ```
492
-
493
- ## 코드 품질 도구
494
-
495
- ```bash
496
- # TypeScript 컴파일
497
- tsc --noEmit
498
-
499
- # ESLint
500
- eslint src/ --ext .ts,.tsx
501
-
502
- # Prettier
503
- prettier --write src/
504
-
505
- # 테스트
506
- vitest
507
- # or
508
- jest
509
- ```
510
-
511
- ## 체크리스트
512
-
513
- TypeScript/React 코드 작성 시:
514
-
515
- - [ ] 타입 안전성 100% (no any)
516
- - [ ] 함수형 컴포넌트 + Hooks
517
- - [ ] Custom Hook으로 로직 분리
518
- - [ ] Props 타입 명확히 정의
519
- - [ ] React Query로 서버 상태 관리
520
- - [ ] Zod로 Contract 정의
521
- - [ ] JSX ≤ 50줄 (컴포넌트 분리)
522
- - [ ] useCallback/useMemo 최적화
523
- - [ ] Error Boundary 사용
524
- - [ ] 타입 가드 활용
525
- - [ ] 복잡도 ≤ 10