@su-record/vibe 2.8.18 → 2.8.20

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.
@@ -15,6 +15,14 @@ type DeepPartial<T> = {
15
15
  [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
16
16
  };
17
17
  export declare function patchGlobalConfig(patch: DeepPartial<GlobalVibeConfig>): void;
18
+ /** .claude/vibe/config.json (프로젝트별 설정) */
19
+ export declare function getProjectConfigPath(projectDir: string): string;
20
+ /**
21
+ * 다중 계층 설정 병합: 글로벌(~/.vibe) + 프로젝트(.claude/vibe)
22
+ * 우선순위: 프로젝트 > 글로벌 (프로젝트 설정이 글로벌을 덮어씀)
23
+ * credentials는 글로벌 전용 — 프로젝트에서 덮어쓰지 않음.
24
+ */
25
+ export declare function resolveConfig(projectDir: string): GlobalVibeConfig;
18
26
  export declare function getGptApiKey(): string | null;
19
27
  export declare function getGeminiApiKey(): string | null;
20
28
  export declare function getModelOverride(key: string): string | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"GlobalConfigManager.d.ts","sourceRoot":"","sources":["../../../../src/infra/lib/config/GlobalConfigManager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAsB9D,2BAA2B;AAC3B,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,0BAA0B;AAC1B,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAQD,wBAAgB,gBAAgB,IAAI,gBAAgB,CA6BnD;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAQhE;AAID,KAAK,WAAW,CAAC,CAAC,IAAI;KACnB,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAChE,CAAC;AAwBF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAK5E;AAID,wBAAgB,YAAY,IAAI,MAAM,GAAG,IAAI,CAE5C;AAED,wBAAgB,eAAe,IAAI,MAAM,GAAG,IAAI,CAE/C;AAID,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAIhE;AA0DD;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CA2KzC"}
1
+ {"version":3,"file":"GlobalConfigManager.d.ts","sourceRoot":"","sources":["../../../../src/infra/lib/config/GlobalConfigManager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAsB9D,2BAA2B;AAC3B,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,0BAA0B;AAC1B,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAQD,wBAAgB,gBAAgB,IAAI,gBAAgB,CA6BnD;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAQhE;AAID,KAAK,WAAW,CAAC,CAAC,IAAI;KACnB,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAChE,CAAC;AAwBF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAK5E;AAID,0CAA0C;AAC1C,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE/D;AAeD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB,CAiBlE;AAID,wBAAgB,YAAY,IAAI,MAAM,GAAG,IAAI,CAE5C;AAED,wBAAgB,eAAe,IAAI,MAAM,GAAG,IAAI,CAE/C;AAID,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAIhE;AA0DD;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CA2KzC"}
@@ -95,6 +95,43 @@ export function patchGlobalConfig(patch) {
95
95
  merged.version = '1';
96
96
  writeGlobalConfig(merged);
97
97
  }
98
+ // ─── Project config + layered merge ────────────────────────────────
99
+ /** .claude/vibe/config.json (프로젝트별 설정) */
100
+ export function getProjectConfigPath(projectDir) {
101
+ return path.join(projectDir, '.claude', 'vibe', 'config.json');
102
+ }
103
+ function readProjectConfig(projectDir) {
104
+ const configPath = getProjectConfigPath(projectDir);
105
+ try {
106
+ if (!fs.existsSync(configPath))
107
+ return {};
108
+ const content = fs.readFileSync(configPath, 'utf-8');
109
+ const parsed = JSON.parse(content);
110
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
111
+ return {};
112
+ return parsed;
113
+ }
114
+ catch {
115
+ return {};
116
+ }
117
+ }
118
+ /**
119
+ * 다중 계층 설정 병합: 글로벌(~/.vibe) + 프로젝트(.claude/vibe)
120
+ * 우선순위: 프로젝트 > 글로벌 (프로젝트 설정이 글로벌을 덮어씀)
121
+ * credentials는 글로벌 전용 — 프로젝트에서 덮어쓰지 않음.
122
+ */
123
+ export function resolveConfig(projectDir) {
124
+ const global = readGlobalConfig();
125
+ const project = readProjectConfig(projectDir);
126
+ if (Object.keys(project).length === 0) {
127
+ return global;
128
+ }
129
+ // credentials는 글로벌 전용이므로 프로젝트에서 제거 후 병합
130
+ const { credentials: _ignored, ...projectWithoutCreds } = project;
131
+ const merged = deepMerge(global, projectWithoutCreds);
132
+ merged.version = '1';
133
+ return merged;
134
+ }
98
135
  // ─── Credential helpers ─────────────────────────────────────────────
99
136
  export function getGptApiKey() {
100
137
  return readGlobalConfig().credentials?.gpt?.apiKey ?? null;
@@ -1 +1 @@
1
- {"version":3,"file":"GlobalConfigManager.js","sourceRoot":"","sources":["../../../../src/infra/lib/config/GlobalConfigManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"GlobalConfigManager.js","sourceRoot":"","sources":["../../../../src/infra/lib/config/GlobalConfigManager.ts"],"names":[],"mappings":"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"}
@@ -2,8 +2,14 @@
2
2
  * Notification Hook - 컨텍스트 자동 저장 (80/90/95%) + 세션 요약 + Reflection
3
3
  * Usage: node context-save.js <urgency>
4
4
  * urgency: medium | high | critical
5
+ *
6
+ * 구조적 메타데이터를 자동 추출하여 세션 복원 품질을 높임.
7
+ * (claw-code compact.rs 패턴 참조)
5
8
  */
6
9
  import { getToolsBaseUrl, getLibBaseUrl, PROJECT_DIR } from './utils.js';
10
+ import { execSync } from 'child_process';
11
+ import fs from 'fs';
12
+ import path from 'path';
7
13
 
8
14
  const BASE_URL = getToolsBaseUrl();
9
15
  const LIB_URL = getLibBaseUrl();
@@ -18,13 +24,94 @@ const summaryMap = {
18
24
  // Debounce: track last reflection level per session to avoid duplicates
19
25
  let lastReflectionLevel = null;
20
26
 
27
+ /**
28
+ * 프로젝트 환경에서 구조적 메타데이터를 추출.
29
+ * 실패 시 빈 객체 반환 (non-blocking).
30
+ */
31
+ function extractStructuredMetadata() {
32
+ const metadata = {
33
+ recentFiles: [],
34
+ gitBranch: null,
35
+ pendingWork: [],
36
+ toolsUsed: [],
37
+ timestamp: new Date().toISOString(),
38
+ };
39
+
40
+ try {
41
+ // 최근 수정 파일 (최대 8개, 확장자 기반 필터)
42
+ const gitDiff = execSync('git diff --name-only HEAD 2>/dev/null || true', {
43
+ cwd: PROJECT_DIR, encoding: 'utf-8', timeout: 3000,
44
+ }).trim();
45
+ const staged = execSync('git diff --cached --name-only 2>/dev/null || true', {
46
+ cwd: PROJECT_DIR, encoding: 'utf-8', timeout: 3000,
47
+ }).trim();
48
+
49
+ const allFiles = [...new Set([...gitDiff.split('\n'), ...staged.split('\n')])]
50
+ .filter(f => f && /\.(ts|tsx|js|jsx|py|rs|go|java|json|md|css|html|vue|svelte)$/.test(f))
51
+ .slice(0, 8);
52
+ metadata.recentFiles = allFiles;
53
+
54
+ // 현재 브랜치
55
+ const branch = execSync('git branch --show-current 2>/dev/null || true', {
56
+ cwd: PROJECT_DIR, encoding: 'utf-8', timeout: 2000,
57
+ }).trim();
58
+ if (branch) metadata.gitBranch = branch;
59
+ } catch { /* git 없는 환경 무시 */ }
60
+
61
+ try {
62
+ // SPEC/TODO에서 진행 중 작업 추출
63
+ const specDir = path.join(PROJECT_DIR, '.claude', 'vibe', 'specs');
64
+ if (fs.existsSync(specDir)) {
65
+ const specs = fs.readdirSync(specDir).filter(f => f.endsWith('.md')).slice(0, 3);
66
+ for (const spec of specs) {
67
+ metadata.pendingWork.push(`SPEC: ${spec.replace('.md', '')}`);
68
+ }
69
+ }
70
+ const todoDir = path.join(PROJECT_DIR, '.claude', 'vibe', 'todos');
71
+ if (fs.existsSync(todoDir)) {
72
+ const todos = fs.readdirSync(todoDir).filter(f => f.endsWith('.md')).slice(0, 3);
73
+ for (const todo of todos) {
74
+ metadata.pendingWork.push(`TODO: ${todo.replace('.md', '')}`);
75
+ }
76
+ }
77
+ } catch { /* 파일 시스템 접근 실패 무시 */ }
78
+
79
+ return metadata;
80
+ }
81
+
82
+ /**
83
+ * 구조적 요약 텍스트 생성 (claw-code compact.rs 패턴)
84
+ */
85
+ function buildStructuredSummary(baseMessage, metadata) {
86
+ const sections = [baseMessage];
87
+
88
+ if (metadata.gitBranch) {
89
+ sections.push(`Branch: ${metadata.gitBranch}`);
90
+ }
91
+ if (metadata.recentFiles.length > 0) {
92
+ sections.push(`Key files: ${metadata.recentFiles.join(', ')}`);
93
+ }
94
+ if (metadata.pendingWork.length > 0) {
95
+ sections.push(`Pending work: ${metadata.pendingWork.join('; ')}`);
96
+ }
97
+ if (metadata.toolsUsed.length > 0) {
98
+ sections.push(`Tools used: ${metadata.toolsUsed.join(', ')}`);
99
+ }
100
+
101
+ return sections.join('\n');
102
+ }
103
+
21
104
  async function main() {
22
105
  try {
106
+ const metadata = extractStructuredMetadata();
107
+ const baseMessage = summaryMap[urgency] || summaryMap.medium;
108
+ const structuredSummary = buildStructuredSummary(baseMessage, metadata);
109
+
23
110
  const module = await import(`${BASE_URL}memory/index.js`);
24
111
  const result = await module.autoSaveContext({
25
112
  urgency,
26
113
  contextType: 'progress',
27
- summary: summaryMap[urgency] || summaryMap.medium,
114
+ summary: structuredSummary,
28
115
  projectPath: PROJECT_DIR,
29
116
  });
30
117
  const percent = urgency === 'critical' ? '95' : urgency === 'high' ? '90' : '80';
@@ -110,9 +110,34 @@ function formatOutput(toolName, validation) {
110
110
  return lines.join('\n');
111
111
  }
112
112
 
113
- // 메인 실행
114
- const toolName = process.argv[2] || 'Bash';
115
- const toolInput = process.argv[3] || process.env.TOOL_INPUT || '';
113
+ /**
114
+ * stdin에서 JSON 페이로드 읽기 (Claude Code 하네스 호환)
115
+ * stdin이 없거나 파싱 실패 시 argv/env 폴백
116
+ */
117
+ function readStdinSync() {
118
+ try {
119
+ if (process.stdin.isTTY) return null;
120
+ const fd = fs.openSync('/dev/stdin', 'r');
121
+ const buf = Buffer.alloc(65536);
122
+ const bytesRead = fs.readSync(fd, buf, 0, buf.length, null);
123
+ fs.closeSync(fd);
124
+ if (bytesRead > 0) {
125
+ return JSON.parse(buf.toString('utf-8', 0, bytesRead));
126
+ }
127
+ } catch { /* 파싱 실패 시 폴백 */ }
128
+ return null;
129
+ }
130
+
131
+ import fs from 'fs';
132
+
133
+ // 메인 실행: stdin JSON 우선, argv 폴백
134
+ const stdinPayload = readStdinSync();
135
+ const toolName = stdinPayload?.tool_name || process.argv[2] || 'Bash';
136
+ const toolInput = stdinPayload?.tool_input
137
+ ? (typeof stdinPayload.tool_input === 'string'
138
+ ? stdinPayload.tool_input
139
+ : JSON.stringify(stdinPayload.tool_input))
140
+ : (process.argv[3] || process.env.TOOL_INPUT || '');
116
141
 
117
142
  const validation = validateCommand(toolName, toolInput);
118
143
  const output = formatOutput(toolName, validation);
@@ -121,5 +146,5 @@ if (output) {
121
146
  console.log(output);
122
147
  }
123
148
 
124
- // Exit code: 0 = allowed, 1 = blocked
125
- process.exit(validation.allowed ? 0 : 1);
149
+ // Exit code: 0 = allowed, 2 = denied (claw-code 규약), 1 = 레거시 호환
150
+ process.exit(validation.allowed ? 0 : 2);
@@ -90,15 +90,39 @@ function guard(toolName, toolInput) {
90
90
  return undefined;
91
91
  }
92
92
 
93
- // Main execution
94
- const toolName = process.argv[2] || '';
95
- const toolInput = process.argv[3] || process.env.TOOL_INPUT || '';
93
+ import fs from 'fs';
94
+
95
+ /**
96
+ * stdin에서 JSON 페이로드 읽기 (Claude Code 하네스 호환)
97
+ */
98
+ function readStdinSync() {
99
+ try {
100
+ if (process.stdin.isTTY) return null;
101
+ const fd = fs.openSync('/dev/stdin', 'r');
102
+ const buf = Buffer.alloc(65536);
103
+ const bytesRead = fs.readSync(fd, buf, 0, buf.length, null);
104
+ fs.closeSync(fd);
105
+ if (bytesRead > 0) {
106
+ return JSON.parse(buf.toString('utf-8', 0, bytesRead));
107
+ }
108
+ } catch { /* 폴백 */ }
109
+ return null;
110
+ }
111
+
112
+ // Main execution: stdin JSON 우선, argv 폴백
113
+ const stdinPayload = readStdinSync();
114
+ const toolName = stdinPayload?.tool_name || process.argv[2] || '';
115
+ const toolInput = stdinPayload?.tool_input
116
+ ? (typeof stdinPayload.tool_input === 'string'
117
+ ? stdinPayload.tool_input
118
+ : JSON.stringify(stdinPayload.tool_input))
119
+ : (process.argv[3] || process.env.TOOL_INPUT || '');
96
120
 
97
121
  const result = guard(toolName, toolInput);
98
122
 
99
123
  if (result) {
100
124
  console.log(JSON.stringify(result));
101
- process.exit(1);
125
+ process.exit(2); // deny 규약
102
126
  }
103
127
 
104
128
  process.exit(0);
@@ -36,6 +36,54 @@ export function readVibeConfig() {
36
36
  return {};
37
37
  }
38
38
 
39
+ /**
40
+ * 프로젝트 설정(.claude/vibe/config.json) 읽기
41
+ * @returns {object} 파싱된 config 또는 빈 객체
42
+ */
43
+ export function readProjectConfig() {
44
+ const configPath = path.join(PROJECT_DIR, '.claude', 'vibe', 'config.json');
45
+ try {
46
+ if (fs.existsSync(configPath)) {
47
+ return JSON.parse(fs.readFileSync(configPath, 'utf-8'));
48
+ }
49
+ } catch { /* ignore */ }
50
+ return {};
51
+ }
52
+
53
+ /**
54
+ * Deep merge: source의 값이 target을 덮어씀 (배열은 교체)
55
+ */
56
+ function deepMerge(target, source) {
57
+ const result = { ...target };
58
+ for (const key of Object.keys(source)) {
59
+ const srcVal = source[key];
60
+ if (srcVal === undefined) continue;
61
+ const tgtVal = target[key];
62
+ if (
63
+ tgtVal && typeof tgtVal === 'object' && !Array.isArray(tgtVal) &&
64
+ srcVal && typeof srcVal === 'object' && !Array.isArray(srcVal)
65
+ ) {
66
+ result[key] = deepMerge(tgtVal, srcVal);
67
+ } else {
68
+ result[key] = srcVal;
69
+ }
70
+ }
71
+ return result;
72
+ }
73
+
74
+ /**
75
+ * 다중 계층 설정 병합: 글로벌 + 프로젝트
76
+ * 우선순위: 프로젝트 > 글로벌 (credentials는 글로벌 전용)
77
+ * @returns {object} 병합된 config
78
+ */
79
+ export function resolveVibeConfig() {
80
+ const global = readVibeConfig();
81
+ const project = readProjectConfig();
82
+ if (Object.keys(project).length === 0) return global;
83
+ const { credentials: _ignored, ...projectWithoutCreds } = project;
84
+ return deepMerge(global, projectWithoutCreds);
85
+ }
86
+
39
87
  /**
40
88
  * 파일 시스템 경로를 file:// URL로 변환 (크로스 플랫폼)
41
89
  * - macOS/Linux: /Users/grove/... → file:///Users/grove/...
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@su-record/vibe",
3
- "version": "2.8.18",
3
+ "version": "2.8.20",
4
4
  "description": "AI Coding Framework for Claude Code — 49 agents, 41+ tools, multi-LLM orchestration",
5
5
  "type": "module",
6
6
  "main": "dist/cli/index.js",
@@ -132,25 +132,129 @@ Popup: 패턴 분류 (확인/취소, 상세 모달, 알림, 입력 폼)
132
132
  - 개요 JSDoc 주석 (A-2에서 추출한 overview)
133
133
  ```
134
134
 
135
- ### 섹션 컴포넌트 필수 포함 사항
135
+ ### HARD RULE: template 금지
136
136
 
137
137
  ```
138
- 섹션 컴포넌트에 반드시 포함:
139
-
140
- 1. JSDoc 주석:
141
- - [기능 정의] — A-2에서 추출한 기능 설명
142
- - [인터랙션] ①②③ 번호 + 동작 설명
143
- - [상태] 해당 섹션의 상태 목록
138
+ 브라우저에서 열었을 화면에 텍스트가 보여야 한다.
139
+ 빈 컴포넌트 shell은 Step A 미완성.
140
+
141
+ <template> 안에 반드시:
142
+ - 스토리보드에서 추출한 실제 텍스트 (제목, 설명, 버튼 라벨)
143
+ - 데이터가 렌더링되는 리스트 (v-for / .map)
144
+ - 클릭 가능한 버튼/링크
145
+ - 조건부 렌더링 (v-if / &&)
146
+ ```
144
147
 
145
- 2. TypeScript 인터페이스:
146
- - 섹션에서 사용하는 데이터 구조 정의
148
+ ### 섹션 컴포넌트 — 실제 코드 예시 (Vue)
149
+
150
+ ```vue
151
+ <template>
152
+ <section class="dailyCheckInSection">
153
+ <h2 class="dailyCheckInSection__title">일일 출석 미션</h2>
154
+ <p class="dailyCheckInSection__description">매일 출석하고 스노우 토큰을 받으세요!</p>
155
+
156
+ <div class="dailyCheckInSection__calendar">
157
+ <div
158
+ v-for="day in checkInDays"
159
+ :key="day.date"
160
+ class="dailyCheckInSection__day"
161
+ :class="{ 'is-checked': day.checked, 'is-today': day.isToday }"
162
+ @click="handleCheckIn(day)"
163
+ >
164
+ <span class="dailyCheckInSection__dayLabel">{{ day.date }}</span>
165
+ <span class="dailyCheckInSection__dayReward">{{ day.reward }} 토큰</span>
166
+ </div>
167
+ </div>
168
+
169
+ <div class="dailyCheckInSection__milestones">
170
+ <div
171
+ v-for="milestone in milestones"
172
+ :key="milestone.days"
173
+ class="dailyCheckInSection__milestone"
174
+ :class="{ 'is-claimable': milestone.claimable, 'is-claimed': milestone.claimed }"
175
+ @click="handleClaimReward(milestone)"
176
+ >
177
+ <span>{{ milestone.days }}일 달성</span>
178
+ <span>{{ milestone.reward }}</span>
179
+ <button v-if="milestone.claimable && !milestone.claimed">받기</button>
180
+ </div>
181
+ </div>
182
+ </section>
183
+ </template>
184
+
185
+ <script setup lang="ts">
186
+ /**
187
+ * 일일 출석 미션 섹션
188
+ *
189
+ * [기능 정의]
190
+ * - 매일 출석 시 스노우 토큰 즉시 지급
191
+ * - 누적 3/5/7일 달성 시 추가 보상
192
+ *
193
+ * [인터랙션]
194
+ * ① 출석하기 클릭 → 출석 처리 → 토큰 지급 표시
195
+ * ② 누적 보상 클릭 → 보상 수령
196
+ *
197
+ * [상태] default, checked, reward-claimed
198
+ */
199
+
200
+ interface CheckInDay {
201
+ date: string
202
+ checked: boolean
203
+ isToday: boolean
204
+ reward: number
205
+ }
206
+
207
+ interface Milestone {
208
+ days: number
209
+ claimable: boolean
210
+ claimed: boolean
211
+ reward: string
212
+ }
213
+
214
+ // 목 데이터 — 빈 배열 금지!
215
+ const checkInDays = ref<CheckInDay[]>([
216
+ { date: 'Day 1', checked: true, isToday: false, reward: 10 },
217
+ { date: 'Day 2', checked: true, isToday: false, reward: 10 },
218
+ { date: 'Day 3', checked: false, isToday: true, reward: 10 },
219
+ { date: 'Day 4', checked: false, isToday: false, reward: 10 },
220
+ { date: 'Day 5', checked: false, isToday: false, reward: 10 },
221
+ { date: 'Day 6', checked: false, isToday: false, reward: 15 },
222
+ { date: 'Day 7', checked: false, isToday: false, reward: 20 },
223
+ ])
224
+
225
+ const milestones = ref<Milestone[]>([
226
+ { days: 3, claimable: false, claimed: false, reward: '보상 상자 1개' },
227
+ { days: 5, claimable: false, claimed: false, reward: '보상 상자 2개' },
228
+ { days: 7, claimable: false, claimed: false, reward: '스페셜 보상' },
229
+ ])
230
+
231
+ function handleCheckIn(day: CheckInDay): void {
232
+ // TODO: 출석 API 호출
233
+ }
234
+
235
+ function handleClaimReward(milestone: Milestone): void {
236
+ // TODO: 누적 보상 수령 API 호출
237
+ }
238
+ </script>
239
+ <!-- 스타일은 외부 파일: styles/{feature}/components/_daily-checkin.scss -->
240
+ ```
147
241
 
148
- 3. 이벤트 핸들러:
149
- - 인터랙션 스펙에 맞는 함수 (body는 // TODO:)
242
+ ### 필수 포함 사항 체크리스트
150
243
 
151
- 4. 목 데이터 (빈 배열 금지):
152
- - 기능 정의서에서 추출한 아이템/보상/상품 정보로 채움
153
- - 배열 = UI가 보임 = Step A 미완성
244
+ ```
245
+ <template> 안에:
246
+ 섹션 제목 <h2> (스토리보드에서 추출한 실제 텍스트)
247
+ □ 설명 텍스트 <p> (스토리보드에서 추출)
248
+ □ 리스트 렌더링 (v-for + 목 데이터, 빈 배열 금지)
249
+ □ 버튼/CTA (실제 라벨 텍스트 + @click 핸들러)
250
+ □ 조건부 렌더링 (상태에 따른 v-if)
251
+ □ 클래스명 (Step B에서 외부 스타일과 매칭)
252
+
253
+ <script> 안에:
254
+ □ JSDoc: [기능 정의] + [인터랙션] + [상태]
255
+ □ TypeScript interface
256
+ □ 목 데이터 (기능 정의서에서 추출, 3~7개 아이템)
257
+ □ 이벤트 핸들러 함수 (body는 // TODO:)
154
258
  ```
155
259
 
156
260
  ### 스타일 분리 규칙
@@ -158,18 +262,21 @@ Popup: 패턴 분류 (확인/취소, 상세 모달, 알림, 입력 폼)
158
262
  ```
159
263
  컴포넌트 파일에 <style> 블록을 작성하지 않는다.
160
264
  스타일은 Step B에서 외부 파일로 생성.
161
- 컴포넌트는 template + script 만 포함.
265
+ 컴포넌트는 <template> + <script setup> 만 포함.
162
266
  ```
163
267
 
164
- ### 핵심 원칙: 스타일 없이 동작하는 코드
268
+ ### Step A 완료 기준
165
269
 
166
270
  ```
167
- 클릭/탭/아코디언 등 인터랙션이 실제로 동작
168
- 모달/팝업 open/close가 연결됨
169
- ✅ 리스트 렌더링이데이터로 동작
170
- 조건부 렌더링이 상태에 따라 전환
171
- emit으로 부모-자식 이벤트 연결
172
- 브라우저에서 열면 스타일은 없지만 인터랙션은 동작하는 상태
271
+ 브라우저에서 열었을 때:
272
+ 섹션의 제목/설명 텍스트가 화면에 보인다
273
+ ✅ 리스트 아이템이 렌더링된다 (데이터)
274
+ 버튼을 클릭하면 핸들러가 실행된다
275
+ 탭/아코디언/모달이 동작한다
276
+ 스타일은 없다 (Step B에서)
277
+ ❌ 이미지는 없다 (Step B에서)
278
+
279
+ 빈 화면 = Step A 미완성. 다음 단계로 넘어가지 않는다.
173
280
  ```
174
281
 
175
282
  ## A-6. 인터랙션 매핑 테이블
@@ -192,37 +299,46 @@ Popup: 패턴 분류 (확인/취소, 상세 모달, 알림, 입력 폼)
192
299
  ### 검증 항목
193
300
 
194
301
  ```
302
+ 0. 빈 화면 검사 (가장 중요 — 먼저 실행):
303
+ 각 컴포넌트 파일을 Read로 열어서 <template> 안에 확인:
304
+ □ <h2> 또는 <h3> 섹션 제목 텍스트 존재
305
+ □ <p> 설명 텍스트 존재
306
+ □ v-for 또는 .map 렌더링 존재 (리스트 있는 섹션)
307
+ □ @click 또는 onClick 이벤트 존재 (인터랙션 있는 섹션)
308
+ <template> 안에 실제 HTML 태그가 없으면 → 빈 컴포넌트 → 재작성
309
+ Grep: "<template>" 다음 줄이 "</template>"이면 → 빈 template
310
+
195
311
  1. 파일 존재 확인 (Glob 도구):
196
312
  □ 루트 페이지 파일 존재
197
313
  □ PAGE 프레임 수 = 컴포넌트 파일 수
198
314
  □ styles 디렉토리 존재
199
- □ 팝업 컴포넌트 존재 (스토리보드에 팝업이 있었으면)
200
- → 누락 시 Write로 생성
201
-
202
- 2. 기능 주석 확인 (Read 도구):
203
- □ 모든 컴포넌트에 [기능 정의] + [인터랙션] + [상태] JSDoc
204
- → 누락 시 Edit으로 추가
205
315
 
206
- 3. 목 데이터 확인 (Grep 도구):
316
+ 2. 목 데이터 확인 (Grep 도구):
207
317
  □ 빈 배열 (ref([]) 패턴) 검색 → 0건
208
318
  → 발견 시 목 데이터 채움
209
319
 
210
- 4. 스타일 분리 확인 (Grep 도구):
320
+ 3. 스타일 분리 확인 (Grep 도구):
211
321
  □ 컴포넌트 내 <style> 블록 0건
212
- → 발견 시 제거
213
322
 
214
- 5. 빌드 확인 (Bash 도구):
323
+ 4. 빌드 확인 (Bash 도구):
215
324
  □ npm run build 성공
216
- → 에러 시 수정 후 재빌드
325
+
326
+ 5. 브라우저 확인:
327
+ □ dev 서버 열어서 실제 화면 확인
328
+ □ 각 섹션에 텍스트가 보이는지
329
+ □ 빈 화면이면 → 해당 컴포넌트 재작성
217
330
  ```
218
331
 
219
332
  ### 완료 조건
220
333
 
221
334
  ```
335
+ ✅ 빈 template 0개 — 모든 컴포넌트에 실제 HTML 마크업 존재
336
+ ✅ 브라우저에서 텍스트/리스트/버튼이 보인다
222
337
  ✅ 파일 수 = PAGE 프레임 수
223
- ✅ 모든 JSDoc 주석 완비
224
338
  ✅ 빈 배열 0개
225
339
  ✅ <style> 블록 0개
226
340
  ✅ 빌드 성공
341
+
342
+ 빈 화면 = Step A 미완성. Step B로 넘어가지 않는다.
227
343
  → Step B 진행 가능
228
344
  ```
@@ -16,6 +16,52 @@ triggers: []
16
16
  > - 코드: Edit 도구로 Step A 컴포넌트의 template/style 채움
17
17
  > - 토큰: Edit 도구로 _tokens 파일에 추출한 값 추가
18
18
 
19
+ ## HARD RULES (위반 시 Step B 미완성)
20
+
21
+ ```
22
+ 1. PLACEHOLDER 금지
23
+ 코드에 "placeholder", "Key Visual Image", 빈 dashed box,
24
+ alt="placeholder", src="" 등이 남아있으면 → Step B 미완성.
25
+ 이미지를 추출 못하면 placeholder가 아니라 대체 추출(B-3.3 Step e)을 실행한다.
26
+
27
+ 2. 이미지 없는 섹션은 완료가 아니다
28
+ 스크린샷에 이미지(배경/캐릭터/일러스트/아이콘)가 보이는 섹션에서
29
+ 생성 코드에 실제 이미지 파일이 없으면 → 해당 섹션 미완성.
30
+ 다음 섹션으로 넘어가지 않고 현재 섹션의 이미지를 확보할 때까지 머문다.
31
+
32
+ 3. 단색 배경으로 대체 금지
33
+ 원본에 이미지 배경이 있는데 생성 코드가 CSS gradient/단색으로 대체하면 → P1.
34
+ 이미지를 반드시 다운로드하여 background-image로 적용해야 한다.
35
+
36
+ 4. 이미지 추출 실패 = 전체 실패
37
+ 인벤토리의 이미지 중 하나라도 확보 못하면 Step B를 완료로 마킹하지 않는다.
38
+ 대체 추출 경로(하위 노드 탐색 → 개별 스크린샷 → 크롭)를 전부 시도한 후,
39
+ 그래도 실패하면 사용자에게 해당 이미지를 직접 제공해달라고 요청한다.
40
+
41
+ 5. 텍스트 스타일 미적용 = 미완성
42
+ 스크린샷에서 읽은 모든 텍스트 스타일을 코드에 반영해야 한다:
43
+ - font-size (스케일 팩터 적용)
44
+ - font-weight
45
+ - color
46
+ - line-height
47
+ - letter-spacing (있으면)
48
+ - text-align
49
+ 제목, 본문, 버튼 텍스트, 설명 등 스크린샷에 보이는 모든 텍스트 요소에 적용.
50
+ 스타일이 적용되지 않은 텍스트 요소가 있으면 → P1.
51
+ 브라우저 기본 스타일(검은색 16px)로 보이는 텍스트가 있으면 → 미완성.
52
+
53
+ 6. 스타일은 반드시 외부 파일에 작성
54
+ 컴포넌트 파일(.vue/.tsx) 안에 <style> 블록이나 인라인 스타일을 작성하지 않는다.
55
+ 모든 스타일은 외부 파일에 작성:
56
+ --new 모드: styles/{feature}/layout/_섹션.scss, components/_요소.scss
57
+ 기본 모드: 프로젝트 기존 스타일 패턴에 따름
58
+
59
+ 작성 후 검증:
60
+ Grep: "<style" in components/{feature}/ → 0건
61
+ Grep: "style=" in components/{feature}/ → 0건 (동적 바인딩 제외)
62
+ 위반 시 → 해당 스타일을 외부 파일로 이동 후 재검증.
63
+ ```
64
+
19
65
  ## 입력
20
66
 
21
67
  - 디자인 Figma URL (전체 페이지)
@@ -59,54 +105,101 @@ AskUserQuestion (options 사용 금지, 자유 텍스트만):
59
105
 
60
106
  **각 매핑된 섹션에 대해 순서대로:**
61
107
 
62
- ### 3-1. 스크린샷 시각 분석 (1순위)
108
+ ### 3-1. 참조 코드에서 스타일 값 + 에셋 추출
63
109
 
64
110
  ```
65
- get_screenshot(fileKey, designFrame.nodeId)
66
- 원본 디자인 이미지 확보 이것이 코드 생성의 1차 소스
111
+ get_design_context(fileKey, designFrame.nodeId)
112
+ 참조 코드 (React+Tailwind) + 에셋 URL
113
+
114
+ 참조 코드에서 추출하는 것 (Figma 토큰 = 정확한 값):
115
+ ✅ 색상: hex 값 (text-[#1B3A1D], bg-[#0A1628] 등)
116
+ ✅ 폰트: font-size(px), font-weight, line-height, font-family
117
+ ✅ 간격: padding, margin, gap (px)
118
+ ✅ 장식: border-radius, box-shadow, opacity
119
+ ✅ 에셋 URL: https://figma.com/api/mcp/asset/...
120
+
121
+ 이 값들은 디자이너가 Figma UI에서 보는 것과 동일한 토큰 값.
122
+ 스크린샷에서 추정하지 않고 이 값을 그대로 사용한다.
123
+ px 값에만 스케일 팩터(R-3)를 적용.
67
124
 
68
- 스크린샷에서 읽는 항목 (vibe-figma-rules R-7 참조):
69
- 레이아웃 구조 (섹션 경계, flex/grid 방향, 요소 배치)
70
- → 배경 (이미지/단색/그라데이션, 오버레이 유무)
71
- → 색상 (배경, 텍스트, 버튼, 보더)
72
- → 타이포 (크기 비율, 굵기, 줄간격) — 스케일 팩터 적용 (R-3)
73
- → 간격 (패딩, gap, 마진) — 스케일 팩터 적용 (R-3)
74
- → 이미지 분류 (Background/Content/Overlay, R-4 참조)
75
- → z-index 관계 (겹침 구조, 투명도)
125
+ ⚠️ HTML 구조는 레이어가 비정형이면 부정확할 수 있음.
126
+ 구조는 3-2 스크린샷에서 판단.
76
127
  ```
77
128
 
78
- ### 3-2. 참조 코드 + 에셋 추출 (2순위)
129
+ ### 3-2. 스크린샷으로 구조 + 이미지 인벤토리
79
130
 
80
131
  ```
81
- get_design_context(fileKey, designFrame.nodeId)
82
- 참조 코드 + 에셋 URL
132
+ get_screenshot(fileKey, designFrame.nodeId)
133
+ 원본 디자인 이미지 확보
134
+
135
+ 스크린샷에서 판단하는 것 (구조):
136
+ → 레이아웃 구조 (섹션 경계, flex/grid 방향, 요소 배치 순서)
137
+ → 이미지 배치 분류 (Background/Content/Overlay, R-4 참조)
138
+ → z-index 관계 (겹침 구조, 오버레이 유무)
139
+ → 참조 코드에 없는 시각 요소 발견 → 추가 구현 대상
140
+ ```
83
141
 
84
- 참조 코드에서 가져오는 것:
85
- ✅ 이미지 에셋 URL (https://figma.com/api/mcp/asset/...) — 핵심 가치
86
- ✅ 정확한 hex 색상값 (스크린샷 추정보다 정확할 때)
87
- ✅ 폰트 패밀리명, border-radius, shadow 값
88
- ⚠️ 레이아웃/구조 — 스크린샷과 대조 후 채택
89
- ❌ px 값 그대로 사용 금지 — 반드시 스케일 팩터 적용
142
+ **이미지 인벤토리 작성 (필수):**
90
143
 
91
- ⚠️ 레이어가 "Frame 633372" 같은 비정형일 때:
92
- 참조 코드가 부정확할 있음 스크린샷 분석 결과를 기준으로 코드 생성
144
+ ```
145
+ 스크린샷을 보고 해당 섹션에 보이는 모든 이미지를 목록화:
146
+
147
+ imageInventory = [
148
+ { name: "hero-bg", type: "background", description: "눈 테마 풀스크린 배경" },
149
+ { name: "hero-character", type: "overlay", description: "캐릭터 일러스트 우하단" },
150
+ { name: "hero-vehicle", type: "content", description: "차량 이미지 중앙" },
151
+ { name: "hero-logo", type: "content", description: "이벤트 로고 상단" },
152
+ ]
153
+
154
+ → 이 인벤토리가 B-3.3 다운로드의 체크리스트가 됨
155
+ → B-5 검증에서 인벤토리 vs 코드의 이미지를 1:1 대조
156
+ → 인벤토리에 있는데 코드에 없으면 = P1
93
157
  ```
94
158
 
95
159
  ### 3-3. 이미지 에셋 다운로드 (BLOCKING — 코드 반영 전 필수)
96
160
 
161
+ > **인벤토리의 모든 이미지가 로컬에 존재해야 다음 단계로 넘어갈 수 있다.**
162
+
97
163
  ```
98
164
  Step a: 참조 코드에서 에셋 URL 추출
99
165
  → 모든 https://www.figma.com/api/mcp/asset/ URL 수집
166
+ → 각 URL을 imageInventory 항목과 매칭
100
167
 
101
- Step b: URL을 다운로드 파일 저장
102
- Bash: curl -L "{url}" -o static/images/{feature}/{name}.webp
103
- 파일명: 변수명/레이어명 기반 kebab-case
168
+ Step b: 인벤토리 vs 에셋 URL 대조
169
+ 인벤토리에 있는데 에셋 URL이 없는 이미지 = 누락 후보
170
+ 누락 후보에 대해 대체 추출 실행 (Step e)
104
171
 
105
- Step c: URL→로컬경로 매핑 테이블 생성
172
+ Step c: 매칭된 에셋 다운로드
173
+ Bash: curl -L "{url}" -o static/images/{feature}/{name}.webp
174
+ 파일명: 인벤토리 name 기반 kebab-case
106
175
 
107
176
  Step d: 다운로드 검증
108
177
  → 파일 존재 + 0byte 아닌지 확인
109
178
  → 누락/실패 시 재다운로드
179
+
180
+ Step e: 대체 추출 (참조 코드에 에셋 URL이 없는 이미지)
181
+ 레이어가 비정형("Frame 633372")이면 참조 코드에 이미지가 누락될 수 있음.
182
+ 이 경우 다음 순서로 시도:
183
+
184
+ 1. 하위 노드 탐색:
185
+ get_metadata로 섹션 하위 프레임 목록 확보
186
+ → 이미지로 의심되는 하위 nodeId에 대해 get_design_context 재호출
187
+ → 에셋 URL 확보되면 다운로드
188
+
189
+ 2. 하위 노드 개별 스크린샷:
190
+ 이미지로 의심되는 하위 nodeId에 대해 get_screenshot
191
+ → 해당 스크린샷 자체를 이미지 에셋으로 저장
192
+ → 배경 이미지: 스크린샷을 background-image로 사용
193
+ → 콘텐츠 이미지: 스크린샷을 <img>로 사용
194
+
195
+ 3. 섹션 전체 스크린샷 크롭:
196
+ 위 방법이 다 실패하면, 섹션 스크린샷에서 해당 영역을 잘라서 사용
197
+ → 최후 수단이지만 이미지 누락보다는 낫다
198
+
199
+ Step f: 최종 인벤토리 체크
200
+ 인벤토리 항목 수 = 다운로드된 파일 수
201
+ 하나라도 빠지면 → Step e 재시도
202
+ 모든 이미지가 로컬에 있어야 → 3-4로 진행
110
203
  ```
111
204
 
112
205
  ### 3-4. 이미지 코드 패턴 적용
@@ -140,29 +233,211 @@ Step d: 다운로드 검증
140
233
  }
141
234
  ```
142
235
 
143
- ### 3-5. 컴포넌트 파일에 반영 (Edit 도구)
236
+ ### 3-5. 글로벌 스타일 파일 구조 생성 (BLOCKING — 컴포넌트 수정 전 필수)
237
+
238
+ > **이 단계를 건너뛰면 Step B 미완성. 컴포넌트를 수정하기 전에 스타일 파일을 먼저 만든다.**
239
+
240
+ 첫 번째 섹션 처리 시 전체 구조를 Write로 생성. 이후 섹션에서는 해당 파일에 Edit으로 추가.
241
+
242
+ ```
243
+ styles/{feature}/
244
+ index.scss ← [1] 진입점 (모든 파일 import)
245
+ _tokens.scss ← [2] 토큰 (색상, 폰트, 간격 변수)
246
+ _mixins.scss ← [3] mixin (breakpoint, fluid 함수)
247
+ _base.scss ← [4] 공통 (reset, font-face, 전역 규칙)
248
+ layout/
249
+ _page.scss ← [5] 페이지 전체 레이아웃
250
+ _{section}.scss ← [6] 각 섹션별 배치/구조/배경
251
+ components/
252
+ _{element}.scss ← [7] 재사용 UI 요소 (card, button, badge 등)
253
+ ```
254
+
255
+ #### [1] index.scss — Write로 생성
256
+
257
+ ```scss
258
+ // Foundation
259
+ @use 'tokens';
260
+ @use 'mixins';
261
+ @use 'base';
262
+
263
+ // Layout
264
+ @use 'layout/page';
265
+ @use 'layout/hero';
266
+ @use 'layout/daily-checkin';
267
+ // ... Step A의 모든 섹션
268
+
269
+ // Components
270
+ @use 'components/card';
271
+ @use 'components/button';
272
+ // ... 반복 패턴에서 추출된 재사용 요소
273
+ ```
274
+
275
+ #### [2] _tokens.scss — 참조 코드에서 추출한 값으로 Write
276
+
277
+ ```scss
278
+ @use 'sass:math';
279
+
280
+ // ── Colors (참조 코드 hex 그대로) ──
281
+ $figma-bg-primary: #0A1628;
282
+ $figma-bg-section: #1A2B4A;
283
+ $figma-text-heading: #1B3A1D;
284
+ $figma-text-body: #333333;
285
+ $figma-text-light: #FFFFFF;
286
+ $figma-accent: #FFD700;
287
+
288
+ // ── Typography (참조 코드 px × scaleFactor) ──
289
+ $figma-text-hero: 36px; // Figma 48px × 0.75
290
+ $figma-text-sub: 18px; // Figma 24px × 0.75
291
+ $figma-text-body: 14px; // Figma 18px × 0.75
292
+ $figma-text-caption: 12px; // Figma 16px × 0.75
293
+ $figma-font-family: 'Noto Sans KR', sans-serif;
294
+
295
+ // ── Spacing (참조 코드 px × scaleFactor) ──
296
+ $figma-space-section: 60px; // Figma 80px × 0.75
297
+ $figma-space-content: 24px; // Figma 32px × 0.75
298
+ $figma-space-element: 12px; // Figma 16px × 0.75
299
+
300
+ // ── Decorations ──
301
+ $figma-radius-card: 12px;
302
+ $figma-shadow-card: 0 4px 12px rgba(0,0,0,0.15);
303
+
304
+ // ── Breakpoints ──
305
+ $figma-bp: 1024px;
306
+ $figma-bp-mobile-min: 360px;
307
+ $figma-bp-pc-target: 1920px;
308
+ ```
309
+
310
+ #### [3] _mixins.scss — Write로 생성
311
+
312
+ ```scss
313
+ @use 'tokens' as t;
314
+
315
+ @mixin figma-pc { @media (min-width: t.$figma-bp) { @content; } }
316
+
317
+ @function figma-fluid($mobile, $desktop) {
318
+ // clamp 계산 (vibe-figma-rules R-3)
319
+ }
320
+ ```
321
+
322
+ #### [4] _base.scss — Write로 생성
323
+
324
+ ```scss
325
+ @use 'tokens' as t;
326
+
327
+ * { margin: 0; padding: 0; box-sizing: border-box; }
328
+ body { font-family: t.$figma-font-family; }
329
+ img { max-width: 100%; height: auto; }
330
+ ```
331
+
332
+ #### [6] layout/_{section}.scss — 섹션별 Write
333
+
334
+ ```scss
335
+ @use '../tokens' as t;
336
+ @use '../mixins' as m;
337
+
338
+ // 참조 코드의 레이아웃 관련 값 + 스크린샷의 구조를 적용
339
+ .heroSection {
340
+ position: relative;
341
+ overflow: hidden;
342
+ min-height: 100vh;
343
+ padding: t.$figma-space-section 0;
344
+ }
345
+
346
+ // Multi-Layer 배경 (이미지가 있는 섹션)
347
+ .heroBg {
348
+ position: absolute; inset: 0; z-index: 0;
349
+ background-image: url('/images/{feature}/hero-bg.webp');
350
+ background-size: cover;
351
+ background-position: center;
352
+ }
353
+ .heroBgOverlay {
354
+ position: absolute; inset: 0; z-index: 1;
355
+ background: linear-gradient(to bottom, rgba(0,0,0,0.3), rgba(0,0,0,0.7));
356
+ }
357
+ .heroContent {
358
+ position: relative; z-index: 2;
359
+ display: flex; flex-direction: column; align-items: center;
360
+ padding: 0 t.$figma-space-content;
361
+ }
362
+ ```
363
+
364
+ #### [7] components/_{element}.scss — 텍스트 + UI 요소
144
365
 
366
+ ```scss
367
+ @use '../tokens' as t;
368
+
369
+ // 참조 코드의 Figma 토큰 값을 그대로 사용
370
+ .heroTitle {
371
+ font-size: t.$figma-text-hero;
372
+ font-weight: 900;
373
+ color: t.$figma-text-heading;
374
+ line-height: 1.2;
375
+ text-align: center;
376
+ }
377
+
378
+ .heroDescription {
379
+ font-size: t.$figma-text-sub;
380
+ font-weight: 400;
381
+ color: t.$figma-text-body;
382
+ line-height: 1.6;
383
+ text-align: center;
384
+ }
385
+
386
+ .heroCta {
387
+ font-size: t.$figma-text-body;
388
+ font-weight: 700;
389
+ color: t.$figma-text-light;
390
+ background: t.$figma-accent;
391
+ border-radius: t.$figma-radius-card;
392
+ padding: t.$figma-space-element t.$figma-space-content;
393
+ }
145
394
  ```
146
- 변환 순서 (스크린샷 분석 → 코드):
147
395
 
148
- a. 스크린샷 분석 결과로 코드 작성:
149
- - 레이아웃 구조 (스크린샷에서 읽은 flex/grid, 배치)
150
- - 스타일 값 (스크린샷에서 읽은 색상, 간격, 폰트 × 스케일 팩터)
151
- - 배경 이미지 Multi-Layer 구조 (스크린샷에서 판단한 z-index)
396
+ ### 3-6. 생성 확인 (BLOCKING)
152
397
 
153
- b. 참조 코드에서 보강:
154
- - 에셋 URL 다운로드된 로컬 경로로 교체
155
- - 정확한 hex 색상값, border-radius, shadow (스크린샷 추정보다 정확할 때)
398
+ ```
399
+ 스타일 파일 생성 반드시 확인:
156
400
 
157
- c. 프로젝트 스택으로 변환 (ReactVue 등)
401
+ Glob: styles/{feature}/index.scss 존재
402
+ Glob: styles/{feature}/_tokens.scss → 존재
403
+ Glob: styles/{feature}/_mixins.scss → 존재
404
+ Glob: styles/{feature}/_base.scss → 존재
405
+ Glob: styles/{feature}/layout/*.scss → 섹션 수만큼 존재
406
+ Glob: styles/{feature}/components/*.scss → 1개 이상 존재
158
407
 
159
- d. Step A 코드와 병합:
160
- - 기능 주석/핸들러/인터페이스 보존
161
- - template의 placeholder실제 마크업으로 교체
408
+ Grep: "font-size" in styles/{feature}/ → 0건이면 P1 (텍스트 스타일 미작성)
409
+ Grep: "color:" in styles/{feature}/ → 0건이면 P1
410
+ Grep: "background-image" in styles/{feature}/배경 이미지 섹션 수만큼
162
411
 
163
- 주의:
164
- - 스크린샷에 보이는 이미지가 코드에 없으면 누락
165
- - Figma 임시 URL이 코드에 남으면 안 됨
412
+ 하나라도 실패 → Write/Edit으로 보완 → 재확인
413
+ 파일이 모두 존재하고 내용이 있어야3-7로 진행
414
+ ```
415
+
416
+ ### 3-7. 컴포넌트 파일에 반영 (Edit 도구)
417
+
418
+ ```
419
+ 컴포넌트 파일에는 template + script만 수정한다.
420
+ 모든 스타일은 3-5에서 생성한 외부 파일에만 존재.
421
+
422
+ a. template 수정:
423
+ - placeholder → 실제 마크업으로 교체
424
+ - 클래스명 추가 (layout/*.scss, components/*.scss의 셀렉터와 매칭)
425
+ - 이미지 태그에 로컬 경로 설정
426
+ - Multi-Layer 구조 적용 (.{section}Bg + .{section}Content)
427
+
428
+ b. Step A 코드 보존:
429
+ - 기능 주석/핸들러/인터페이스 유지
430
+ - 목 데이터/이벤트 바인딩 유지
431
+
432
+ c. 스타일 import 설정:
433
+ - 루트 페이지 또는 설정 파일에서 styles/{feature}/index.scss import
434
+ - Nuxt: nuxt.config의 css 배열에 추가
435
+ - Next.js: _app 또는 layout에서 import
436
+
437
+ d. 컴포넌트 안에 스타일 작성 금지:
438
+ - <style> 블록 금지
439
+ - style="" 인라인 금지 (동적 바인딩 제외)
440
+ - 스타일이 필요하면 → 외부 파일에 추가 → 클래스명으로 연결
166
441
  ```
167
442
 
168
443
  ## B-4. 뷰포트 모드에 따른 스타일 적용
@@ -207,11 +482,48 @@ for each section in mappings:
207
482
  ### Step B 추가 검증 항목
208
483
 
209
484
  ```
210
- 1. 이미지 에셋: 전부 다운로드 + 로컬 파일 존재 + 0byte 아님
211
- 2. Figma 임시 URL: Grep으로 figma.com/api/mcp/asset 잔존 0건 확인
212
- 3. 배경 이미지: 스크린샷에 보이는 배경이 코드에도 있는지
213
- 4. 오버레이: 배경 위 텍스트 가독성 확보 (스크린샷 대조)
214
- 5. (responsive) 이전 뷰포트 섹션들 재비교 — 깨진 곳 없는지
485
+ 1. 이미지 인벤토리 대조:
486
+ for each item in imageInventory:
487
+ 로컬 파일 존재 (Glob)
488
+ 0byte 아님 (ls -la)
489
+ 코드에서 참조됨 (Grep: 파일명으로 검색)
490
+ □ 올바른 패턴 적용됨:
491
+ - background → .{section}Bg { background-image: url(...) }
492
+ - content → <img src="..." /> 또는 <Image />
493
+ - overlay → .{section}Character { background-image: url(...) }
494
+ 하나라도 실패 → P1 → 수정 → 재검증
495
+
496
+ 2. 텍스트 스타일 검증:
497
+ for each section:
498
+ □ 외부 스타일 파일 존재 (Glob: styles/{feature}/**/*.scss)
499
+ □ 스크린샷의 텍스트 요소 수 ≈ font-size 선언 수
500
+ Grep: "font-size" in styles/{feature}/
501
+ □ 브라우저 기본 스타일로 보이는 텍스트 0건
502
+ → 모든 텍스트에 font-size, color, font-weight 지정 확인
503
+ □ color 값이 적용됨 (원본 스크린샷 색상과 매칭)
504
+ 미적용 텍스트 발견 → P1
505
+
506
+ 3. 스타일 분리 검증:
507
+ □ Grep: "<style" in components/{feature}/**/*.vue → 0건
508
+ □ Grep: "<style" in components/{feature}/**/*.tsx → 0건
509
+ □ Grep: 'style="' in components/{feature}/ → 0건 (v-bind:style 동적 바인딩 제외)
510
+ 위반 → 외부 파일로 이동 → 재검증
511
+
512
+ 4. Figma 임시 URL + placeholder 잔존 체크:
513
+ □ Grep: "figma.com/api/mcp/asset" → 0건
514
+ □ Grep: "placeholder" (대소문자 무시) → 0건
515
+ □ Grep: "Key Visual" → 0건
516
+
517
+ 5. 배경 이미지 Multi-Layer 검증:
518
+ 스크린샷에 배경 이미지가 보이는 섹션:
519
+ □ .{section}Bg 클래스 존재 (Grep)
520
+ □ .{section}Content 클래스 존재 (z-index 최상위)
521
+ □ 배경 위 텍스트 가독성 확보 (오버레이 유무)
522
+ 누락 → P1
523
+
524
+ 6. (responsive) 뷰포트별:
525
+ □ 뷰포트별 다른 배경 이미지 → @media 분기 있는지
526
+ □ 이전 뷰포트 스타일/이미지 깨지지 않았는지
215
527
  ```
216
528
 
217
529
  ## 참조 스킬
@@ -14,7 +14,7 @@ tier: standard
14
14
 
15
15
  ## R-0. 설계 철학
16
16
 
17
- > **스크린샷 시각 분석이 핵심이다. 레이어 구조/참조 코드는 보조 수단.**
17
+ > **비정형 레이어에서도 원본 디자인 수준의 완성도를 달성한다.**
18
18
 
19
19
  실무 Figma 파일의 현실:
20
20
  ```
@@ -24,39 +24,57 @@ tier: standard
24
24
  ```
25
25
 
26
26
  레이어명이 "Frame 47", "Group 12"이고, Auto Layout 없이 절대 배치된 프레임이 대부분.
27
- `get_design_context`가 깔끔한 참조 코드를 돌려주지 못하는 것이 **기본 전제**.
27
+ 그러나 `get_design_context`는 레이어가 비정형이어도 **스타일 토큰 값(색상, 폰트, 간격)과
28
+ 에셋 URL은 정확하게 반환**한다. 이 값들은 디자이너가 Figma UI에서 보는 것과 동일한 값이다.
28
29
 
29
- 스킬은 **스토리보드에서 기능/인터랙션/상태를 추출**하고,
30
- **디자인 프레임 스크린샷에서 스타일/이미지를 시각 분석**하여,
31
- **원본 디자인 이미지 수준의 완성도**를 달성하는 것이 목적이다.
30
+ ### 역할 분담
31
+
32
+ ```
33
+ 스크린샷이 답하는 것 (구조):
34
+ — WHAT goes WHERE: 레이아웃 구조, 섹션 경계, 이미지 배치, z-index, 겹침 관계
35
+ — 어떤 요소가 배경인지 콘텐츠인지, 어디에 오버레이가 있는지
36
+ — 참조 코드의 구조가 스크린샷과 다르면 → 스크린샷이 맞다
37
+
38
+ 참조 코드가 답하는 것 (정확한 값):
39
+ — EXACT VALUES: hex 색상, font-size(px), font-weight, line-height,
40
+ padding, gap, margin, border-radius, shadow, 에셋 URL
41
+ — 이 값들은 Figma 디자인 토큰에서 직접 추출된 것이므로 정확하다
42
+ — 스크린샷에서 추정할 필요 없이 참조 코드의 값을 그대로 사용한다
43
+ — 단, px 값에는 스케일 팩터를 적용해야 한다 (R-3)
44
+
45
+ 스크린샷이 검증하는 것 (최종 확인):
46
+ — 생성 코드의 렌더링 결과가 원본 스크린샷과 시각적으로 일치하는지
47
+ — Match Score 95%+, P1=0이 완료 기준
48
+ ```
32
49
 
33
50
  ### 핵심 원칙
34
51
 
35
52
  ```
36
- 1. 스크린샷이 1차 소스다
37
- 모든 시각적 판단(레이아웃, 색상, 간격, 폰트, 이미지 배치)은 스크린샷에서 읽는다
38
- get_screenshot으로 섹션별 원본 이미지를 먼저 확보한다
53
+ 1. 참조 코드의 스타일 값을 반드시 사용한다
54
+ get_design_context가 반환하는 색상/폰트/간격 값은 Figma 토큰에서 정확한
55
+ 스크린샷에서 색상을 추정하거나 폰트 크기를 눈대중으로 읽지 않는다
56
+ — 참조 코드의 값 + 스케일 팩터 적용 = 코드에 쓸 값
39
57
 
40
- 2. 참조 코드는 2차 소스다
41
- get_design_context의 참조 코드는 이미지 에셋 URL 추출 + 구조 힌트 용도
42
- — 참조 코드의 레이아웃/스타일 값은 스크린샷과 대조 후에만 신뢰한다
43
- 참조 코드가 부정확해도 스크린샷만으로 코드를 생성할 수 있어야 한다
58
+ 2. 스크린샷으로 구조를 결정한다
59
+ 레이어 구조("Frame 633372")가 무의미해도 스크린샷에서 섹션 경계를 파악
60
+ — 참조 코드의 HTML 구조가 스크린샷과 다르면 스크린샷 기준으로 재구성
61
+ 이미지 배치(배경/콘텐츠/오버레이)도 스크린샷에서 판단
44
62
 
45
- 3. 레이어 구조에 의존하지 않는다
46
- 구조화된 레이어는 보너스, 없어도 결과물 품질은 동일해야 한다
47
- "Frame 633372" 같은 무의미한 이름이 와도 스크린샷에서 섹션 경계를 파악한다
63
+ 3. 스크린샷으로 누락을 잡는다
64
+ 참조 코드에 없는 시각 요소가 스크린샷에 보이면 → 추가 구현
65
+ 이미지 인벤토리는 스크린샷에서 작성 (참조 코드에 없는 이미지도 잡기 위해)
48
66
 
49
67
  4. 검증은 항상 시각적 비교로
50
68
  — 완료 기준: 원본 스크린샷 vs 생성 코드의 Match Score 95%+, P1=0
51
69
  — 코드의 "정확성"이 아니라 "보이는 결과"가 기준이다
52
70
  ```
53
71
 
54
- ### 분석 우선순위
72
+ ### MCP 도구별 역할
55
73
 
56
74
  ```
57
- [1순위] get_screenshot 시각 분석 (레이아웃, 색상, 간격, 폰트, 배경 이미지)
58
- [2순위] get_design_context 에셋 URL 추출 + 구조 힌트 (스크린샷과 대조 필수)
59
- [3순위] get_metadata → 프레임 목록 + nodeId 확보 (구조 파악이 아닌 탐색 용도)
75
+ get_design_context정확한 스타일 + 에셋 URL (코드 작성의 데이터 소스)
76
+ get_screenshot → 구조 파악 + 누락 검출 + 최종 시각 검증 (구조의 진실)
77
+ get_metadata → 프레임 목록 + nodeId 확보 (탐색 용도)
60
78
  ```
61
79
 
62
80
  ---
@@ -323,12 +341,13 @@ Step A에서 get_screenshot으로 확보한 섹션별 원본 이미지를 기준
323
341
 
324
342
  | 비교 항목 | P1 (필수 수정) | P2 (권장 수정) |
325
343
  |----------|---------------|---------------|
344
+ | **이미지 인벤토리** | 인벤토리에 있는 이미지가 코드에 없음 | — |
345
+ | **배경 이미지** | 누락, Multi-Layer 미적용, 경로 깨짐 | 크기/위치 미세 차이 |
346
+ | **이미지 다운로드** | 파일 미존재, 0byte, Figma URL 잔존 | — |
326
347
  | **레이아웃** | 요소 배치 방향 다름, 섹션 순서 다름 | 미세 정렬 차이 |
327
- | **배경 이미지** | 누락, 완전히 다른 이미지 | 크기/위치 미세 차이 |
328
348
  | **색상** | 배경/텍스트색 완전히 다름 | 미세한 톤 차이 (ΔE < 10) |
329
349
  | **타이포** | 제목/본문 크기 비율 다름, 굵기 다름 | ±2px 차이 |
330
350
  | **간격** | 섹션 간 간격 크게 다름, 요소 겹침 | ±4px 차이 |
331
- | **이미지 에셋** | 다운로드 실패, 경로 깨짐 | 크기/비율 미세 차이 |
332
351
  | **누락 요소** | 스크린샷에 보이는 요소가 코드에 없음 | — |
333
352
  | **오버레이** | 배경 위 텍스트 가독성 확보 안 됨 | 투명도 미세 차이 |
334
353
 
@@ -372,49 +391,73 @@ P1이 있으면:
372
391
  ✅ P1 = 0 (전 섹션)
373
392
  ✅ 모든 이미지 에셋 표시 + Figma 임시 URL 잔존 0건
374
393
  ✅ (반응형) 각 뷰포트 독립 검증 통과
394
+ ✅ placeholder 0건 — "placeholder", "Key Visual Image", 빈 dashed box,
395
+ alt="placeholder", src="" 등이 코드에 남아있으면 미완성
396
+ ✅ 단색/gradient 대체 0건 — 원본에 이미지 배경인 곳이 CSS 단색으로 처리되면 미완성
397
+ ✅ 텍스트 스타일 전수 적용 — 브라우저 기본 스타일(검은색 16px)로 보이는 텍스트 0건
398
+ ✅ 스타일 외부 파일 — 컴포넌트 내 <style> 블록 0건, 인라인 style="" 0건
375
399
  ```
376
400
 
377
401
  ---
378
402
 
379
- ## R-7. 스크린샷 중심 분석 프로세스
403
+ ## R-7. 섹션별 분석 프로세스
380
404
 
381
- ### 섹션별 분석 순서
405
+ ### Step 1: get_design_context (스타일 값 + 에셋)
382
406
 
383
407
  ```
384
- Step 1: get_screenshot(섹션 nodeId)
385
- 원본 디자인 이미지 확보
386
- → 시각 분석: 레이아웃 구조, 색상 팔레트, 폰트 크기/굵기, 간격, 배경 이미지 유무
408
+ get_design_context(fileKey, 섹션 nodeId)
409
+ 참조 코드 반환 (React+Tailwind 형태)
387
410
 
388
- Step 2: get_design_context(섹션 nodeId)
389
- 이미지 에셋 URL 추출 (const xxxImage = 'https://figma.com/api/mcp/asset/...')
390
- 참조 코드에서 구조 힌트 확인 (HTML 계층, 컴포넌트 분리 방식)
391
- ⚠️ 참조 코드의 스타일 값은 스크린샷과 대조 후에만 채택
411
+ 참조 코드에서 추출하는 것 (정확한 값 — Figma 토큰에서 직접 추출됨):
412
+ 색상: hex (text-[#1B3A1D], bg-[#0A1628] )
413
+ 폰트: font-size(px), font-weight, line-height, font-family
414
+ 간격: padding, margin, gap (px)
415
+ ✅ 장식: border-radius, box-shadow, opacity
416
+ ✅ 에셋 URL: const xxxImage = 'https://figma.com/api/mcp/asset/...'
392
417
 
393
- Step 3: 스크린샷 기반 코드 생성
394
- 스크린샷에서 읽은 시각 정보로 스타일 작성
395
- 참조 코드의 에셋 URL을 로컬 경로로 교체
396
- → 참조 코드 구조가 스크린샷과 다르면 → 스크린샷 기준으로 재구성
418
+ 값들은 디자이너가 Figma UI 우측 패널에서 보는 것과 동일.
419
+ 스크린샷에서 추정할 필요 없이 값을 그대로 사용한다.
420
+ 단, px 값에는 스케일 팩터를 적용한다 (R-3).
397
421
  ```
398
422
 
399
- ### 스크린샷에서 읽어야 하는
423
+ ### Step 2: get_screenshot (구조 + 이미지 인벤토리)
424
+
425
+ ```
426
+ get_screenshot(fileKey, 섹션 nodeId)
427
+ → 원본 디자인 이미지 확보
400
428
 
401
- | 항목 | 읽는 방법 |
402
- |------|----------|
403
- | 레이아웃 | 섹션 경계, flex/grid 방향, 요소 배치, 중첩 관계 |
404
- | 배경 | 이미지 배경 vs 단색 vs 그라데이션, 오버레이 유무 |
405
- | 색상 | 배경색, 텍스트색, 버튼색, 보더색 (hex 추정) |
406
- | 타이포 | 제목/본문 크기 비율, 굵기, 줄간격 (스케일 팩터 적용) |
407
- | 간격 | 섹션 패딩, 요소 간 gap, 마진 (스케일 팩터 적용) |
408
- | 이미지 배치 | Background vs Content vs Overlay (R-4 분류) |
409
- | 시각적 계층 | z-index 관계, 겹침 구조, 투명도 |
429
+ 스크린샷에서 판단하는 (구조 참조 코드가 틀릴 수 있는 영역):
430
+ ✅ 레이아웃 구조: 섹션 경계, flex/grid 방향, 요소 배치 순서
431
+ 이미지 배치: 배경/콘텐츠/오버레이 분류, z-index 관계
432
+ 이미지 인벤토리: 보이는 모든 이미지 목록 (참조 코드에 없는 것도 잡음)
433
+ 겹침 구조: 텍스트-배경 관계, 오버레이 유무
434
+ 누락 검출: 참조 코드에 없는 시각 요소 발견
435
+ ```
436
+
437
+ ### Step 3: 코드 생성
438
+
439
+ ```
440
+ a. 참조 코드의 스타일 값을 그대로 사용하여 외부 스타일 파일 작성:
441
+ - 색상 hex → 토큰 변수로 정의
442
+ - font-size × scaleFactor → 토큰 변수로 정의
443
+ - 간격 × scaleFactor → 토큰 변수로 정의
444
+
445
+ b. 스크린샷의 구조로 HTML/template 결정:
446
+ - 레이아웃 방향, 요소 순서
447
+ - Multi-Layer 배경 구조 (배경 이미지가 있으면)
448
+ - 참조 코드의 구조가 스크린샷과 다르면 → 스크린샷 기준
449
+
450
+ c. 에셋 URL → 다운로드 → 로컬 경로로 교체
451
+
452
+ d. 스크린샷에 보이지만 참조 코드에 없는 요소 → 추가 구현
453
+ ```
410
454
 
411
- ### 참조 코드에서 읽어야 하는 것 (보조)
455
+ ### 참조 코드의 구조가 틀릴
412
456
 
413
457
  ```
414
- 이미지 에셋 URL (다운로드용) 이것이 참조 코드의 핵심 가치
415
- ✅ 정확한 hex 색상값 (스크린샷 추정보다 정확할 때)
416
- 폰트 패밀리명
417
- 정확한 border-radius, shadow
418
- ⚠️ 레이아웃 구조 스크린샷과 대조 채택
419
- ❌ px 값 그대로 사용 — 반드시 스케일 팩터 적용
458
+ 레이어가 "Frame 633372"면 참조 코드의 HTML 구조가 부정확할 있다.
459
+ 이때:
460
+ - 스타일 값(색상, 폰트, 간격)은 여전히 정확 → 그대로 사용
461
+ - HTML 구조(어떤 요소가 어디에)만 스크린샷 기준으로 재배치
462
+ - 에셋 URL도 여전히 유효 그대로 다운로드
420
463
  ```