@nclamvn/vibecode-cli 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/.vibecode/learning/fixes.json +1 -0
  2. package/.vibecode/learning/preferences.json +1 -0
  3. package/README.md +310 -49
  4. package/SESSION_NOTES.md +154 -0
  5. package/bin/vibecode.js +212 -2
  6. package/package.json +5 -2
  7. package/src/agent/decomposition.js +476 -0
  8. package/src/agent/index.js +391 -0
  9. package/src/agent/memory.js +542 -0
  10. package/src/agent/orchestrator.js +917 -0
  11. package/src/agent/self-healing.js +516 -0
  12. package/src/commands/agent.js +349 -0
  13. package/src/commands/ask.js +230 -0
  14. package/src/commands/assist.js +413 -0
  15. package/src/commands/build.js +345 -4
  16. package/src/commands/debug.js +565 -0
  17. package/src/commands/docs.js +167 -0
  18. package/src/commands/git.js +1024 -0
  19. package/src/commands/go.js +387 -0
  20. package/src/commands/learn.js +294 -0
  21. package/src/commands/migrate.js +341 -0
  22. package/src/commands/plan.js +8 -2
  23. package/src/commands/refactor.js +205 -0
  24. package/src/commands/review.js +126 -1
  25. package/src/commands/security.js +229 -0
  26. package/src/commands/shell.js +486 -0
  27. package/src/commands/test.js +194 -0
  28. package/src/commands/undo.js +281 -0
  29. package/src/commands/watch.js +556 -0
  30. package/src/commands/wizard.js +322 -0
  31. package/src/config/constants.js +5 -1
  32. package/src/config/templates.js +146 -15
  33. package/src/core/backup.js +325 -0
  34. package/src/core/error-analyzer.js +237 -0
  35. package/src/core/fix-generator.js +195 -0
  36. package/src/core/iteration.js +226 -0
  37. package/src/core/learning.js +295 -0
  38. package/src/core/session.js +18 -2
  39. package/src/core/test-runner.js +281 -0
  40. package/src/debug/analyzer.js +329 -0
  41. package/src/debug/evidence.js +228 -0
  42. package/src/debug/fixer.js +348 -0
  43. package/src/debug/image-analyzer.js +304 -0
  44. package/src/debug/index.js +378 -0
  45. package/src/debug/verifier.js +346 -0
  46. package/src/index.js +89 -0
  47. package/src/providers/claude-code.js +12 -7
  48. package/src/ui/__tests__/error-translator.test.js +390 -0
  49. package/src/ui/dashboard.js +364 -0
  50. package/src/ui/error-translator.js +775 -0
  51. package/src/utils/image.js +222 -0
