@su-record/vibe 2.8.36 → 2.8.37

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.
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.5+-blue)](https://www.typescriptlang.org/)
7
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
8
 
9
- **One install adds 56 agents, 36 skills, multi-LLM orchestration, and automated quality gates to your AI coding workflow.**
9
+ **One install adds 56 agents, 45 skills, multi-LLM orchestration, and automated quality gates to your AI coding workflow.**
10
10
 
11
11
  Works with Claude Code, Codex, Cursor, and Gemini CLI.
12
12
 
@@ -131,13 +131,17 @@ Event Content, Event Image, Event Speaker, Event Ops, Event Comms, Event Schedul
131
131
 
132
132
  ---
133
133
 
134
- ## Skills (36)
134
+ ## Skills (45)
135
135
 
136
- Domain-specific skill modules auto-installed based on detected stack.
136
+ Domain-specific skill modules auto-installed based on detected stack. Classified into 3 tiers to prevent context overload.
137
137
 
138
- **Core (15):** Core Capabilities, Parallel Research, Commit Push PR, Git Worktree, Handoff, Priority Todos, Tool Fallback, Context7, Tech Debt, Characterization Test, Agents MD, Claude MD Guide, Exec Plan, Arch Guard, Capability Loop
138
+ **Core (4):** Tech Debt, Characterization Test, Arch Guard, Exec Plan
139
139
 
140
- **Design (7):** Frontend Design, UI/UX Pro Max, Design Teach, Design Audit, Design Critique, Design Polish, Design Normalize
140
+ **Standard (11):** Parallel Research, Handoff, Priority Todos, Agents MD, Claude MD Guide, Capability Loop, Design Teach, Vibe Figma, Vibe Figma Extract, Vibe Figma Convert, Vibe Docs
141
+
142
+ **Optional (4):** Commit Push PR, Git Worktree, Tool Fallback, Context7
143
+
144
+ **Design (8):** UI/UX Pro Max, Design Audit, Design Critique, Design Polish, Design Normalize, Design Distill, Brand Assets, SEO Checklist
141
145
 
142
146
  **Domain (3):** Commerce Patterns, E2E Commerce, Video Production
143
147
 
@@ -145,7 +149,9 @@ Domain-specific skill modules auto-installed based on detected stack.
145
149
 
146
150
  **Event (3):** Event Planning, Event Comms, Event Ops
147
151
 
148
- **Stack-Specific (5):** TypeScript Advanced Types, Vercel React Best Practices, SEO Checklist, Brand Assets, Design Distill
152
+ **Stack-Specific (2):** TypeScript Advanced Types, Vercel React Best Practices
153
+
154
+ **Figma Pipeline (7):** Figma Rules, Figma Pipeline, Figma Frame, Figma Style, Figma Analyze, Figma Consolidate, Figma Codegen
149
155
 
150
156
  ### External Skills (skills.sh)
151
157
 
@@ -262,7 +268,7 @@ const runner = skills.resolve('review');
262
268
 
263
269
  ---
264
270
 
265
- ## Hooks (16 scripts)
271
+ ## Hooks (21 scripts)
266
272
 
267
273
  | Event | Script | Role |
268
274
  |-------|--------|------|
@@ -272,9 +278,11 @@ const runner = skills.resolve('review');
272
278
  | PostToolUse | `post-edit.js` | Git index update |
273
279
  | UserPromptSubmit | `prompt-dispatcher.js` | Command routing |
274
280
  | UserPromptSubmit | `keyword-detector.js` | Magic keyword detection |
281
+ | UserPromptSubmit | `llm-orchestrate.js` | Multi-LLM dispatch |
275
282
  | Notification | `context-save.js` | Auto-save at 80/90/95% context |
283
+ | Notification | `stop-notify.js` | Session end notification |
276
284
 
277
- Additional: `llm-orchestrate.js`, `codex-review-gate.js`, `codex-detect.js`, `sentinel-guard.js`, `skill-injector.js`, `evolution-engine.js`, `hud-status.js`, `stop-notify.js`
285
+ Additional: `codex-review-gate.js`, `codex-detect.js`, `sentinel-guard.js`, `skill-injector.js`, `evolution-engine.js`, `hud-status.js`, `auto-commit.js`, `auto-format.js`, `auto-test.js`, `command-log.js`, `pr-test-gate.js`, `figma-extract.js`
278
286
 
279
287
  ---
280
288
 
@@ -397,6 +405,10 @@ vibe figma status|logout # Token management
397
405
  vibe telegram setup|chat|status
398
406
  vibe slack setup|channel|status
399
407
 
408
+ # Diagnostics
409
+ vibe config show # Unified config view (global + project)
410
+ vibe stats [--week|--quality] # Usage telemetry summary
411
+
400
412
  # Other
401
413
  vibe env import [path] # Migrate .env → config.json
402
414
  vibe help / version
@@ -178,7 +178,7 @@ function parseAnalyzeImageArgs(args) {
178
178
  // CLI Provider Functions
179
179
  // ============================================
180
180
 
181
- const CLI_TIMEOUT_MS = 60000;
181
+ const CLI_TIMEOUT_MS = 180000;
182
182
  const CLI_FALLBACK_TIMEOUT_MS = 30000;
183
183
  const IS_WINDOWS = os.platform() === 'win32';
184
184
 
@@ -205,7 +205,7 @@ function callCodexCli(prompt, sysPrompt, jsonMode, model, timeoutMs) {
205
205
  const fullPrompt = buildCliPrompt(prompt, sysPrompt, jsonMode);
206
206
  const outputFile = path.join(os.tmpdir(), `vibe-codex-${crypto.randomUUID()}.txt`);
207
207
  // stdin pipe로 프롬프트 전달 (shell escaping 이슈 회피)
208
- const args = ['exec', '-m', model, '--sandbox', 'read-only', '--ephemeral', '-o', outputFile, '-'];
208
+ const args = ['exec', '-m', model, '--sandbox', 'read-only', '--ephemeral', '-c', 'model_reasoning_effort="medium"', '-o', outputFile, '-'];
209
209
 
210
210
  // config에 저장된 API key를 환경변수로 전달 (임베딩과 동일한 키 사용)
211
211
  const vibeConfig = readVibeConfig();
@@ -219,8 +219,7 @@ function callCodexCli(prompt, sysPrompt, jsonMode, model, timeoutMs) {
219
219
  timeout: effectiveTimeout,
220
220
  env,
221
221
  });
222
- proc.stdin.write(fullPrompt);
223
- proc.stdin.end();
222
+ proc.stdin.end(fullPrompt);
224
223
 
225
224
  let stderr = '';
226
225
  proc.stderr.on('data', (d) => { stderr += d.toString(); });
@@ -255,8 +254,7 @@ function callGeminiCli(prompt, sysPrompt, jsonMode, model, timeoutMs) {
255
254
  stdio: ['pipe', 'pipe', 'pipe'],
256
255
  timeout: effectiveTimeout,
257
256
  });
258
- proc.stdin.write(fullPrompt);
259
- proc.stdin.end();
257
+ proc.stdin.end(fullPrompt);
260
258
 
261
259
  let stdout = '';
262
260
  let stderr = '';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@su-record/vibe",
3
- "version": "2.8.36",
4
- "description": "AI Coding Framework for Claude Code — 49 agents, 41+ tools, multi-LLM orchestration",
3
+ "version": "2.8.37",
4
+ "description": "AI Coding Framework for Claude Code — 56 agents, 45 skills, multi-LLM orchestration",
5
5
  "type": "module",
6
6
  "main": "dist/cli/index.js",
7
7
  "exports": {
@@ -64,9 +64,99 @@ tier: standard
64
64
  - public/images/{feature}/ (또는 static/images/{feature}/)
65
65
  - styles/{feature}/ (layout/, components/ 하위)
66
66
 
67
- 5. 기존 컴포넌트 스캔:
67
+ 5. 기존 컴포넌트 스캔 + 인덱싱:
68
68
  - Glob "components/**/*.vue" or "components/**/*.tsx"
69
69
  - 재사용 가능한 컴포넌트 목록 수집 (GNB, Footer, Button 등)
70
+
71
+ 5-1. 컴포넌트 상세 인덱싱 (50개 이하 스캔):
72
+ 대상 파일 수집 (우선순위 순서, 합산 50개 이내):
73
+ barrel file index.ts → components/ui/ → components/common/ → components/shared/ → 나머지
74
+ 각 디렉토리 내에서는 1-depth 파일만 (하위 재귀 탐색 안 함)
75
+
76
+ 각 파일에 대해 2단계 추출:
77
+ a. Grep: defineProps|interface Props|<slot|@description|class=|className=
78
+ → 시작 줄 번호 탐색
79
+ b. Read: 시작줄 ~ +30줄 추출
80
+ Vue/Svelte template+script 분리 파일: 첫 300줄 전체 Read
81
+ barrel file (index.ts): 전체 Read
82
+
83
+ 추출 항목:
84
+ - Props/Interface: defineProps<{...}> 또는 interface Props {...} 에서 prop 이름+타입
85
+ ※ 외부 타입 참조 시 (defineProps<ButtonProps>()) → types 인덱스에서 교차 참조
86
+ - Slots: <slot> 또는 {children} 패턴
87
+ - 스타일 클래스: class="..." 또는 className={styles.xxx} 최상위 요소의 클래스명
88
+ - 용도 힌트: JSDoc @description 또는 파일 첫 번째 주석
89
+
90
+ 5-2. 인덱스 결과 저장:
91
+ 저장 경로: /tmp/{feature}/component-index.json
92
+ [
93
+ { name: "BaseButton",
94
+ path: "components/common/BaseButton.vue",
95
+ props: [{ name: "label", type: "string" }, { name: "variant", type: "'primary'|'secondary'" }],
96
+ slots: ["default"],
97
+ classes: ["btn", "btn--primary"],
98
+ description: "공통 버튼 컴포넌트" },
99
+ ...
100
+ ]
101
+
102
+ 컨텍스트 관리:
103
+ - 컴포넌트 20개 이하: 전체 인덱스를 프롬프트에 포함
104
+ - 컴포넌트 20개 초과: 이름+설명+축약 props(이름만, 타입 생략)만 포함
105
+ 매칭 후보 발견 시 해당 파일 Read로 상세 확인
106
+ - classes 필드는 요약에서 제외 (매칭 시 파일 Read로 확인)
107
+
108
+ 5-3. Hooks/Types/Constants 인덱싱:
109
+ 추가 스캔 대상:
110
+ - Composables/Hooks: composables/**/*.ts, hooks/**/*.ts
111
+ → export 함수명 + 파라미터 + 반환 타입
112
+ - 타입 정의: types/**/*.ts, types.ts
113
+ → export interface/type 이름 + 최상위 필드
114
+ - 상수: constants/**/*.ts
115
+ → export const 이름 + 값 (또는 타입)
116
+
117
+ 저장: /tmp/{feature}/context-index.json (component-index와 별도)
118
+ 컨텍스트 관리:
119
+ - 항목 30개 이하: 전체 인덱스를 프롬프트에 포함
120
+ - 항목 30개 초과: 이름+핵심 시그니처만 요약, 상세 필요 시 파일 Read로 지연 조회
121
+
122
+ 타임아웃: 파일당 Read 최대 300줄, 전체 인덱싱 2분 이내 완료
123
+
124
+ 6. 기존 디자인 토큰 스캔:
125
+
126
+ SCSS 토큰:
127
+ Glob: **/_variables.scss, **/_tokens.scss, **/_colors.scss, **/variables.scss
128
+ → 패턴: $변수명: 값; 추출
129
+ → 결과: { name: "$color-primary", value: "#3b82f6", source: "styles/_variables.scss" }
130
+
131
+ CSS Variables:
132
+ Glob: **/global.css, **/variables.css, **/root.css, **/app.css
133
+ Grep: "--[a-zA-Z].*:" 패턴
134
+ → 결과: { name: "--color-primary", value: "#3b82f6", source: "styles/global.css" }
135
+
136
+ Tailwind:
137
+ tailwind.config.{js,ts,mjs} 존재 시 Read
138
+ → theme.colors, theme.extend.colors 에서 커스텀 색상 추출
139
+ → theme.spacing, theme.fontSize 에서 커스텀 값 추출
140
+ → Tailwind v4: global CSS에서 @theme 디렉티브 내 CSS variable도 스캔
141
+ → 결과: { name: "blue-500", value: "#3b82f6", type: "tailwind", category: "color" }
142
+
143
+ CSS-in-JS:
144
+ Glob: **/theme.{ts,js}, **/tokens.{ts,js}, **/design-tokens.{ts,js}
145
+ → export 객체에서 color/spacing/typography 키 추출
146
+
147
+ 통합 결과 → /tmp/{feature}/project-tokens.json:
148
+ {
149
+ colors: [{ name, value, source }],
150
+ spacing: [{ name, value, source }],
151
+ typography: [{ name, value, source }],
152
+ other: [{ name, value, source }]
153
+ }
154
+
155
+ 토큰 소스 우선순위 (복수 시스템 공존 시):
156
+ Tailwind > CSS Variables > SCSS > CSS-in-JS
157
+
158
+ 성능: 100개 파일 기준 5초 이내 완료
159
+ 파싱 실패 시: 해당 파일 스킵 + 경고 로그 (전체 중단하지 않음)
70
160
  ```
71
161
 
72
162
  ---
@@ -190,10 +280,24 @@ Phase 1 완료 조건:
190
280
  Phase 1 컴포넌트가 준비된 상태에서, 디자인 URL로 시각 재료를 수집한다.
191
281
 
192
282
  사용자에게 질문한다:
193
- - question: "베이스 디자인(모바일) Figma URL을 입력해주세요."
283
+ - question: "디자인 Figma URL을 입력해주세요. 여러 페이지는 줄바꿈으로 구분."
194
284
  - options 제공 금지 — 자유 텍스트 입력만 허용
195
285
 
196
- ### 2-1. 디자인 재료 추출
286
+ ### 멀티 프레임 URL 검증
287
+
288
+ ```
289
+ URL 유효성 검증:
290
+ - 모든 URL에서 fileKey 추출 → 동일한 fileKey인지 확인
291
+ - 서로 다른 fileKey 발견 시 에러: "멀티 프레임은 동일 Figma 파일 내 다른 프레임만 지원합니다"
292
+ - node-id 파라미터 누락 시 해당 URL 에러 보고
293
+ - 최대 5개 URL까지 지원
294
+
295
+ URL 개수에 따른 처리:
296
+ 1개: 기존 방식 (변경 없음, 아래 2-1 그대로)
297
+ 2개 이상: 멀티 프레임 모드 활성화 (2-1-multi 참조)
298
+ ```
299
+
300
+ ### 2-1. 디자인 재료 추출 (단일 URL)
197
301
 
198
302
  ```
199
303
  URL에서 fileKey, nodeId 추출
@@ -214,11 +318,42 @@ URL에서 fileKey, nodeId 추출
214
318
  node "[FIGMA_SCRIPT]" screenshot {fileKey} {child.nodeId} --out=/tmp/{feature}/sections/{child.name}.png
215
319
  ```
216
320
 
321
+ ### 2-1-multi. 멀티 프레임 재료 확보 (2개 이상 URL)
322
+
323
+ ```
324
+ 각 URL에 대해 순차 추출 (Figma API rate limit: 요청 간 500ms 간격):
325
+ URL 1 → /tmp/{feature}/frame-1/ (full-screenshot, tree, images, sections)
326
+ URL 2 → /tmp/{feature}/frame-2/ (URL 1 완료 후 500ms 대기)
327
+ URL 3 → /tmp/{feature}/frame-3/ (URL 2 완료 후 500ms 대기)
328
+ ※ 추출 완료 후 후처리(섹션 분할 등)는 병렬 가능
329
+
330
+ 부분 실패 처리:
331
+ - 개별 URL 추출 실패 시 해당 frame만 건너뛰고 나머지 진행
332
+ - 실패한 frame은 사용자에게 즉시 보고: "frame-{N} 추출 실패: {에러 사유}" (API 에러, 권한 부족, 잘못된 nodeId 등)
333
+ - 성공한 frame ≥ 2: Phase 2.5 계속 진행
334
+ - 정확히 1개만 성공: 단일 프레임 모드로 폴백 (Phase 2.5 스킵)
335
+ - 0개 성공: 전체 실패 보고
336
+
337
+ 결과:
338
+ /tmp/{feature}/
339
+ ├── frame-1/ ← 메인 페이지
340
+ │ ├── full-screenshot.png
341
+ │ ├── tree.json
342
+ │ ├── images/
343
+ │ └── sections/
344
+ ├── frame-2/ ← 서브 페이지 1
345
+ │ └── ...
346
+ ├── frame-3/ ← 서브 페이지 2
347
+ │ └── ...
348
+ └── shared/ ← 공통 분석 결과 (Phase 2.5에서 생성)
349
+ ```
350
+
217
351
  ### 2-2. 재료함 정리
218
352
 
219
353
  ```
220
354
  Phase 2 완료 시 /tmp/{feature}/ 에 다음이 준비되어야 함:
221
355
 
356
+ 단일 URL:
222
357
  /tmp/{feature}/
223
358
  ├── full-screenshot.png ← 전체 정답 사진
224
359
  ├── tree.json ← 노드 트리 + CSS 수치
@@ -233,6 +368,8 @@ Phase 2 완료 시 /tmp/{feature}/ 에 다음이 준비되어야 함:
233
368
  ├── playtime-mission.png
234
369
  └── ...
235
370
 
371
+ 멀티 URL: 위 2-1-multi 결과 구조 참조
372
+
236
373
  재료 목록 (material-inventory):
237
374
  - 이미지: 파일명 + 크기 + 용도 추정 (BG/icon/title/decoration)
238
375
  - 색상: tree.json에서 추출한 모든 고유 색상값
@@ -254,12 +391,81 @@ Phase 2 완료 시 /tmp/{feature}/ 에 다음이 준비되어야 함:
254
391
 
255
392
  ---
256
393
 
394
+ ## Phase 2.5: 공통 패턴 분석 (멀티 프레임 전용)
395
+
396
+ **URL 2개 이상일 때만 실행. 단일 URL이면 Phase 3으로 건너뜀.**
397
+ **프레임 간 공통 요소를 식별하여 공유 컴포넌트로 추출한다.**
398
+
399
+ ```
400
+ 1. 시각 비교 — 각 프레임의 스크린샷을 순차 Read:
401
+ - frame-1/full-screenshot.png → frame-2/full-screenshot.png → ...
402
+ - 시각적으로 반복되는 요소 식별:
403
+ 상단 영역 (GNB/Header), 하단 영역 (Footer),
404
+ 카드 패턴, 버튼 스타일, 섹션 레이아웃
405
+
406
+ 2. 구조 비교 — 각 tree.json의 1depth 자식 비교:
407
+ - 동일한 name 또는 prefix 일치 (예: "GNB", "Header", "Footer", "Nav")
408
+ - 동일한 size (width와 height 모두 ±10% 이내): 같은 컴포넌트 후보
409
+ - 동일한 CSS 패턴: 같은 스타일 사용 (색상, 폰트, 레이아웃)
410
+
411
+ 3. 공통 컴포넌트 후보 목록:
412
+ shared-components:
413
+ - name: GNB
414
+ frames: [frame-1, frame-2, frame-3]
415
+ consistency: 100% (모든 프레임에서 동일)
416
+ action: 공유 컴포넌트로 1회만 생성
417
+ - name: Footer
418
+ frames: [frame-1, frame-3]
419
+ consistency: 67% (2/3 프레임)
420
+ action: 공유 컴포넌트 + frame-2는 다른 Footer
421
+ - name: CardItem
422
+ frames: [frame-1, frame-2]
423
+ size-match: 95%
424
+ action: 공유 컴포넌트 (props로 변형)
425
+
426
+ 4. 공통 토큰 추출:
427
+ - 모든 프레임의 색상 팔레트 합집합 → 공유 _tokens.scss
428
+ - 모든 프레임의 폰트 목록 합집합
429
+ - 모든 프레임의 간격 패턴 합집합
430
+ → 프레임별 고유 값만 프레임 로컬 토큰으로 분리
431
+ ```
432
+
433
+ ---
434
+
257
435
  ## Phase 3: 퍼즐 조립
258
436
 
259
437
  **Phase 1에서 만든 컴포넌트에 Phase 2의 재료로 디자인을 입힌다.**
260
438
  **스크린샷을 보면서 퍼즐을 맞추듯 조립한다.**
261
439
  **첫 섹션(Hero) 단독 완료 후 나머지 섹션 병렬 진행.**
262
440
 
441
+ **멀티 프레임 모드 시 조립 순서 변경:**
442
+ ```
443
+ 멀티 프레임 Phase 3 순서:
444
+
445
+ 1단계: 공유 컴포넌트 먼저 생성
446
+ - shared-components 목록의 컴포넌트를 components/shared/에 생성
447
+ - 가장 일관적인 프레임(shared-components 매칭 수가 가장 많은 프레임) 기준으로 조립
448
+ - 프레임별 변형은 props로 처리
449
+
450
+ 2단계: 프레임별 고유 섹션 조립
451
+ - frame-1 고유 섹션: 공유 컴포넌트 import + 고유 섹션 신규 생성
452
+ - frame-2 고유 섹션: 동일
453
+ - 각 프레임의 페이지 파일에서 공유 + 고유 컴포넌트 배치
454
+
455
+ 3단계: 스타일 구조
456
+ styles/{feature}/
457
+ ├── _tokens.scss ← 공유 토큰 (합집합)
458
+ ├── shared/ ← 공유 컴포넌트 스타일
459
+ │ ├── layout/_gnb.scss
460
+ │ └── components/_gnb.scss
461
+ ├── frame-1/ ← 메인 고유 스타일
462
+ │ ├── layout/
463
+ │ └── components/
464
+ └── frame-2/
465
+
466
+ 단일 URL: 기존 방식 그대로 (위 멀티 프레임 순서 무시)
467
+ ```
468
+
263
469
  ### 3-0. SCSS Setup + 등록 (첫 섹션 전)
264
470
 
265
471
  ```
@@ -269,16 +475,73 @@ Phase 1에서 생성한 빈 SCSS 파일에 기본 내용 Write:
269
475
  styles/{feature}/_mixins.scss ← breakpoint mixin
270
476
  styles/{feature}/_base.scss ← 루트 클래스
271
477
 
272
- 토큰 추출 (tree.json의 CSS 수치에서):
273
- - 색상 → primitive ($color-navy: #0a1628) + semantic ($color-bg-primary)
274
- - 폰트 $font-pretendard, $font-size-md: 16px
275
- - 간격 $space-sm: 8px, $space-md: 16px
478
+ 토큰 매핑 (기존 토큰 우선 사용):
479
+ 1. /tmp/{feature}/project-tokens.json Read로 로드
480
+ 2. Figma 재료함의 값에 대해 project-tokens에서 동일 값 검색:
481
+ - 색상: hex 정규화 후 완전 일치 (Figma RGBA 0-1 → hex, 3자리→6자리, 대소문자 무시)
482
+ ※ alpha < 1: 8자리 hex (#RRGGBBAA) 또는 rgba() 함수로 변환
483
+ - 간격: px 값 완전 일치 (rem→px: 1rem=16px)
484
+ - 폰트: family 이름 포함 매칭
485
+ 3. 매칭됨 → 기존 토큰 참조:
486
+ - SCSS: @use 'path' 로 기존 파일 import, $변수명 사용
487
+ - Tailwind: 해당 유틸리티 클래스 사용 (bg-blue-500)
488
+ - CSS Variables: var(--color-primary) 사용
489
+ 4. 매칭 안 됨 → 새 토큰 생성 (기존 방식)
490
+
491
+ _tokens.scss 구조:
492
+ // ─── 기존 토큰 참조 ────────────────────
493
+ @use '../../styles/variables' as v;
494
+
495
+ // ─── 매핑 (기존 토큰 → 피처 시맨틱) ────
496
+ $color-bg-primary: v.$color-navy; // 기존 재사용
497
+ $color-text-primary: v.$color-white; // 기존 재사용
498
+
499
+ // ─── 새 토큰 (매칭 안 된 값만) ─────────
500
+ $color-accent-gold: #ffd700; // 새 값
501
+ $space-section-gap: 42px; // 새 값
502
+
503
+ 매핑 결과 보고: "토큰 매핑: 12/18 매칭 (67%), 6개 새 토큰 생성"
504
+
505
+ 기존 토큰 파일 수정 금지 — 참조만 함
506
+ 같은 값의 토큰 중복 생성 금지
507
+ 새 토큰은 피처 스코프 네이밍 ($feature-color-xxx)
508
+
509
+ project-tokens.json 없는 경우 (기존 토큰 없음):
510
+ 기존 방식으로 전체 생성:
511
+ - 색상 → primitive ($color-navy: #0a1628) + semantic ($color-bg-primary)
512
+ - 폰트 → $font-pretendard, $font-size-md: 16px
513
+ - 간격 → $space-sm: 8px, $space-md: 16px
276
514
 
277
515
  스타일 등록 (BLOCKING):
278
516
  Grep "{feature}/index.scss" → 이미 등록되어 있으면 건너뜀.
279
517
  없으면 프로젝트 방식에 맞게 등록.
280
518
  ```
281
519
 
520
+ ### 3-0.5. 컴포넌트 매칭 (각 섹션 조립 전)
521
+
522
+ ```
523
+ /tmp/{feature}/component-index.json 을 Read로 로드한다.
524
+
525
+ 각 섹션 스크린샷 분석 후, 기존 컴포넌트 매칭:
526
+
527
+ 1. 스크린샷에서 식별된 UI 요소를 component-index와 대조
528
+ 2. 매칭 판정 기준:
529
+ - 필수: name/role 유사성 (시각적 역할 일치)
530
+ 버튼 → BaseButton, 네비게이션 → GNB, 카드 → Card, 모달 → Modal
531
+ - 보조: props 호환성 (필요 props가 기존 컴포넌트에 존재)
532
+ - 보조: slots 호환성 (필요 slot이 존재)
533
+ - 불일치: props/slots 50% 미만 호환이면 매칭 거부 → 새로 생성
534
+ 3. 매칭된 컴포넌트: import하여 props 전달 (내부 수정 금지)
535
+ 4. 매칭 안 됨: 새로 생성 (강제 재사용 금지)
536
+
537
+ 재사용 시 스타일 충돌 방지:
538
+ ✅ 기존 컴포넌트 import하여 사용
539
+ ✅ props로 variant/size 등 커스터마이즈
540
+ ✅ 래퍼 클래스로 position/size만 오버라이드
541
+ ❌ 기존 컴포넌트 내부 스타일 수정 금지
542
+ ❌ 90% 유사한데 새로 만들기 금지
543
+ ```
544
+
282
545
  ### 3-1. 섹션 조립 프로세스
283
546
 
284
547
  ```
@@ -354,6 +617,116 @@ URL 있으면:
354
617
 
355
618
  ---
356
619
 
620
+ ## Phase 3.5: 컴파일 게이트
621
+
622
+ **Phase 3 퍼즐 조립 완료 후, 브라우저 검증 전에 컴파일 성공을 보장한다.**
623
+ **컴파일 에러는 스킵 불가 — 반드시 수정 또는 사용자 보고.**
624
+ **Phase 3.5 실패 시 Phase 4 진행 불가 (hard gate).**
625
+
626
+ ```
627
+ 자동 반복: 컴파일 성공까지. 최대 3라운드.
628
+ ```
629
+
630
+ ### 3.5-0. 베이스라인 캡처 (Phase 3 변경 전)
631
+
632
+ ```
633
+ Phase 3 시작 전에 기존 프로젝트의 에러를 캡처:
634
+ 1. 타입 체크 베이스라인: (3.5-1에서 선택한 동일 명령 사용) > /tmp/{feature}/baseline-typecheck.txt 2>&1
635
+ 2. 빌드 베이스라인: npm run build > /tmp/{feature}/baseline-build.txt 2>&1
636
+
637
+ Phase 3.5에서는 baseline에 없는 **새로 발생한 에러만** 수정 대상.
638
+ baseline에 존재하던 에러는 무시하고 별도 보고 ("기존 에러 {N}개 유지").
639
+ vibe.figma가 생성/수정한 파일 외의 에러는 자동 수정 금지.
640
+ ```
641
+
642
+ ### 3.5-1. TypeScript 컴파일 체크
643
+
644
+ ```
645
+ 1. 프로젝트 타입 체커 감지 → 실행:
646
+ - package.json scripts에 type-check 또는 typecheck 존재 → npm run type-check 사용
647
+ - vue-tsc 설치 확인 (Vue 프로젝트) → npx vue-tsc --noEmit 2>&1
648
+ - svelte-check 설치 확인 (Svelte 프로젝트) → npx svelte-check 2>&1
649
+ - 위 해당 없음 → fallback: npx tsc --noEmit 2>&1
650
+ → 에러 0개: PASS → 다음 단계
651
+ → 에러 있음: 에러 메시지 파싱 → 자동 수정
652
+
653
+ 2. 에러 파싱:
654
+ 각 에러에서 추출: 파일 경로, 줄 번호, 에러 코드, 메시지
655
+ 예: "src/components/Hero.tsx(15,3): error TS2322: Type 'string' is not assignable to type 'number'"
656
+
657
+ 3. 자동 수정 (에러 유형별):
658
+ - TS2322 (타입 불일치): prop 타입을 올바르게 수정
659
+ - TS2304 (이름 없음): import 추가
660
+ - TS2339 (프로퍼티 없음): interface에 프로퍼티 추가
661
+ - TS7006 (암시적 any): 타입 어노테이션 추가
662
+ - 기타: Read로 해당 파일+줄 확인 → 컨텍스트 기반 수정
663
+ ```
664
+
665
+ ### 3.5-2. 빌드 체크
666
+
667
+ ```
668
+ 1. npm run build 실행:
669
+ Bash: npm run build 2>&1
670
+ → 성공: PASS → 다음 단계
671
+ → 실패: 에러 메시지 파싱 → 자동 수정
672
+ → 타임아웃: 최대 120초 (초과 시 해당 라운드 실패 처리)
673
+
674
+ 2. 일반적 빌드 에러 처리:
675
+ - SCSS 컴파일 에러: 변수명/import 오류 수정
676
+ - Module not found: import 경로 수정 (.js 확장자 등)
677
+ - ESLint 에러 (--max-warnings 초과): 자동 수정 가능한 것 처리
678
+ ```
679
+
680
+ ### 3.5-3. dev 서버 시작 확인
681
+
682
+ ```
683
+ 1. dev 서버 시작 + PID 캡처:
684
+ Bash: npm run dev & echo $! → DEV_PID 저장
685
+ → localhost 포트 자동 감지: npm run dev stdout에서 localhost:\d+ 또는 port \d+ 파싱
686
+ 감지 실패 시 기본값 3000, 5173, 4173 순서 시도
687
+ → 포트 폴링 (3초 간격, 최대 30초 대기)
688
+ → 성공: Phase 4 진행 (Phase 4 완료 후 정리)
689
+ → 실패: kill $DEV_PID → 에러 로그 확인 → 수정 → 재시도
690
+
691
+ 2. 프로세스 정리 규칙:
692
+ - Phase 4 완료 또는 3라운드 실패 시 반드시 정리
693
+ - 정리 순서: kill $DEV_PID → 3초 대기 → kill -9 $DEV_PID (응답 없으면)
694
+ - lsof -i :{port} -t 로 포트 점유 프로세스 확인 후 추가 정리
695
+ ※ spawned child process만 대상 — 관련 없는 프로세스 kill 금지
696
+ - interrupt 시에도 cleanup 보장
697
+ ```
698
+
699
+ ### 3.5-4. 수정 루프
700
+
701
+ ```
702
+ 라운드 1~3:
703
+ 1. tsc → build → dev 순서로 체크
704
+ 2. 첫 번째 실패 단계의 에러 수정
705
+ 3. 수정 후 해당 단계부터 재체크
706
+ 4. 모든 단계 통과: Phase 4 진행
707
+
708
+ 라운드 종료 조건:
709
+ - 3라운드 후 실패: 에러 목록 + 시도한 수정을 사용자에게 보고
710
+ - 같은 에러 반복: 해당 에러 스킵 불가 → 사용자 보고 (컴파일 에러는 스킵 불가)
711
+
712
+ 컴파일 게이트 결과 보고:
713
+
714
+ ✅ 통과:
715
+ "Phase 3.5: 컴파일 게이트 PASS (라운드 {N})"
716
+ - tsc: 0 errors
717
+ - build: success
718
+ - dev server: running on localhost:{port}
719
+
720
+ ❌ 실패 (3라운드 후):
721
+ "Phase 3.5: 컴파일 게이트 FAIL"
722
+ - 남은 에러 목록 (파일, 줄, 메시지)
723
+ - 시도한 수정 내역
724
+ - 사용자 수동 수정 필요
725
+ → Phase 4 진행하지 않음
726
+ ```
727
+
728
+ ---
729
+
357
730
  ## Phase 4: 검증 루프
358
731
 
359
732
  **Puppeteer + CDP로 실제 렌더링 결과를 확인하며 자동 수정한다.**
@@ -368,8 +741,8 @@ URL 있으면:
368
741
 
369
742
  ```
370
743
  1. dev 서버 시작:
371
- npm run dev (또는 프로젝트 dev 명령)
372
- → localhost:3000 (또는 해당 포트) 확인
744
+ Phase 3.5에서 이미 시작된 dev 서버 사용 (재시작 불필요)
745
+ → localhost:{port} 확인
373
746
 
374
747
  2. Puppeteer 브라우저 시작:
375
748
  import { launchBrowser, openPage } from 'src/infra/lib/browser'
@@ -455,8 +828,11 @@ import { extractImages, extractTextContent } from 'src/infra/lib/browser'
455
828
  - 텍스트 누락 → 재료함의 정확한 텍스트 삽입
456
829
  - CSS 수치 틀림 → 재료함(tree.json)의 정확한 값으로 교체
457
830
  ⚠️ 추정으로 수정하지 않는다. 반드시 재료함 참조.
458
- 3. 수정 후 페이지 리로드 → 다시 캡처 → 비교
459
- 4. P1=0 이면 종료
831
+ 3. 수정 후 컴파일 재검증:
832
+ Bash: npx tsc --noEmit 2>&1 (또는 3.5-1에서 선택한 타입 체커)
833
+ → 시각 수정이 타입 에러를 유발하면 즉시 타입 에러 수정 후 진행
834
+ 4. 페이지 리로드 → 다시 캡처 → 비교
835
+ 5. P1=0 이면 종료
460
836
 
461
837
  라운드 종료 조건:
462
838
  - P1=0: 성공 → 브라우저 종료, 결과 보고
@@ -16,6 +16,22 @@ tier: standard
16
16
 
17
17
  ---
18
18
 
19
+ ## 0. 재사용 확인 (코드 작성 전)
20
+
21
+ ```
22
+ component-index (/tmp/{feature}/component-index.json) 에서 매칭되는 컴포넌트가 있으면:
23
+
24
+ ✅ import하여 사용 (새로 만들지 않음)
25
+ ✅ props로 커스터마이즈 (variant, size 등)
26
+ ✅ 래퍼 클래스로 위치/크기만 조정
27
+ ❌ 기존 컴포넌트 내부 수정
28
+ ❌ 90% 유사한데 새로 만들기
29
+
30
+ 매칭 안 되면 → 섹션 1 프로세스로 새로 생성 (기존 방식)
31
+ ```
32
+
33
+ ---
34
+
19
35
  ## 1. 코드 생성 프로세스
20
36
 
21
37
  ```
@@ -120,9 +136,20 @@ components/ → font-size, font-weight, color, line-height, letter-spacing,
120
136
  }
121
137
  ```
122
138
 
123
- ### _tokens.scss 구조 (primitive/semantic 분리)
139
+ ### _tokens.scss 구조 (기존 토큰 참조 + 새 토큰)
124
140
 
125
141
  ```scss
142
+ // ─── 기존 토큰 참조 (프로젝트에 이미 있는 경우) ───
143
+ // project-tokens.json 매칭 결과에 따라 @use로 참조
144
+ @use '../../styles/variables' as v;
145
+
146
+ // ─── 매핑 (기존 토큰 → 피처 시맨틱 별칭) ────────
147
+ $color-bg-primary: v.$color-navy; // 기존 토큰 재사용
148
+ $color-text-primary: v.$color-white; // 기존 토큰 재사용
149
+
150
+ // ─── 새 토큰 (매칭 안 된 값만 생성) ─────────────
151
+ // 기존 토큰이 없는 프로젝트에서는 아래처럼 전체 생성 (기존 방식)
152
+
126
153
  // ─── Primitive (재료함의 원시 값) ────────────────
127
154
  $color-white: #ffffff;
128
155
  $color-black: #000000;
@@ -113,9 +113,16 @@ Bash:
113
113
  title.png | 620×174 | 타이틀 이미지
114
114
  btn-share.png | 48×48 | 아이콘 (작은 사이즈)
115
115
 
116
- 색상 팔레트 (tree.json에서 고유값 추출):
116
+ 색상 팔레트 (tree.json에서 고유값 추출 + 토큰 매핑 힌트):
117
117
  #0a1628, #00264a, #ffffff, #dadce3, #003879, #419bd3, ...
118
118
 
119
+ 토큰 매핑 테이블 (project-tokens.json 존재 시):
120
+ | Figma 값 | 기존 토큰 | 상태 |
121
+ |----------|-----------|------|
122
+ | #0a1628 | $color-navy | ✅ 재사용 |
123
+ | #ffd700 | — | 🆕 생성 |
124
+ | #3b82f6 | $color-primary | ✅ 재사용 |
125
+
119
126
  폰트 목록:
120
127
  Pretendard: 400/500/700, 16px~48px
121
128
  Roboto Condensed: 700, 24px~36px