@su-record/vibe 2.6.2 → 2.6.4

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.
@@ -0,0 +1,359 @@
1
+ ---
2
+ description: Sync UI code with design files (Gemini or Claude)
3
+ argument-hint: "design folder path"
4
+ ---
5
+
6
+ # /vibe.ui-sync
7
+
8
+ Analyze design files and update existing UI code to match.
9
+
10
+ - **Gemini enabled**: Gemini analyzes designs and generates code
11
+ - **Gemini disabled**: Claude handles directly
12
+
13
+ ## Usage
14
+
15
+ ```
16
+ /vibe.utils --ui-sync ./design/ui/
17
+ /vibe.utils --ui-sync ./mockups/
18
+ /vibe.utils --ui-sync ./design/homepage.html
19
+ ```
20
+
21
+ ## Process
22
+
23
+ ### 0. Check Gemini Status
24
+
25
+ **FIRST: Check if Gemini is available.**
26
+
27
+ ```bash
28
+ vibe gemini status
29
+ ```
30
+
31
+ Or check: `~/.config/vibe/gemini.json` or `~/.config/vibe/gemini-apikey.json`
32
+
33
+ - **Gemini available** → Use Gemini for code generation (Step 1A)
34
+ - **Gemini NOT available** → Claude handles directly (Step 1B)
35
+
36
+ ---
37
+
38
+ ## Path A: Gemini Enabled
39
+
40
+ ### 1A. Collect ALL Design Files
41
+
42
+ Scan folder and collect all files to send to Gemini:
43
+
44
+ | Format | What to Collect |
45
+ | ------ | --------------- |
46
+ | `*.html` | Full HTML content |
47
+ | `*.png` / `*.jpg` / `*.webp` | Image as base64 |
48
+ | `*.json` | Design tokens, theme config |
49
+ | `*.css` / `*.scss` | Style variables |
50
+ | `*.md` | Design guidelines |
51
+ | `*.svg` | Vector content |
52
+
53
+ ### 2A. Send to Gemini
54
+
55
+ Use the Gemini UI Generator script:
56
+
57
+ ```bash
58
+ node hooks/scripts/gemini-ui-gen.js \
59
+ --design-folder ./design/ui/ \
60
+ --framework react \
61
+ --output ./src/components
62
+ ```
63
+
64
+ **Or call Gemini API directly with all files:**
65
+
66
+ ```javascript
67
+ // Prepare multipart content
68
+ const parts = [
69
+ // Images as inline data
70
+ { inlineData: { mimeType: "image/png", data: imageBase64 } },
71
+ // HTML/CSS/JSON as text
72
+ { text: `HTML Mockup:\n${htmlContent}` },
73
+ { text: `CSS Styles:\n${cssContent}` },
74
+ { text: `Design Tokens:\n${jsonContent}` },
75
+ // Prompt
76
+ { text: `
77
+ Analyze these design files and generate production-ready React components.
78
+
79
+ Requirements:
80
+ 1. Match the visual design exactly
81
+ 2. Use Tailwind CSS
82
+ 3. TypeScript with proper types
83
+ 4. Responsive and accessible
84
+
85
+ Output complete component code.
86
+ ` }
87
+ ];
88
+ ```
89
+
90
+ ### 3A. Apply Gemini's Output
91
+
92
+ 1. Parse Gemini's code output
93
+ 2. Extract component files
94
+ 3. Compare with existing code
95
+ 4. Show diff to user
96
+ 5. Apply with confirmation
97
+
98
+ ---
99
+
100
+ ## Path B: Gemini NOT Available (Claude Fallback)
101
+
102
+ ### 1B. Read ALL Design Files
103
+
104
+ **MANDATORY: Read every file in the design folder.**
105
+
106
+ | Format | What to Extract |
107
+ | ------ | --------------- |
108
+ | `*.html` | Structure, components, layout, classes |
109
+ | `*.png` / `*.jpg` / `*.webp` | Visual layout, colors, spacing, typography |
110
+ | `*.json` | Design tokens, theme config, component props |
111
+ | `*.css` / `*.scss` | Variables, colors, spacing, typography |
112
+ | `*.md` | Design guidelines, component specs |
113
+ | `*.svg` | Icons, vector assets |
114
+
115
+ **Reading order:**
116
+
117
+ 1. `*.md` files first (design specs/guidelines)
118
+ 2. `*.html` files (structure reference)
119
+ 3. `*.png` / `*.jpg` images (visual reference - use Read tool)
120
+ 4. `*.json` (design tokens)
121
+ 5. `*.css` / `*.scss` (styles)
122
+
123
+ **CRITICAL:** Do NOT skip any file. Read images with the Read tool.
124
+
125
+ ### 2B. Analyze Design Intent (Claude)
126
+
127
+ From all design files, extract:
128
+
129
+ **Layout:**
130
+ - Page structure (header, sidebar, main, footer)
131
+ - Grid system (columns, gaps)
132
+ - Responsive breakpoints
133
+
134
+ **Components:**
135
+ - Component hierarchy
136
+ - Component names and types
137
+ - Props and variants
138
+
139
+ **Styling:**
140
+ - Color palette (primary, secondary, accent, background, text)
141
+ - Typography (font family, sizes, weights)
142
+ - Spacing system (padding, margin, gaps)
143
+ - Border radius, shadows
144
+ - Dark/light theme support
145
+
146
+ ### 3B. Generate Code (Claude)
147
+
148
+ Claude generates the code directly based on analysis.
149
+
150
+ ---
151
+
152
+ ## Common Steps (Both Paths)
153
+
154
+ ### 4. Find Existing UI Code
155
+
156
+ Search for existing UI implementation:
157
+
158
+ ```
159
+ src/components/
160
+ src/pages/
161
+ src/views/
162
+ src/ui/
163
+ app/components/
164
+ app/(routes)/
165
+ ```
166
+
167
+ Detect framework:
168
+ - React: `*.tsx`, `*.jsx`
169
+ - Vue: `*.vue`
170
+ - Svelte: `*.svelte`
171
+ - Angular: `*.component.ts`
172
+
173
+ ### 5. Compare Design vs Code
174
+
175
+ Create a diff report:
176
+
177
+ | Aspect | Design | Current Code | Action |
178
+ | ------ | ------ | ------------ | ------ |
179
+ | Colors | #2F6BFF | #3B82F6 | Update |
180
+ | Font | Inter | system-ui | Update |
181
+ | Border radius | 12px | 8px | Update |
182
+ | Component X | Exists | Missing | Create |
183
+
184
+ ### 6. Generate Update Plan
185
+
186
+ List all changes needed:
187
+
188
+ **Style Updates:**
189
+ ```css
190
+ /* Before */
191
+ --primary: #3B82F6;
192
+ --radius: 8px;
193
+
194
+ /* After */
195
+ --primary: #2F6BFF;
196
+ --radius: 12px;
197
+ ```
198
+
199
+ **Component Updates:**
200
+ ```tsx
201
+ // Before: Missing hover state
202
+ <Button>Click</Button>
203
+
204
+ // After: Add hover state from design
205
+ <Button className="hover:bg-primary-600">Click</Button>
206
+ ```
207
+
208
+ **New Components:**
209
+ - List components that exist in design but not in code
210
+
211
+ ### 7. Execute Updates
212
+
213
+ **Ask user before making changes:**
214
+
215
+ ```
216
+ Found 12 differences between design and code:
217
+ - 3 color updates
218
+ - 2 spacing changes
219
+ - 1 new component
220
+ - 6 style adjustments
221
+
222
+ Proceed with updates? [Y/n]
223
+ ```
224
+
225
+ **Apply changes:**
226
+
227
+ 1. Update CSS/SCSS variables
228
+ 2. Update Tailwind config (if applicable)
229
+ 3. Update component styles
230
+ 4. Create new components (if needed)
231
+ 5. Update imports
232
+
233
+ ### 8. Verify Changes
234
+
235
+ After updates:
236
+
237
+ 1. Run build to check for errors
238
+ 2. Show before/after comparison
239
+ 3. List all files modified
240
+
241
+ ## Output Format
242
+
243
+ ```
244
+ 📂 Design Analysis: ./design/ui/
245
+ 🤖 Mode: Gemini (or Claude fallback)
246
+
247
+ Files Read:
248
+ ✓ homepage.html (structure)
249
+ ✓ homepage.png (visual)
250
+ ✓ tokens.json (design tokens)
251
+ ✓ styles.css (variables)
252
+
253
+ Design Specs Extracted:
254
+ Colors: #2F6BFF (primary), #1E293B (text), #F8FAFC (bg)
255
+ Typography: Inter, 14px base, 1.5 line-height
256
+ Spacing: 4px base unit
257
+ Border Radius: 12px (cards), 8px (buttons)
258
+
259
+ Differences Found: 8
260
+
261
+ | File | Change | Status |
262
+ |------|--------|--------|
263
+ | tailwind.config.js | Update primary color | ⏳ Pending |
264
+ | src/components/Button.tsx | Add hover state | ⏳ Pending |
265
+ | src/styles/globals.css | Update CSS variables | ⏳ Pending |
266
+
267
+ Apply changes? [Y/n]
268
+
269
+ ✅ Updated 3 files
270
+ - tailwind.config.js
271
+ - src/components/Button.tsx
272
+ - src/styles/globals.css
273
+
274
+ Next: Run `npm run build` to verify
275
+ ```
276
+
277
+ ## Example (with Gemini)
278
+
279
+ ```
280
+ User: /vibe.utils --ui-sync ./design/dashboard/
281
+
282
+ Claude: Checking Gemini status...
283
+ ✅ Gemini: OAuth authenticated (user@example.com)
284
+
285
+ 📂 Collecting design files...
286
+ - dashboard.html
287
+ - dashboard-dark.png
288
+ - dashboard-light.png
289
+ - tokens.json
290
+ - components.md
291
+
292
+ 🤖 Sending to Gemini for analysis...
293
+
294
+ Gemini Response:
295
+ Layout: Header + Sidebar + 3-column main
296
+ Theme: Dark (#0F172A bg, #F8FAFC text)
297
+ Components: Header, Sidebar, StatCard, DataTable
298
+
299
+ Generated code:
300
+ - Header.tsx (64 lines)
301
+ - Sidebar.tsx (45 lines)
302
+ - StatCard.tsx (32 lines)
303
+ - DataTable.tsx (78 lines)
304
+
305
+ 🔍 Comparing with existing code...
306
+
307
+ Found: src/pages/Dashboard.tsx
308
+ Found: src/components/StatCard.tsx
309
+ Missing: src/components/DataTable.tsx
310
+
311
+ Differences:
312
+ 1. StatCard border-radius: design=16px, code=8px
313
+ 2. Sidebar width: design=240px, code=200px
314
+ 3. Primary color: design=#6366F1, code=#3B82F6
315
+ 4. DataTable component: missing
316
+
317
+ Apply 3 updates + create 1 component? [Y/n]
318
+ ```
319
+
320
+ ## Example (Claude Fallback)
321
+
322
+ ```
323
+ User: /vibe.utils --ui-sync ./design/dashboard/
324
+
325
+ Claude: Checking Gemini status...
326
+ ⚠️ Gemini not configured. Using Claude fallback.
327
+
328
+ 📂 Reading design files...
329
+
330
+ Reading dashboard.html...
331
+ [Extracts: header, sidebar, 3-column grid]
332
+
333
+ Reading dashboard-dark.png...
334
+ [Analyzes: dark theme colors, spacing]
335
+
336
+ Reading tokens.json...
337
+ [Extracts: color palette, spacing scale]
338
+
339
+ 📊 Design Analysis Complete (Claude):
340
+
341
+ Layout: Header + Sidebar + 3-column main
342
+ Theme: Dark (#0F172A bg, #F8FAFC text)
343
+
344
+ 🔍 Comparing with existing code...
345
+ ...
346
+ ```
347
+
348
+ ## Notes
349
+
350
+ - Always check Gemini status first
351
+ - Gemini handles image analysis better than Claude for visual matching
352
+ - Claude fallback works but may be less accurate for complex visuals
353
+ - Always read ALL files including images
354
+ - Ask for confirmation before making changes
355
+ - Preserve existing functionality while updating styles
356
+
357
+ ---
358
+
359
+ ARGUMENTS: $ARGUMENTS
@@ -11,6 +11,7 @@ Collection of utility tools. Use with options.
11
11
 
