@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
|
[](https://www.typescriptlang.org/)
|
|
7
7
|
[](https://opensource.org/licenses/MIT)
|
|
8
8
|
|
|
9
|
-
**One install adds 56 agents,
|
|
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 (
|
|
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 (
|
|
138
|
+
**Core (4):** Tech Debt, Characterization Test, Arch Guard, Exec Plan
|
|
139
139
|
|
|
140
|
-
**
|
|
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 (
|
|
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 (
|
|
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: `
|
|
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 =
|
|
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.
|
|
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.
|
|
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.
|
|
4
|
-
"description": "AI Coding Framework for Claude Code —
|
|
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: "
|
|
283
|
+
- question: "디자인 Figma URL을 입력해주세요. 여러 페이지는 줄바꿈으로 구분."
|
|
194
284
|
- options 제공 금지 — 자유 텍스트 입력만 허용
|
|
195
285
|
|
|
196
|
-
###
|
|
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
|
-
토큰
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
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
|
-
|
|
372
|
-
→ localhost:
|
|
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
|
-
|
|
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 구조 (
|
|
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
|