@nclamvn/vibecode-cli 2.0.0 → 2.2.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 (53) 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 +235 -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 +635 -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/templates.js +397 -0
  28. package/src/commands/test.js +194 -0
  29. package/src/commands/undo.js +281 -0
  30. package/src/commands/watch.js +556 -0
  31. package/src/commands/wizard.js +322 -0
  32. package/src/config/constants.js +5 -1
  33. package/src/config/templates.js +146 -15
  34. package/src/core/backup.js +325 -0
  35. package/src/core/error-analyzer.js +237 -0
  36. package/src/core/fix-generator.js +195 -0
  37. package/src/core/iteration.js +226 -0
  38. package/src/core/learning.js +295 -0
  39. package/src/core/session.js +18 -2
  40. package/src/core/test-runner.js +281 -0
  41. package/src/debug/analyzer.js +329 -0
  42. package/src/debug/evidence.js +228 -0
  43. package/src/debug/fixer.js +348 -0
  44. package/src/debug/image-analyzer.js +304 -0
  45. package/src/debug/index.js +378 -0
  46. package/src/debug/verifier.js +346 -0
  47. package/src/index.js +102 -0
  48. package/src/providers/claude-code.js +12 -7
  49. package/src/templates/index.js +724 -0
  50. package/src/ui/__tests__/error-translator.test.js +390 -0
  51. package/src/ui/dashboard.js +364 -0
  52. package/src/ui/error-translator.js +775 -0
  53. package/src/utils/image.js +222 -0
