@nclamvn/vibecode-cli 1.3.0 → 1.6.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.
- package/.vibecode/learning/fixes.json +1 -0
- package/.vibecode/learning/preferences.json +1 -0
- package/README.md +310 -49
- package/bin/vibecode.js +103 -2
- package/package.json +4 -2
- package/src/agent/decomposition.js +476 -0
- package/src/agent/index.js +325 -0
- package/src/agent/memory.js +542 -0
- package/src/agent/orchestrator.js +713 -0
- package/src/agent/self-healing.js +516 -0
- package/src/commands/agent.js +255 -0
- package/src/commands/assist.js +413 -0
- package/src/commands/build.js +13 -3
- package/src/commands/debug.js +457 -0
- package/src/commands/go.js +387 -0
- package/src/commands/learn.js +294 -0
- package/src/commands/undo.js +281 -0
- package/src/commands/wizard.js +322 -0
- package/src/core/backup.js +325 -0
- package/src/core/learning.js +295 -0
- package/src/core/test-runner.js +38 -5
- package/src/debug/analyzer.js +329 -0
- package/src/debug/evidence.js +228 -0
- package/src/debug/fixer.js +348 -0
- package/src/debug/index.js +378 -0
- package/src/debug/verifier.js +346 -0
- package/src/index.js +62 -0
- package/src/ui/__tests__/error-translator.test.js +390 -0
- package/src/ui/dashboard.js +364 -0
- package/src/ui/error-translator.js +775 -0
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
2
|
+
// VIBECODE DEBUG - Main Debug Engine
|
|
3
|
+
// Orchestrates the 9-step intelligent debugging workflow
|
|
4
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
5
|
+
//
|
|
6
|
+
// The 9-Step Debug Protocol:
|
|
7
|
+
// 1. EVIDENCE - Gather error information
|
|
8
|
+
// 2. REPRODUCE - Confirm the error exists
|
|
9
|
+
// 3. ANALYZE - Identify root cause
|
|
10
|
+
// 4. HYPOTHESIZE - Generate fix hypotheses
|
|
11
|
+
// 5. TEST - Test hypothesis validity
|
|
12
|
+
// 6. FIX - Apply the fix via Claude Code
|
|
13
|
+
// 7. VERIFY - Confirm the fix works
|
|
14
|
+
// 8. DOCUMENT - Log the fix for future reference
|
|
15
|
+
// 9. PREVENT - Add prevention rules to CLAUDE.md
|
|
16
|
+
//
|
|
17
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
18
|
+
|
|
19
|
+
import { exec } from 'child_process';
|
|
20
|
+
import { promisify } from 'util';
|
|
21
|
+
import fs from 'fs-extra';
|
|
22
|
+
import path from 'path';
|
|
23
|
+
import chalk from 'chalk';
|
|
24
|
+
|
|
25
|
+
import { EvidenceCollector } from './evidence.js';
|
|
26
|
+
import { RootCauseAnalyzer } from './analyzer.js';
|
|
27
|
+
import { FixGenerator } from './fixer.js';
|
|
28
|
+
import { FixVerifier } from './verifier.js';
|
|
29
|
+
import { spawnClaudeCode, isClaudeCodeAvailable } from '../providers/index.js';
|
|
30
|
+
import { translateError, formatTranslatedError } from '../ui/error-translator.js';
|
|
31
|
+
import { getLearningEngine } from '../core/learning.js';
|
|
32
|
+
import { askFeedback, showLearningSuggestion } from '../commands/learn.js';
|
|
33
|
+
|
|
34
|
+
const execAsync = promisify(exec);
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Debug Engine Class
|
|
38
|
+
* Main orchestrator for the debugging workflow
|
|
39
|
+
*/
|
|
40
|
+
export class DebugEngine {
|
|
41
|
+
constructor(projectPath, options = {}) {
|
|
42
|
+
this.projectPath = projectPath;
|
|
43
|
+
this.options = {
|
|
44
|
+
autoFix: options.autoFix || false,
|
|
45
|
+
maxAttempts: options.maxAttempts || 3,
|
|
46
|
+
verbose: options.verbose || false,
|
|
47
|
+
interactive: options.interactive !== false,
|
|
48
|
+
...options
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// Initialize components
|
|
52
|
+
this.evidence = new EvidenceCollector(projectPath);
|
|
53
|
+
this.analyzer = new RootCauseAnalyzer();
|
|
54
|
+
this.fixer = new FixGenerator(projectPath);
|
|
55
|
+
this.verifier = new FixVerifier(projectPath);
|
|
56
|
+
|
|
57
|
+
// Debug session state
|
|
58
|
+
this.session = {
|
|
59
|
+
id: `debug-${Date.now()}`,
|
|
60
|
+
startTime: new Date().toISOString(),
|
|
61
|
+
steps: [],
|
|
62
|
+
attempts: 0,
|
|
63
|
+
resolved: false
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Run the full debug workflow
|
|
69
|
+
*/
|
|
70
|
+
async debug(input) {
|
|
71
|
+
console.log(chalk.cyan.bold('\n🔍 VIBECODE DEBUG - Intelligent Bug Fixing\n'));
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
// Step 1: EVIDENCE - Gather error information
|
|
75
|
+
this.logStep(1, 'EVIDENCE', 'Gathering error information...');
|
|
76
|
+
const evidence = await this.evidence.collect(input);
|
|
77
|
+
this.session.steps.push({ step: 'EVIDENCE', data: evidence });
|
|
78
|
+
this.logEvidence(evidence);
|
|
79
|
+
|
|
80
|
+
// Step 2: REPRODUCE - Confirm error exists (if auto mode)
|
|
81
|
+
if (input.auto) {
|
|
82
|
+
this.logStep(2, 'REPRODUCE', 'Confirming error exists...');
|
|
83
|
+
const reproduced = await this.reproduce(evidence);
|
|
84
|
+
this.session.steps.push({ step: 'REPRODUCE', data: reproduced });
|
|
85
|
+
|
|
86
|
+
if (!reproduced.errorFound) {
|
|
87
|
+
console.log(chalk.green(' ✓ No errors found during reproduction check'));
|
|
88
|
+
return this.createResult('no_error', 'No errors found to fix');
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Step 3: ANALYZE - Identify root cause
|
|
93
|
+
this.logStep(3, 'ANALYZE', 'Analyzing root cause...');
|
|
94
|
+
const analysis = await this.analyzer.analyze(evidence);
|
|
95
|
+
this.session.steps.push({ step: 'ANALYZE', data: analysis });
|
|
96
|
+
this.logAnalysis(analysis);
|
|
97
|
+
|
|
98
|
+
// Step 4: HYPOTHESIZE - Generate fix hypotheses
|
|
99
|
+
this.logStep(4, 'HYPOTHESIZE', 'Generating fix hypotheses...');
|
|
100
|
+
const hypotheses = this.analyzer.buildHypotheses(analysis);
|
|
101
|
+
this.session.steps.push({ step: 'HYPOTHESIZE', data: hypotheses });
|
|
102
|
+
this.logHypotheses(hypotheses);
|
|
103
|
+
|
|
104
|
+
if (hypotheses.length === 0) {
|
|
105
|
+
console.log(chalk.yellow(' ⚠ No fix hypotheses generated'));
|
|
106
|
+
return this.createResult('no_hypothesis', 'Could not generate fix hypotheses');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Check for learning-based suggestions
|
|
110
|
+
await showLearningSuggestion(evidence.type, evidence.category);
|
|
111
|
+
|
|
112
|
+
// Step 5-7: TEST, FIX, VERIFY - Attempt fixes
|
|
113
|
+
let fixResult = null;
|
|
114
|
+
for (let attempt = 0; attempt < this.options.maxAttempts && !this.session.resolved; attempt++) {
|
|
115
|
+
this.session.attempts = attempt + 1;
|
|
116
|
+
|
|
117
|
+
const hypothesis = hypotheses[attempt % hypotheses.length];
|
|
118
|
+
console.log(chalk.cyan(`\n Attempt ${attempt + 1}/${this.options.maxAttempts}:`));
|
|
119
|
+
|
|
120
|
+
// Step 5: TEST - Generate fix prompt
|
|
121
|
+
this.logStep(5, 'TEST', 'Preparing fix...');
|
|
122
|
+
const fixPrompt = this.fixer.generateFixPrompt(evidence, hypothesis);
|
|
123
|
+
const fixAttempt = this.fixer.createFixAttempt(evidence, hypothesis);
|
|
124
|
+
|
|
125
|
+
// Step 6: FIX - Apply fix via Claude Code
|
|
126
|
+
this.logStep(6, 'FIX', 'Applying fix via Claude Code...');
|
|
127
|
+
fixResult = await this.applyFix(fixPrompt);
|
|
128
|
+
fixAttempt.status = fixResult.success ? 'applied' : 'failed';
|
|
129
|
+
|
|
130
|
+
if (!fixResult.success) {
|
|
131
|
+
console.log(chalk.yellow(` ⚠ Fix application failed: ${fixResult.error}`));
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Step 7: VERIFY - Confirm fix works
|
|
136
|
+
this.logStep(7, 'VERIFY', 'Verifying fix...');
|
|
137
|
+
const verification = await this.verifier.verify(evidence, fixAttempt);
|
|
138
|
+
this.session.steps.push({ step: 'VERIFY', data: verification });
|
|
139
|
+
|
|
140
|
+
if (verification.passed) {
|
|
141
|
+
console.log(chalk.green(' ✓ Fix verified successfully!'));
|
|
142
|
+
this.session.resolved = true;
|
|
143
|
+
fixAttempt.verified = true;
|
|
144
|
+
|
|
145
|
+
// Step 8: DOCUMENT - Log the fix
|
|
146
|
+
this.logStep(8, 'DOCUMENT', 'Documenting fix...');
|
|
147
|
+
await this.fixer.documentFix(fixAttempt);
|
|
148
|
+
|
|
149
|
+
// Step 9: PREVENT - Add prevention rules
|
|
150
|
+
this.logStep(9, 'PREVENT', 'Adding prevention rules...');
|
|
151
|
+
await this.fixer.updateClaudeMd(fixAttempt);
|
|
152
|
+
|
|
153
|
+
console.log(chalk.green.bold('\n✅ Bug fixed and documented!\n'));
|
|
154
|
+
|
|
155
|
+
// Ask for feedback to improve future suggestions
|
|
156
|
+
if (this.options.interactive) {
|
|
157
|
+
await askFeedback({
|
|
158
|
+
errorType: evidence.type,
|
|
159
|
+
errorMessage: evidence.message,
|
|
160
|
+
errorCategory: evidence.category,
|
|
161
|
+
fixApplied: fixAttempt.description || hypothesis.description
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
} else {
|
|
165
|
+
console.log(chalk.yellow(' ⚠ Verification failed, trying next approach...'));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return this.createResult(
|
|
170
|
+
this.session.resolved ? 'resolved' : 'unresolved',
|
|
171
|
+
this.session.resolved ? 'Bug fixed successfully' : 'Could not resolve after max attempts',
|
|
172
|
+
fixResult
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
} catch (error) {
|
|
176
|
+
console.log(chalk.red(`\n❌ Debug error: ${error.message}\n`));
|
|
177
|
+
return this.createResult('error', error.message);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Quick debug mode - minimal interaction
|
|
183
|
+
*/
|
|
184
|
+
async quickDebug(description) {
|
|
185
|
+
return this.debug({
|
|
186
|
+
description,
|
|
187
|
+
auto: false
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Auto scan and fix mode
|
|
193
|
+
*/
|
|
194
|
+
async autoDebug() {
|
|
195
|
+
console.log(chalk.cyan('🔄 Auto-scanning project for errors...\n'));
|
|
196
|
+
|
|
197
|
+
return this.debug({
|
|
198
|
+
auto: true
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Reproduce the error to confirm it exists
|
|
204
|
+
*/
|
|
205
|
+
async reproduce(evidence) {
|
|
206
|
+
const result = {
|
|
207
|
+
errorFound: false,
|
|
208
|
+
output: ''
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
// Try to reproduce based on category
|
|
212
|
+
try {
|
|
213
|
+
const checks = {
|
|
214
|
+
SYNTAX: 'npx tsc --noEmit',
|
|
215
|
+
TYPE: 'npx tsc --noEmit',
|
|
216
|
+
IMPORT: 'npx tsc --noEmit',
|
|
217
|
+
BUILD: 'npm run build',
|
|
218
|
+
LINT: 'npm run lint',
|
|
219
|
+
TEST: 'npm test'
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
const command = checks[evidence.category] || 'npm run build';
|
|
223
|
+
|
|
224
|
+
await execAsync(command, {
|
|
225
|
+
cwd: this.projectPath,
|
|
226
|
+
timeout: 60000
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
result.output = 'Command succeeded';
|
|
230
|
+
} catch (error) {
|
|
231
|
+
result.errorFound = true;
|
|
232
|
+
result.output = error.stderr || error.stdout || error.message;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return result;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Apply a fix using Claude Code
|
|
240
|
+
*/
|
|
241
|
+
async applyFix(prompt) {
|
|
242
|
+
const result = {
|
|
243
|
+
success: false,
|
|
244
|
+
output: '',
|
|
245
|
+
error: null
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
try {
|
|
249
|
+
// Check if Claude Code is available
|
|
250
|
+
const available = await isClaudeCodeAvailable();
|
|
251
|
+
if (!available) {
|
|
252
|
+
throw new Error('Claude Code CLI not found. Install with: npm install -g @anthropic-ai/claude-code');
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Save prompt to debug folder for reference
|
|
256
|
+
const promptFile = path.join(this.projectPath, '.vibecode', 'debug', 'current-fix.md');
|
|
257
|
+
await fs.ensureDir(path.dirname(promptFile));
|
|
258
|
+
await fs.writeFile(promptFile, prompt);
|
|
259
|
+
|
|
260
|
+
if (this.options.verbose) {
|
|
261
|
+
console.log(chalk.gray(` Running Claude Code with fix prompt...`));
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Use spawnClaudeCode which handles temp file properly
|
|
265
|
+
const spawnResult = await spawnClaudeCode(prompt, {
|
|
266
|
+
cwd: this.projectPath
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
result.success = spawnResult.success;
|
|
270
|
+
result.output = `Exit code: ${spawnResult.code}`;
|
|
271
|
+
|
|
272
|
+
} catch (error) {
|
|
273
|
+
result.error = error.message;
|
|
274
|
+
result.output = '';
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return result;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Log a debug step
|
|
282
|
+
*/
|
|
283
|
+
logStep(number, name, message) {
|
|
284
|
+
const stepLabel = chalk.cyan(`[${number}/9 ${name}]`);
|
|
285
|
+
console.log(`${stepLabel} ${message}`);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Log evidence summary
|
|
290
|
+
*/
|
|
291
|
+
logEvidence(evidence) {
|
|
292
|
+
console.log(chalk.gray(` Type: ${evidence.type || 'Unknown'}`));
|
|
293
|
+
console.log(chalk.gray(` Category: ${evidence.category}`));
|
|
294
|
+
|
|
295
|
+
if (evidence.message) {
|
|
296
|
+
// Translate error for human-friendly display
|
|
297
|
+
const translated = translateError(evidence.message);
|
|
298
|
+
console.log(chalk.yellow(` Error: ${translated.title}`));
|
|
299
|
+
console.log(chalk.gray(` → ${translated.description.substring(0, 80)}${translated.description.length > 80 ? '...' : ''}`));
|
|
300
|
+
|
|
301
|
+
// Show suggestions
|
|
302
|
+
if (translated.suggestions && translated.suggestions.length > 0) {
|
|
303
|
+
console.log(chalk.gray(` Suggestions:`));
|
|
304
|
+
for (const s of translated.suggestions.slice(0, 2)) {
|
|
305
|
+
console.log(chalk.gray(` • ${s}`));
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (evidence.files.length > 0) {
|
|
311
|
+
console.log(chalk.gray(` Files: ${evidence.files.slice(0, 3).join(', ')}${evidence.files.length > 3 ? '...' : ''}`));
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Log analysis results
|
|
317
|
+
*/
|
|
318
|
+
logAnalysis(analysis) {
|
|
319
|
+
console.log(chalk.gray(` Root cause: ${analysis.rootCause || 'Unknown'}`));
|
|
320
|
+
console.log(chalk.gray(` Confidence: ${Math.round(analysis.confidence * 100)}%`));
|
|
321
|
+
if (analysis.patterns.length > 0) {
|
|
322
|
+
console.log(chalk.gray(` Patterns: ${analysis.patterns.join(', ')}`));
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Log hypotheses
|
|
328
|
+
*/
|
|
329
|
+
logHypotheses(hypotheses) {
|
|
330
|
+
console.log(chalk.gray(` Generated ${hypotheses.length} hypothesis(es):`));
|
|
331
|
+
for (const h of hypotheses.slice(0, 3)) {
|
|
332
|
+
console.log(chalk.gray(` - ${h.description.substring(0, 60)}... (${Math.round(h.confidence * 100)}%)`));
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Create result object
|
|
338
|
+
*/
|
|
339
|
+
createResult(status, message, fixResult = null) {
|
|
340
|
+
return {
|
|
341
|
+
status,
|
|
342
|
+
message,
|
|
343
|
+
session: {
|
|
344
|
+
id: this.session.id,
|
|
345
|
+
attempts: this.session.attempts,
|
|
346
|
+
resolved: this.session.resolved,
|
|
347
|
+
steps: this.session.steps.length
|
|
348
|
+
},
|
|
349
|
+
fixResult
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Get debug session summary
|
|
355
|
+
*/
|
|
356
|
+
getSessionSummary() {
|
|
357
|
+
return {
|
|
358
|
+
id: this.session.id,
|
|
359
|
+
startTime: this.session.startTime,
|
|
360
|
+
attempts: this.session.attempts,
|
|
361
|
+
resolved: this.session.resolved,
|
|
362
|
+
stepsCompleted: this.session.steps.map(s => s.step)
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Create a new debug engine instance
|
|
369
|
+
*/
|
|
370
|
+
export function createDebugEngine(projectPath, options = {}) {
|
|
371
|
+
return new DebugEngine(projectPath, options);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Re-export components
|
|
375
|
+
export { EvidenceCollector } from './evidence.js';
|
|
376
|
+
export { RootCauseAnalyzer } from './analyzer.js';
|
|
377
|
+
export { FixGenerator } from './fixer.js';
|
|
378
|
+
export { FixVerifier } from './verifier.js';
|