@@ -0,0 +1,222 @@
1
+ /**
2
+ * Image utilities for Vibecode CLI
3
+ * Handle clipboard images, file reading, and base64 conversion
4
+ */
5
+
6
+ import fs from 'fs/promises';
7
+ import path from 'path';
8
+ import { exec } from 'child_process';
9
+ import { promisify } from 'util';
10
+ import os from 'os';
11
+
12
+ const execAsync = promisify(exec);
13
+
14
+ /**
15
+ * Save clipboard image to temp file
16
+ * Supports macOS, Linux, and Windows
17
+ */
18
+ export async function saveClipboardImage() {
19
+ const platform = process.platform;
20
+ const tempDir = os.tmpdir();
21
+ const tempFile = path.join(tempDir, `vibecode-screenshot-${Date.now()}.png`);
22
+
23
+ if (platform === 'darwin') {
24
+ // macOS: Use pngpaste or osascript
25
+ try {
26
+ // Try pngpaste first (if installed via brew install pngpaste)
27
+ await execAsync(`pngpaste "${tempFile}"`);
28
+
29
+ // Verify file was created
30
+ const stats = await fs.stat(tempFile);
31
+ if (stats.size > 0) {
32
+ return tempFile;
33
+ }
34
+ throw new Error('Empty file');
35
+ } catch {
36
+ // Fallback to osascript
37
+ try {
38
+ const script = `
39
+ set theFile to POSIX file "${tempFile}"
40
+ try
41
+ set imageData to the clipboard as «class PNGf»
42
+ set fileRef to open for access theFile with write permission
43
+ write imageData to fileRef
44
+ close access fileRef
45
+ return "success"
46
+ on error errMsg
47
+ return "error: " & errMsg
48
+ end try
49
+ `;
50
+
51
+ const { stdout } = await execAsync(`osascript -e '${script.replace(/'/g, "'\\''")}'`);
52
+
53
+ if (stdout.trim().startsWith('success')) {
54
+ // Verify file was created
55
+ const stats = await fs.stat(tempFile);
56
+ if (stats.size > 0) {
57
+ return tempFile;
58
+ }
59
+ }
60
+
61
+ throw new Error('No image in clipboard');
62
+ } catch (e) {
63
+ throw new Error('No image in clipboard. Copy a screenshot first (Cmd+Shift+4).');
64
+ }
65
+ }
66
+ } else if (platform === 'linux') {
67
+ // Linux: Use xclip
68
+ try {
69
+ await execAsync(`xclip -selection clipboard -t image/png -o > "${tempFile}" 2>/dev/null`);
70
+
71
+ const stats = await fs.stat(tempFile);
72
+ if (stats.size > 0) {
73
+ return tempFile;
74
+ }
75
+ throw new Error('No image in clipboard');
76
+ } catch {
77
+ throw new Error('No image in clipboard. Make sure xclip is installed: sudo apt install xclip');
78
+ }
79
+ } else if (platform === 'win32') {
80
+ // Windows: Use PowerShell
81
+ try {
82
+ const psScript = `
83
+ Add-Type -AssemblyName System.Windows.Forms
84
+ $img = [System.Windows.Forms.Clipboard]::GetImage()
85
+ if ($img -ne $null) {
86
+ $img.Save('${tempFile.replace(/\\/g, '\\\\')}', [System.Drawing.Imaging.ImageFormat]::Png)
87
+ Write-Output 'success'
88
+ } else {
89
+ Write-Output 'no image'
90
+ }
91
+ `.replace(/\n/g, ' ');
92
+
93
+ const { stdout } = await execAsync(`powershell -Command "${psScript}"`);
94
+
95
+ if (stdout.trim() === 'success') {
96
+ return tempFile;
97
+ }
98
+ throw new Error('No image in clipboard');
99
+ } catch {
100
+ throw new Error('No image in clipboard');
101
+ }
102
+ }
103
+
104
+ throw new Error(`Unsupported platform: ${platform}`);
105
+ }
106
+
107
+ /**
108
+ * Read image file and convert to base64
109
+ */
110
+ export async function imageToBase64(imagePath) {
111
+ const absolutePath = path.resolve(imagePath);
112
+
113
+ // Check file exists
114
+ try {
115
+ await fs.access(absolutePath);
116
+ } catch {
117
+ throw new Error(`Image file not found: ${imagePath}`);
118
+ }
119
+
120
+ // Read file
121
+ const imageBuffer = await fs.readFile(absolutePath);
122
+ const base64 = imageBuffer.toString('base64');
123
+
124
+ // Detect mime type from extension
125
+ const ext = path.extname(absolutePath).toLowerCase();
126
+ const mimeTypes = {
127
+ '.png': 'image/png',
128
+ '.jpg': 'image/jpeg',
129
+ '.jpeg': 'image/jpeg',
130
+ '.gif': 'image/gif',
131
+ '.webp': 'image/webp',
132
+ '.bmp': 'image/bmp'
133
+ };
134
+ const mimeType = mimeTypes[ext] || 'image/png';
135
+
136
+ return {
137
+ base64,
138
+ mimeType,
139
+ dataUrl: `data:${mimeType};base64,${base64}`,
140
+ path: absolutePath,
141
+ size: imageBuffer.length
142
+ };
143
+ }
144
+
145
+ /**
146
+ * Get image information
147
+ */
148
+ export async function getImageInfo(imagePath) {
149
+ const info = await imageToBase64(imagePath);
150
+ const stats = await fs.stat(imagePath);
151
+
152
+ return {
153
+ ...info,
154
+ fileSize: stats.size,
155
+ fileName: path.basename(imagePath),
156
+ extension: path.extname(imagePath).toLowerCase()
157
+ };
158
+ }
159
+
160
+ /**
161
+ * Check if file is a valid image
162
+ */
163
+ export async function isValidImage(imagePath) {
164
+ const validExtensions = ['.png', '.jpg', '.jpeg', '.gif', '.webp', '.bmp'];
165
+ const ext = path.extname(imagePath).toLowerCase();
166
+
167
+ if (!validExtensions.includes(ext)) {
168
+ return false;
169
+ }
170
+
171
+ try {
172
+ await fs.access(imagePath);
173
+ const stats = await fs.stat(imagePath);
174
+ return stats.size > 0;
175
+ } catch {
176
+ return false;
177
+ }
178
+ }
179
+
180
+ /**
181
+ * Cleanup temporary vibecode images
182
+ */
183
+ export async function cleanupTempImages() {
184
+ const tempDir = os.tmpdir();
185
+
186
+ try {
187
+ const files = await fs.readdir(tempDir);
188
+ const vibecodeImages = files.filter(f => f.startsWith('vibecode-screenshot-'));
189
+
190
+ let cleaned = 0;
191
+ for (const file of vibecodeImages) {
192
+ try {
193
+ await fs.unlink(path.join(tempDir, file));
194
+ cleaned++;
195
+ } catch {
196
+ // Ignore errors
197
+ }
198
+ }
199
+
200
+ return cleaned;
201
+ } catch {
202
+ return 0;
203
+ }
204
+ }
205
+
206
+ /**
207
+ * Format file size for display
208
+ */
209
+ export function formatFileSize(bytes) {
210
+ if (bytes < 1024) return `${bytes} B`;
211
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
212
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
213
+ }
214
+
215
+ export default {
216
+ saveClipboardImage,
217
+ imageToBase64,
218
+ getImageInfo,
219
+ isValidImage,
220
+ cleanupTempImages,
221
+ formatFileSize
222
+ };