@@ -0,0 +1,565 @@
1
+ // ═══════════════════════════════════════════════════════════════════════════════
2
+ // VIBECODE CLI - Debug Command
3
+ // Phase G: Intelligent 9-Step Bug Fixing
4
+ // ═══════════════════════════════════════════════════════════════════════════════
5
+
6
+ import chalk from 'chalk';
7
+ import ora from 'ora';
8
+ import path from 'path';
9
+ import fs from 'fs-extra';
10
+ import readline from 'readline';
11
+ import inquirer from 'inquirer';
12
+ import { printBox, printError, printSuccess, printWarning, printNextStep } from '../ui/output.js';
13
+ import { createDebugEngine } from '../debug/index.js';
14
+ import { ImageAnalyzer } from '../debug/image-analyzer.js';
15
+
16
+ /**
17
+ * Debug Command Entry Point
18
+ * Usage:
19
+ * vibecode debug - Interactive mode (default)
20
+ * vibecode debug "error description" - Debug with description
21
+ * vibecode debug --log - Paste error log
22
+ * vibecode debug --image <path> - Debug from screenshot
23
+ * vibecode debug --auto - Auto-scan and fix
24
+ */
25
+ export async function debugCommand(args = [], options = {}) {
26
+ try {
27
+ const projectPath = process.cwd();
28
+
29
+ // Handle image input modes first
30
+ if (options.image) {
31
+ return handleImageDebug(options.image, projectPath, options);
32
+ }
33
+
34
+ if (options.clipboard) {
35
+ return handleClipboardDebug(projectPath, options);
36
+ }
37
+
38
+ // Parse command arguments
39
+ const input = parseDebugInput(args, options);
40
+
41
+ // If interactive mode or no input provided, enter interactive mode
42
+ if (options.interactive || (!input.description && !input.log && !input.image && !input.auto)) {
43
+ return interactiveDebug(projectPath, options);
44
+ }
45
+
46
+ // Create debug engine
47
+ const engine = createDebugEngine(projectPath, {
48
+ autoFix: options.autoFix !== false,
49
+ maxAttempts: options.attempts || 3,
50
+ verbose: options.verbose || false,
51
+ interactive: !options.quiet
52
+ });
53
+
54
+ // Show intro
55
+ console.log();
56
+ printBox(`🔍 VIBECODE DEBUG
57
+
58
+ Intelligent 9-Step Bug Fixing
59
+ Mode: ${input.auto ? 'Auto-Scan' : input.log ? 'Log Analysis' : input.image ? 'Image Analysis' : 'Description'}
60
+ Max Attempts: ${options.attempts || 3}`, { borderColor: 'cyan' });
61
+ console.log();
62
+
63
+ // Run debug workflow
64
+ const result = await engine.debug(input);
65
+
66
+ // Show final result
67
+ await showDebugResult(result, projectPath);
68
+
69
+ } catch (error) {
70
+ printError(`Debug failed: ${error.message}`);
71
+ if (options.verbose) {
72
+ console.error(error.stack);
73
+ }
74
+ process.exit(1);
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Parse debug input from args and options
80
+ */
81
+ function parseDebugInput(args, options) {
82
+ const input = {
83
+ description: null,
84
+ log: null,
85
+ image: null,
86
+ auto: options.auto || false
87
+ };
88
+
89
+ // Join args as description
90
+ if (args.length > 0) {
91
+ input.description = args.join(' ');
92
+ }
93
+
94
+ // Log paste mode
95
+ if (options.log) {
96
+ if (typeof options.log === 'string') {
97
+ input.log = options.log;
98
+ } else {
99
+ // Will need to read from stdin or file
100
+ input.log = options.logContent || null;
101
+ }
102
+ }
103
+
104
+ // Image mode
105
+ if (options.image) {
106
+ input.image = options.image;
107
+ }
108
+
109
+ return input;
110
+ }
111
+
112
+ /**
113
+ * Show debug result summary
114
+ */
115
+ async function showDebugResult(result, projectPath) {
116
+ console.log();
117
+
118
+ if (result.status === 'resolved') {
119
+ const content = `✅ BUG FIXED!
120
+
121
+ Status: ${result.status}
122
+ Attempts: ${result.session.attempts}
123
+ Steps: ${result.session.steps}
124
+
125
+ Documentation saved to:
126
+ .vibecode/debug/fixes.md
127
+
128
+ Prevention rules added to:
129
+ CLAUDE.md`;
130
+
131
+ printBox(content, { borderColor: 'green' });
132
+ printNextStep('Build your project to verify the fix');
133
+
134
+ } else if (result.status === 'no_error') {
135
+ printSuccess('No errors found to fix!');
136
+
137
+ } else if (result.status === 'no_hypothesis') {
138
+ printWarning('Could not determine how to fix this error.');
139
+ console.log(chalk.gray('\nTry:'));
140
+ console.log(chalk.gray(' • Providing more details about the error'));
141
+ console.log(chalk.gray(' • Pasting the full error log with --log'));
142
+ console.log(chalk.gray(' • Running vibecode debug --auto to scan project'));
143
+
144
+ } else {
145
+ // Show escalation options - user NEVER bế tắc
146
+ console.log(chalk.yellow(`
147
+ ╭───────────────────────────────────────────────────────────────────╮
148
+ │ │
149
+ │ ⚠️ COULD NOT AUTO-RESOLVE │
150
+ │ │
151
+ │ Status: ${result.status.padEnd(47)}│
152
+ │ Attempts: ${String(result.session.attempts).padEnd(45)}│
153
+ │ │
154
+ │ Don't worry! You have options: │
155
+ │ │
156
+ │ 1. vibecode assist "describe your issue" │
157
+ │ → Direct AI expert access with full context │
158
+ │ │
159
+ │ 2. vibecode debug -i │
160
+ │ → Interactive debug with more context │
161
+ │ │
162
+ │ 3. vibecode debug --attempts 5 │
163
+ │ → Retry with more attempts │
164
+ │ │
165
+ ╰───────────────────────────────────────────────────────────────────╯
166
+ `));
167
+
168
+ // Ask if user wants to auto-escalate to summon
169
+ const rl = readline.createInterface({
170
+ input: process.stdin,
171
+ output: process.stdout
172
+ });
173
+
174
+ try {
175
+ const answer = await new Promise(resolve => {
176
+ rl.question(chalk.cyan('\n🤝 Escalate to AI Assist? (Y/n): '), resolve);
177
+ });
178
+ rl.close();
179
+
180
+ if (answer.toLowerCase() !== 'n') {
181
+ const { assistCommand } = await import('./assist.js');
182
+ const errorMsg = result.message || 'the error that occurred';
183
+ await assistCommand([`Fix ${errorMsg}`], {});
184
+ }
185
+ } catch {
186
+ rl.close();
187
+ }
188
+ }
189
+ }
190
+
191
+ /**
192
+ * Handle image file debug
193
+ */
194
+ async function handleImageDebug(imagePath, projectPath, options) {
195
+ const analyzer = new ImageAnalyzer(projectPath);
196
+
197
+ try {
198
+ const analysis = await analyzer.analyzeImage(imagePath);
199
+ console.log(analyzer.formatAnalysis(analysis));
200
+
201
+ // If error detected, ask to fix
202
+ if (analysis.errorType && analysis.suggestedFix) {
203
+ const { fix } = await inquirer.prompt([{
204
+ type: 'confirm',
205
+ name: 'fix',
206
+ message: 'Apply suggested fix?',
207
+ default: true
208
+ }]);
209
+
210
+ if (fix) {
211
+ return debugWithAnalysis(analysis, projectPath, options);
212
+ }
213
+ }
214
+ } catch (error) {
215
+ printError(error.message);
216
+ }
217
+ }
218
+
219
+ /**
220
+ * Handle clipboard image debug
221
+ */
222
+ async function handleClipboardDebug(projectPath, options) {
223
+ const analyzer = new ImageAnalyzer(projectPath);
224
+
225
+ try {
226
+ const analysis = await analyzer.analyzeClipboard();
227
+ console.log(analyzer.formatAnalysis(analysis));
228
+
229
+ // If error detected, ask to fix
230
+ if (analysis.errorType && analysis.suggestedFix) {
231
+ const { fix } = await inquirer.prompt([{
232
+ type: 'confirm',
233
+ name: 'fix',
234
+ message: 'Apply suggested fix?',
235
+ default: true
236
+ }]);
237
+
238
+ if (fix) {
239
+ return debugWithAnalysis(analysis, projectPath, options);
240
+ }
241
+ }
242
+ } catch (error) {
243
+ printError(error.message);
244
+ }
245
+ }
246
+
247
+ /**
248
+ * Debug with analysis from image
249
+ */
250
+ async function debugWithAnalysis(analysis, projectPath, options) {
251
+ // Build error description from analysis
252
+ const errorDescription = [
253
+ analysis.errorType,
254
+ analysis.errorMessage,
255
+ analysis.location ? `at ${analysis.location}` : '',
256
+ analysis.rootCause ? `Cause: ${analysis.rootCause}` : ''
257
+ ].filter(Boolean).join(' - ');
258
+
259
+ console.log(chalk.cyan(`\n Attempting to fix: ${analysis.errorType}\n`));
260
+
261
+ // Create debug engine and run
262
+ const engine = createDebugEngine(projectPath, {
263
+ autoFix: true,
264
+ maxAttempts: options.attempts || 3,
265
+ verbose: options.verbose || false,
266
+ interactive: !options.quiet
267
+ });
268
+
269
+ const input = {
270
+ description: errorDescription,
271
+ suggestedFix: analysis.suggestedFix,
272
+ fromImage: true
273
+ };
274
+
275
+ const result = await engine.debug(input);
276
+
277
+ // Show result
278
+ if (result.status === 'resolved') {
279
+ printSuccess('Bug fixed successfully!');
280
+ } else {
281
+ printWarning('Could not auto-fix. Try: vibecode assist "' + analysis.errorMessage + '"');
282
+ }
283
+ }
284
+
285
+ /**
286
+ * Show debug command help
287
+ */
288
+ function showDebugHelp() {
289
+ console.log();
290
+ printBox(`🔍 VIBECODE DEBUG - Help
291
+
292
+ Intelligent 9-step bug fixing powered by AI.
293
+
294
+ Usage:
295
+ vibecode debug "error description" Quick fix from description
296
+ vibecode debug --auto Auto-scan project for errors
297
+ vibecode debug --log "error text" Fix from error log
298
+ vibecode debug --image path/to/img Fix from screenshot
299
+ vibecode debug --clipboard Fix from clipboard image
300
+
301
+ Options:
302
+ --auto Auto-scan mode - find and fix errors
303
+ --log <text> Provide error log directly
304
+ --image <path> Provide error screenshot
305
+ --clipboard Analyze image from clipboard
306
+ --attempts <n> Max fix attempts (default: 3)
307
+ --verbose Show detailed output
308
+ --quiet Minimal output
309
+
310
+ Examples:
311
+ vibecode debug "Cannot read property of undefined"
312
+ vibecode debug --auto
313
+ vibecode debug --log "TypeError: x is not a function"
314
+ vibecode debug --image ./error-screenshot.png
315
+ vibecode debug --clipboard`, { borderColor: 'cyan' });
316
+ console.log();
317
+ }
318
+
319
+ /**
320
+ * Interactive Debug Mode
321
+ * REPL-like interface for debugging
322
+ */
323
+ async function interactiveDebug(projectPath, options) {
324
+ const engine = createDebugEngine(projectPath, {
325
+ autoFix: true,
326
+ maxAttempts: options.attempts || 3,
327
+ verbose: options.verbose || false,
328
+ interactive: true
329
+ });
330
+
331
+ // Show welcome banner
332
+ console.log(chalk.cyan(`
333
+ ╭────────────────────────────────────────────────────────────────────╮
334
+ │ │
335
+ │ 🔍 VIBECODE DEBUG (Interactive Mode) │
336
+ │ │
337
+ │ Commands: │
338
+ │ • Type error description or paste log │
339
+ │ • /scan - Auto-scan project for errors │
340
+ │ • /fix - Apply last suggested fix │
341
+ │ • /retry - Retry with current context │
342
+ │ • /clear - Clear context │
343
+ │ • /help - Show help │
344
+ │ • /quit - Exit │
345
+ │ │
346
+ ╰────────────────────────────────────────────────────────────────────╯
347
+ `));
348
+
349
+ const rl = readline.createInterface({
350
+ input: process.stdin,
351
+ output: process.stdout,
352
+ prompt: chalk.green('debug> ')
353
+ });
354
+
355
+ // Session context
356
+ const context = {
357
+ errors: [],
358
+ lastAnalysis: null,
359
+ lastFix: null,
360
+ lastEvidence: null
361
+ };
362
+
363
+ rl.prompt();
364
+
365
+ rl.on('line', async (line) => {
366
+ const input = line.trim();
367
+
368
+ if (!input) {
369
+ rl.prompt();
370
+ return;
371
+ }
372
+
373
+ // Handle commands
374
+ if (input.startsWith('/')) {
375
+ await handleDebugCommand(input, engine, context, rl);
376
+ } else {
377
+ // Treat as error description or log
378
+ await handleDebugInput(input, engine, context);
379
+ }
380
+
381
+ rl.prompt();
382
+ });
383
+
384
+ rl.on('close', () => {
385
+ console.log(chalk.cyan('\n👋 Debug session ended.\n'));
386
+ process.exit(0);
387
+ });
388
+ }
389
+
390
+ /**
391
+ * Handle debug commands (/scan, /fix, etc.)
392
+ */
393
+ async function handleDebugCommand(cmd, engine, context, rl) {
394
+ const command = cmd.toLowerCase().split(' ')[0];
395
+
396
+ switch (command) {
397
+ case '/scan':
398
+ console.log(chalk.blue('\n🔍 Scanning project for errors...\n'));
399
+ try {
400
+ const result = await engine.debug({ auto: true });
401
+ context.lastAnalysis = result;
402
+ context.lastEvidence = result.evidence;
403
+
404
+ if (result.status === 'resolved') {
405
+ console.log(chalk.green('\n✅ All errors resolved!'));
406
+ } else if (result.status === 'no_error') {
407
+ console.log(chalk.green('\n✅ No errors found!'));
408
+ } else {
409
+ console.log(chalk.yellow('\n⚠️ Some issues found. Use /fix to apply fixes.'));
410
+ }
411
+ } catch (error) {
412
+ console.log(chalk.red(`\nScan error: ${error.message}`));
413
+ }
414
+ break;
415
+
416
+ case '/fix':
417
+ if (context.lastAnalysis && context.lastAnalysis.fixPrompt) {
418
+ console.log(chalk.blue('\n🔧 Applying fix...\n'));
419
+ try {
420
+ const fixResult = await engine.applyFix(context.lastAnalysis.fixPrompt);
421
+ if (fixResult.success) {
422
+ console.log(chalk.green('\n✅ Fix applied! Run /scan to verify.'));
423
+ } else {
424
+ console.log(chalk.yellow(`\n⚠️ Fix may have issues: ${fixResult.error || 'Check output above'}`));
425
+ }
426
+ } catch (error) {
427
+ console.log(chalk.red(`\nFix error: ${error.message}`));
428
+ }
429
+ } else if (context.errors.length > 0) {
430
+ // Try to generate fix from accumulated context
431
+ console.log(chalk.blue('\n🔧 Generating fix from context...\n'));
432
+ try {
433
+ const result = await engine.debug({ description: context.errors.join('\n\n') });
434
+ context.lastAnalysis = result;
435
+ } catch (error) {
436
+ console.log(chalk.red(`\nError: ${error.message}`));
437
+ }
438
+ } else {
439
+ console.log(chalk.yellow('\nNo analysis to fix. Run /scan or describe an error first.'));
440
+ }
441
+ break;
442
+
443
+ case '/retry':
444
+ if (context.errors.length > 0) {
445
+ console.log(chalk.blue('\n🔄 Retrying with accumulated context...\n'));
446
+ try {
447
+ const result = await engine.debug({ description: context.errors.join('\n\n') });
448
+ context.lastAnalysis = result;
449
+ } catch (error) {
450
+ console.log(chalk.red(`\nRetry error: ${error.message}`));
451
+ }
452
+ } else {
453
+ console.log(chalk.yellow('\nNo context to retry with. Describe an error first.'));
454
+ }
455
+ break;
456
+
457
+ case '/clear':
458
+ context.errors = [];
459
+ context.lastAnalysis = null;
460
+ context.lastFix = null;
461
+ context.lastEvidence = null;
462
+ console.log(chalk.green('\n✓ Context cleared.\n'));
463
+ break;
464
+
465
+ case '/context':
466
+ console.log(chalk.cyan('\n📋 Current Context:'));
467
+ console.log(chalk.gray(` Errors collected: ${context.errors.length}`));
468
+ console.log(chalk.gray(` Last analysis: ${context.lastAnalysis ? 'Yes' : 'No'}`));
469
+ if (context.errors.length > 0) {
470
+ console.log(chalk.gray('\n Recent errors:'));
471
+ context.errors.slice(-3).forEach((e, i) => {
472
+ console.log(chalk.gray(` ${i + 1}. ${e.substring(0, 60)}${e.length > 60 ? '...' : ''}`));
473
+ });
474
+ }
475
+ console.log();
476
+ break;
477
+
478
+ case '/help':
479
+ console.log(chalk.cyan(`
480
+ Commands:
481
+ /scan Auto-scan project for errors
482
+ /fix Apply last suggested fix
483
+ /retry Retry with accumulated context
484
+ /clear Clear all context
485
+ /context Show current context
486
+ /help Show this help
487
+ /quit Exit debug mode
488
+
489
+ Tips:
490
+ • Paste error messages directly for analysis
491
+ • Describe what's wrong in plain English
492
+ • Use /scan for automatic error detection
493
+ • Context accumulates - use /clear to reset
494
+ `));
495
+ break;
496
+
497
+ case '/quit':
498
+ case '/exit':
499
+ case '/q':
500
+ rl.close();
501
+ break;
502
+
503
+ default:
504
+ console.log(chalk.yellow(`\nUnknown command: ${cmd}`));
505
+ console.log(chalk.gray('Type /help for available commands.\n'));
506
+ }
507
+ }
508
+
509
+ /**
510
+ * Handle user input (error description or log)
511
+ */
512
+ async function handleDebugInput(input, engine, context) {
513
+ // Add to context
514
+ context.errors.push(input);
515
+
516
+ // Show spinner
517
+ const spinner = ora('Analyzing error...').start();
518
+
519
+ try {
520
+ const result = await engine.debug({ description: input });
521
+ context.lastAnalysis = result;
522
+
523
+ spinner.stop();
524
+
525
+ if (result.status === 'resolved') {
526
+ console.log(chalk.green('\n✅ Error analyzed and fixed!\n'));
527
+ } else if (result.status === 'no_error') {
528
+ console.log(chalk.green('\n✅ No actionable error found.\n'));
529
+ } else {
530
+ console.log(chalk.yellow('\n⚠️ Analysis complete. Use /fix to apply suggested fix.\n'));
531
+
532
+ // Show brief analysis
533
+ if (result.session && result.session.steps > 0) {
534
+ console.log(chalk.gray(` Steps completed: ${result.session.steps}`));
535
+ console.log(chalk.gray(` Attempts: ${result.session.attempts}`));
536
+ }
537
+ }
538
+ } catch (error) {
539
+ spinner.stop();
540
+ console.log(chalk.red(`\nAnalysis error: ${error.message}\n`));
541
+ }
542
+ }
543
+
544
+ /**
545
+ * Interactive log paste mode (for future enhancement)
546
+ */
547
+ async function interactiveLogMode() {
548
+ console.log(chalk.cyan('Paste your error log below (end with Ctrl+D):'));
549
+ console.log(chalk.gray('---'));
550
+
551
+ let logContent = '';
552
+
553
+ process.stdin.setEncoding('utf8');
554
+
555
+ return new Promise((resolve) => {
556
+ process.stdin.on('data', (chunk) => {
557
+ logContent += chunk;
558
+ });
559
+
560
+ process.stdin.on('end', () => {
561
+ console.log(chalk.gray('---'));
562
+ resolve(logContent.trim());
563
+ });
564
+ });
565
+ }