12
12
  ```
13
13
  /vibe.utils --ui "description" # UI ASCII preview
14
+ /vibe.utils --ui-sync ./design/ # Sync UI code with design files
14
15
  /vibe.utils --diagram # Architecture diagram
15
16
  /vibe.utils --diagram --er # ERD diagram
16
17
  /vibe.utils --diagram --flow # Flowchart
@@ -63,6 +64,46 @@ Generate UI preview from description or design folder.
63
64
 
64
65
  ---
65
66
 
67
+ ## --ui-sync (Design to Code Sync)
68
+
69
+ Read and follow `agents/ui-syncer.md` for design-to-code synchronization.
70
+
71
+ Analyze design files (HTML, images, CSS, tokens) and update existing UI code to match.
72
+
73
+ **What it does:**
74
+
75
+ 1. Read ALL design files (including images)
76
+ 2. Extract design specs (colors, typography, spacing, components)
77
+ 3. Compare with existing code
78
+ 4. Generate update plan
79
+ 5. Apply changes (with confirmation)
80
+
81
+ **Supported file formats:**
82
+
83
+ - `*.html` - Structure, layout, classes
84
+ - `*.png` / `*.jpg` / `*.webp` - Visual reference (Claude reads images)
85
+ - `*.json` - Design tokens, theme config
86
+ - `*.css` / `*.scss` - Variables, colors, spacing
87
+ - `*.md` - Design guidelines
88
+ - `*.svg` - Icons, vectors
89
+
90
+ **Example:**
91
+
92
+ ```
93
+ /vibe.utils --ui-sync ./design/ui/
94
+ /vibe.utils --ui-sync ./mockups/dashboard/
95
+ /vibe.utils --ui-sync ./design/homepage.html
96
+ ```
97
+
98
+ **Output:**
99
+
100
+ - Diff report (design vs code)
101
+ - List of changes to apply
102
+ - Confirmation prompt
103
+ - Files modified
104
+
105
+ ---
106
+
66
107
  ## --diagram (Diagram Generation)
67
108
 
68
109
  Read and follow `agents/diagrammer.md` for diagram generation.
@@ -0,0 +1,409 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Gemini UI Code Generator
5
+ *
6
+ * 디자인 파일(이미지, HTML 등)을 분석해서 UI 코드를 생성합니다.
7
+ *
8
+ * Usage:
9
+ * node gemini-ui-gen.js --image ./design.png --framework react --output ./src/components
10
+ * node gemini-ui-gen.js --html ./mockup.html --framework vue --output ./src/components
11
+ * node gemini-ui-gen.js --design-folder ./design/ --framework react --output ./src
12
+ */
13
+
14
+ import fs from 'fs';
15
+ import path from 'path';
16
+ import os from 'os';
17
+
18
+ // ============================================
19
+ // Config
20
+ // ============================================
21
+
22
+ function getGlobalConfigDir() {
23
+ return process.platform === 'win32'
24
+ ? path.join(process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming'), 'vibe')
25
+ : path.join(process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config'), 'vibe');
26
+ }
27
+
28
+ function getGeminiCredentials() {
29
+ const configDir = getGlobalConfigDir();
30
+
31
+ // OAuth 토큰 확인
32
+ const tokenPath = path.join(configDir, 'gemini-token.json');
33
+ if (fs.existsSync(tokenPath)) {
34
+ const tokenData = JSON.parse(fs.readFileSync(tokenPath, 'utf-8'));
35
+ if (tokenData.access_token) {
36
+ return { type: 'oauth', accessToken: tokenData.access_token };
37
+ }
38
+ }
39
+
40
+ // API Key 확인
41
+ const keyPath = path.join(configDir, 'gemini-apikey.json');
42
+ if (fs.existsSync(keyPath)) {
43
+ const keyData = JSON.parse(fs.readFileSync(keyPath, 'utf-8'));
44
+ if (keyData.apiKey) {
45
+ return { type: 'apikey', apiKey: keyData.apiKey };
46
+ }
47
+ }
48
+
49
+ return null;
50
+ }
51
+
52
+ // ============================================
53
+ // Gemini API with Vision
54
+ // ============================================
55
+
56
+ async function callGeminiWithImage(imageBase64, mimeType, prompt, creds) {
57
+ const model = 'gemini-2.0-flash';
58
+
59
+ const requestBody = {
60
+ contents: [
61
+ {
62
+ role: 'user',
63
+ parts: [
64
+ {
65
+ inlineData: {
66
+ mimeType,
67
+ data: imageBase64
68
+ }
69
+ },
70
+ {
71
+ text: prompt
72
+ }
73
+ ]
74
+ }
75
+ ],
76
+ generationConfig: {
77
+ maxOutputTokens: 8192,
78
+ temperature: 0.3,
79
+ }
80
+ };
81
+
82
+ let url;
83
+ let headers;
84
+
85
+ if (creds.type === 'apikey') {
86
+ url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${creds.apiKey}`;
87
+ headers = { 'Content-Type': 'application/json' };
88
+ } else {
89
+ // OAuth - Antigravity
90
+ url = 'https://daily-cloudcode-pa.sandbox.googleapis.com/v1internal:generateContent';
91
+ headers = {
92
+ 'Authorization': `Bearer ${creds.accessToken}`,
93
+ 'Content-Type': 'application/json',
94
+ 'x-goog-api-client': 'vibe-ui-gen',
95
+ };
96
+
97
+ // Wrap for Antigravity
98
+ const wrappedBody = {
99
+ project: 'anthropic-api-proxy',
100
+ model: 'gemini-2.0-flash-001',
101
+ request: requestBody,
102
+ requestType: 'agent',
103
+ userAgent: 'antigravity',
104
+ requestId: `ui-gen-${Date.now()}`,
105
+ };
106
+ requestBody = wrappedBody;
107
+ }
108
+
109
+ const response = await fetch(url, {
110
+ method: 'POST',
111
+ headers,
112
+ body: JSON.stringify(creds.type === 'apikey' ? requestBody : requestBody),
113
+ });
114
+
115
+ if (!response.ok) {
116
+ const errorText = await response.text();
117
+ throw new Error(`Gemini API error (${response.status}): ${errorText}`);
118
+ }
119
+
120
+ const result = await response.json();
121
+ const responseData = result.response || result;
122
+
123
+ if (!responseData.candidates || responseData.candidates.length === 0) {
124
+ throw new Error('Gemini returned empty response');
125
+ }
126
+
127
+ return responseData.candidates[0].content?.parts?.[0]?.text || '';
128
+ }
129
+
130
+ async function callGeminiText(prompt, creds) {
131
+ const model = 'gemini-2.0-flash';
132
+
133
+ const requestBody = {
134
+ contents: [
135
+ {
136
+ role: 'user',
137
+ parts: [{ text: prompt }]
138
+ }
139
+ ],
140
+ generationConfig: {
141
+ maxOutputTokens: 8192,
142
+ temperature: 0.3,
143
+ }
144
+ };
145
+
146
+ let url;
147
+ let headers;
148
+
149
+ if (creds.type === 'apikey') {
150
+ url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${creds.apiKey}`;
151
+ headers = { 'Content-Type': 'application/json' };
152
+ } else {
153
+ url = 'https://daily-cloudcode-pa.sandbox.googleapis.com/v1internal:generateContent';
154
+ headers = {
155
+ 'Authorization': `Bearer ${creds.accessToken}`,
156
+ 'Content-Type': 'application/json',
157
+ };
158
+ }
159
+
160
+ const response = await fetch(url, {
161
+ method: 'POST',
162
+ headers,
163
+ body: JSON.stringify(requestBody),
164
+ });
165
+
166
+ if (!response.ok) {
167
+ const errorText = await response.text();
168
+ throw new Error(`Gemini API error (${response.status}): ${errorText}`);
169
+ }
170
+
171
+ const result = await response.json();
172
+ const responseData = result.response || result;
173
+
174
+ return responseData.candidates?.[0]?.content?.parts?.[0]?.text || '';
175
+ }
176
+
177
+ // ============================================
178
+ // UI Code Generation
179
+ // ============================================
180
+
181
+ function getFrameworkPrompt(framework) {
182
+ const prompts = {
183
+ react: `Generate React TypeScript components using:
184
+ - Functional components with hooks
185
+ - Tailwind CSS for styling
186
+ - Proper TypeScript types/interfaces
187
+ - Export as default`,
188
+
189
+ vue: `Generate Vue 3 components using:
190
+ - Composition API with <script setup>
191
+ - Tailwind CSS for styling
192
+ - TypeScript support
193
+ - Single File Component format`,
194
+
195
+ svelte: `Generate Svelte components using:
196
+ - Svelte 5 runes syntax
197
+ - Tailwind CSS for styling
198
+ - TypeScript support`,
199
+
200
+ html: `Generate semantic HTML5 with:
201
+ - Tailwind CSS classes
202
+ - Accessible markup
203
+ - Responsive design`,
204
+ };
205
+
206
+ return prompts[framework] || prompts.react;
207
+ }
208
+
209
+ async function generateUIFromImage(imagePath, framework, creds) {
210
+ const imageBuffer = fs.readFileSync(imagePath);
211
+ const imageBase64 = imageBuffer.toString('base64');
212
+
213
+ const ext = path.extname(imagePath).toLowerCase();
214
+ const mimeTypes = {
215
+ '.png': 'image/png',
216
+ '.jpg': 'image/jpeg',
217
+ '.jpeg': 'image/jpeg',
218
+ '.webp': 'image/webp',
219
+ '.gif': 'image/gif',
220
+ };
221
+ const mimeType = mimeTypes[ext] || 'image/png';
222
+
223
+ const prompt = `Analyze this UI design image and generate production-ready code.
224
+
225
+ ${getFrameworkPrompt(framework)}
226
+
227
+ Requirements:
228
+ 1. Match the visual design exactly (colors, spacing, typography, layout)
229
+ 2. Extract exact colors as hex values
230
+ 3. Use proper semantic HTML structure
231
+ 4. Make it responsive (mobile-first)
232
+ 5. Include hover/focus states where appropriate
233
+ 6. Add appropriate accessibility attributes
234
+
235
+ Output format:
236
+ \`\`\`${framework === 'html' ? 'html' : 'tsx'}
237
+ // Component code here
238
+ \`\`\`
239
+
240
+ Also provide a summary of:
241
+ - Colors extracted
242
+ - Components identified
243
+ - Layout structure`;
244
+
245
+ return callGeminiWithImage(imageBase64, mimeType, prompt, creds);
246
+ }
247
+
248
+ async function generateUIFromHTML(htmlPath, framework, creds) {
249
+ const htmlContent = fs.readFileSync(htmlPath, 'utf-8');
250
+
251
+ const prompt = `Convert this HTML mockup to production-ready ${framework} code.
252
+
253
+ HTML Mockup:
254
+ \`\`\`html
255
+ ${htmlContent}
256
+ \`\`\`
257
+
258
+ ${getFrameworkPrompt(framework)}
259
+
260
+ Requirements:
261
+ 1. Preserve the exact visual appearance
262
+ 2. Extract inline styles to Tailwind classes
263
+ 3. Create reusable components where appropriate
264
+ 4. Add proper TypeScript types
265
+ 5. Make it responsive
266
+
267
+ Output the converted code in proper format.`;
268
+
269
+ return callGeminiText(prompt, creds);
270
+ }
271
+
272
+ async function analyzeDesignFolder(folderPath, framework, creds) {
273
+ const files = fs.readdirSync(folderPath);
274
+ const results = [];
275
+
276
+ // Read all files
277
+ for (const file of files) {
278
+ const filePath = path.join(folderPath, file);
279
+ const ext = path.extname(file).toLowerCase();
280
+
281
+ if (['.png', '.jpg', '.jpeg', '.webp'].includes(ext)) {
282
+ console.log(`📷 Analyzing image: ${file}`);
283
+ const result = await generateUIFromImage(filePath, framework, creds);
284
+ results.push({ file, type: 'image', result });
285
+ } else if (ext === '.html') {
286
+ console.log(`📄 Analyzing HTML: ${file}`);
287
+ const result = await generateUIFromHTML(filePath, framework, creds);
288
+ results.push({ file, type: 'html', result });
289
+ } else if (ext === '.json') {
290
+ console.log(`📋 Reading tokens: ${file}`);
291
+ const content = fs.readFileSync(filePath, 'utf-8');
292
+ results.push({ file, type: 'tokens', content });
293
+ } else if (['.css', '.scss'].includes(ext)) {
294
+ console.log(`🎨 Reading styles: ${file}`);
295
+ const content = fs.readFileSync(filePath, 'utf-8');
296
+ results.push({ file, type: 'styles', content });
297
+ }
298
+ }
299
+
300
+ return results;
301
+ }
302
+
303
+ // ============================================
304
+ // CLI
305
+ // ============================================
306
+
307
+ async function main() {
308
+ const args = process.argv.slice(2);
309
+
310
+ // Parse arguments
311
+ const options = {
312
+ image: null,
313
+ html: null,
314
+ designFolder: null,
315
+ framework: 'react',
316
+ output: './generated',
317
+ };
318
+
319
+ for (let i = 0; i < args.length; i++) {
320
+ switch (args[i]) {
321
+ case '--image':
322
+ options.image = args[++i];
323
+ break;
324
+ case '--html':
325
+ options.html = args[++i];
326
+ break;
327
+ case '--design-folder':
328
+ case '--folder':
329
+ options.designFolder = args[++i];
330
+ break;
331
+ case '--framework':
332
+ case '-f':
333
+ options.framework = args[++i];
334
+ break;
335
+ case '--output':
336
+ case '-o':
337
+ options.output = args[++i];
338
+ break;
339
+ case '--help':
340
+ case '-h':
341
+ console.log(`
342
+ Gemini UI Code Generator
343
+
344
+ Usage:
345
+ node gemini-ui-gen.js --image ./design.png --framework react
346
+ node gemini-ui-gen.js --html ./mockup.html --framework vue
347
+ node gemini-ui-gen.js --design-folder ./design/ --framework react
348
+
349
+ Options:
350
+ --image <path> Image file to analyze
351
+ --html <path> HTML mockup to convert
352
+ --design-folder <path> Folder with design files
353
+ --framework <name> Target framework (react, vue, svelte, html)
354
+ --output <path> Output directory
355
+ --help Show this help
356
+ `);
357
+ process.exit(0);
358
+ }
359
+ }
360
+
361
+ // Check credentials
362
+ const creds = getGeminiCredentials();
363
+ if (!creds) {
364
+ console.error('❌ Gemini credentials not found. Run: vibe gemini auth');
365
+ process.exit(1);
366
+ }
367
+
368
+ console.log(`🤖 Gemini UI Generator (${creds.type})`);
369
+ console.log(`📦 Framework: ${options.framework}`);
370
+
371
+ try {
372
+ let result;
373
+
374
+ if (options.image) {
375
+ console.log(`\n📷 Analyzing: ${options.image}\n`);
376
+ result = await generateUIFromImage(options.image, options.framework, creds);
377
+ } else if (options.html) {
378
+ console.log(`\n📄 Converting: ${options.html}\n`);
379
+ result = await generateUIFromHTML(options.html, options.framework, creds);
380
+ } else if (options.designFolder) {
381
+ console.log(`\n📂 Analyzing folder: ${options.designFolder}\n`);
382
+ const results = await analyzeDesignFolder(options.designFolder, options.framework, creds);
383
+ result = JSON.stringify(results, null, 2);
384
+ } else {
385
+ console.error('❌ No input specified. Use --image, --html, or --design-folder');
386
+ process.exit(1);
387
+ }
388
+
389
+ console.log('\n' + '='.repeat(60) + '\n');
390
+ console.log(result);
391
+ console.log('\n' + '='.repeat(60));
392
+
393
+ // Output to file if specified
394
+ if (options.output && result) {
395
+ if (!fs.existsSync(options.output)) {
396
+ fs.mkdirSync(options.output, { recursive: true });
397
+ }
398
+ const outputFile = path.join(options.output, `generated-${Date.now()}.txt`);
399
+ fs.writeFileSync(outputFile, result);
400
+ console.log(`\n✅ Output saved to: ${outputFile}`);
401
+ }
402
+
403
+ } catch (error) {
404
+ console.error(`\n❌ Error: ${error.message}`);
405
+ process.exit(1);
406
+ }
407
+ }
408
+
409
+ main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@su-record/vibe",
3
- "version": "2.6.2",
3
+ "version": "2.6.4",
4
4
  "description": "Vibe - Claude Code exclusive SPEC-driven AI coding framework with 35+ integrated tools",
5
5
  "type": "module",
6
6
  "main": "dist/cli/index.js",