@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,346 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
2
|
+
// VIBECODE DEBUG - Fix Verifier
|
|
3
|
+
// Verifies that fixes resolve the original error
|
|
4
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
5
|
+
|
|
6
|
+
import { exec } from 'child_process';
|
|
7
|
+
import { promisify } from 'util';
|
|
8
|
+
import fs from 'fs-extra';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
|
|
11
|
+
const execAsync = promisify(exec);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Fix Verifier Class
|
|
15
|
+
* Re-runs failing commands/tests to verify fixes
|
|
16
|
+
*/
|
|
17
|
+
export class FixVerifier {
|
|
18
|
+
constructor(projectPath) {
|
|
19
|
+
this.projectPath = projectPath;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Verify a fix by re-running the original failing command
|
|
24
|
+
*/
|
|
25
|
+
async verify(originalError, fixAttempt) {
|
|
26
|
+
const verification = {
|
|
27
|
+
fixId: fixAttempt.id,
|
|
28
|
+
timestamp: new Date().toISOString(),
|
|
29
|
+
originalError: {
|
|
30
|
+
type: originalError.type,
|
|
31
|
+
category: originalError.category,
|
|
32
|
+
message: originalError.message
|
|
33
|
+
},
|
|
34
|
+
checks: [],
|
|
35
|
+
passed: false,
|
|
36
|
+
summary: ''
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// Determine which checks to run based on category
|
|
40
|
+
const checksToRun = this.getChecksForCategory(originalError.category);
|
|
41
|
+
|
|
42
|
+
for (const check of checksToRun) {
|
|
43
|
+
const result = await this.runCheck(check);
|
|
44
|
+
verification.checks.push(result);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Analyze results
|
|
48
|
+
verification.passed = this.analyzeResults(verification.checks, originalError);
|
|
49
|
+
verification.summary = this.generateSummary(verification);
|
|
50
|
+
|
|
51
|
+
return verification;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Get appropriate checks for error category
|
|
56
|
+
*/
|
|
57
|
+
getChecksForCategory(category) {
|
|
58
|
+
const categoryChecks = {
|
|
59
|
+
SYNTAX: ['tsc', 'build'],
|
|
60
|
+
TYPE: ['tsc', 'build'],
|
|
61
|
+
REFERENCE: ['tsc', 'build'],
|
|
62
|
+
IMPORT: ['tsc', 'build'],
|
|
63
|
+
LINT: ['lint'],
|
|
64
|
+
TEST: ['test'],
|
|
65
|
+
NEXTJS: ['build'],
|
|
66
|
+
DATABASE: ['prisma', 'build'],
|
|
67
|
+
FILE: ['build'],
|
|
68
|
+
RUNTIME: ['build', 'test']
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
return categoryChecks[category] || ['build'];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Run a specific verification check
|
|
76
|
+
*/
|
|
77
|
+
async runCheck(checkName) {
|
|
78
|
+
const result = {
|
|
79
|
+
name: checkName,
|
|
80
|
+
command: '',
|
|
81
|
+
passed: false,
|
|
82
|
+
output: '',
|
|
83
|
+
error: null,
|
|
84
|
+
duration: 0
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const commands = {
|
|
88
|
+
tsc: 'npx tsc --noEmit',
|
|
89
|
+
build: 'npm run build',
|
|
90
|
+
lint: 'npm run lint',
|
|
91
|
+
test: 'npm test',
|
|
92
|
+
prisma: 'npx prisma generate'
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
result.command = commands[checkName] || checkName;
|
|
96
|
+
|
|
97
|
+
// Check if command is available
|
|
98
|
+
if (checkName === 'lint' || checkName === 'test' || checkName === 'build') {
|
|
99
|
+
const pkgPath = path.join(this.projectPath, 'package.json');
|
|
100
|
+
if (await fs.pathExists(pkgPath)) {
|
|
101
|
+
const pkg = await fs.readJson(pkgPath);
|
|
102
|
+
const scriptName = checkName === 'build' ? 'build' : checkName;
|
|
103
|
+
if (!pkg.scripts?.[scriptName]) {
|
|
104
|
+
result.passed = true;
|
|
105
|
+
result.output = `Script "${scriptName}" not found, skipping`;
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const startTime = Date.now();
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
const { stdout, stderr } = await execAsync(result.command, {
|
|
115
|
+
cwd: this.projectPath,
|
|
116
|
+
timeout: 120000,
|
|
117
|
+
maxBuffer: 10 * 1024 * 1024
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
result.passed = true;
|
|
121
|
+
result.output = stdout || stderr || 'Success';
|
|
122
|
+
result.duration = Date.now() - startTime;
|
|
123
|
+
} catch (error) {
|
|
124
|
+
result.passed = false;
|
|
125
|
+
result.error = error.message;
|
|
126
|
+
result.output = error.stderr || error.stdout || error.message;
|
|
127
|
+
result.duration = Date.now() - startTime;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return result;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Compare before and after outputs
|
|
135
|
+
*/
|
|
136
|
+
compareOutput(before, after) {
|
|
137
|
+
const comparison = {
|
|
138
|
+
errorResolved: false,
|
|
139
|
+
newErrors: [],
|
|
140
|
+
improvements: [],
|
|
141
|
+
regressions: []
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
// Check if original error message is gone
|
|
145
|
+
const originalMessage = (before.message || '').toLowerCase();
|
|
146
|
+
const afterOutput = (after.output || '').toLowerCase();
|
|
147
|
+
|
|
148
|
+
if (originalMessage && !afterOutput.includes(originalMessage)) {
|
|
149
|
+
comparison.errorResolved = true;
|
|
150
|
+
comparison.improvements.push('Original error no longer appears');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Check for new errors
|
|
154
|
+
const errorPatterns = [
|
|
155
|
+
/error:/gi,
|
|
156
|
+
/failed/gi,
|
|
157
|
+
/exception/gi,
|
|
158
|
+
/cannot find/gi,
|
|
159
|
+
/undefined/gi
|
|
160
|
+
];
|
|
161
|
+
|
|
162
|
+
const beforeMatches = this.countPatternMatches(before.output || '', errorPatterns);
|
|
163
|
+
const afterMatches = this.countPatternMatches(after.output || '', errorPatterns);
|
|
164
|
+
|
|
165
|
+
if (afterMatches > beforeMatches) {
|
|
166
|
+
comparison.regressions.push(`Potential new errors detected (${afterMatches - beforeMatches} more error patterns)`);
|
|
167
|
+
} else if (afterMatches < beforeMatches) {
|
|
168
|
+
comparison.improvements.push(`Fewer error patterns (${beforeMatches - afterMatches} less)`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return comparison;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Count pattern matches in text
|
|
176
|
+
*/
|
|
177
|
+
countPatternMatches(text, patterns) {
|
|
178
|
+
let count = 0;
|
|
179
|
+
for (const pattern of patterns) {
|
|
180
|
+
const matches = text.match(pattern);
|
|
181
|
+
if (matches) count += matches.length;
|
|
182
|
+
}
|
|
183
|
+
return count;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Analyze check results to determine if fix was successful
|
|
188
|
+
*/
|
|
189
|
+
analyzeResults(checks, originalError) {
|
|
190
|
+
// All checks must pass
|
|
191
|
+
const allPassed = checks.every(c => c.passed);
|
|
192
|
+
|
|
193
|
+
if (!allPassed) {
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// For specific categories, verify the error type is resolved
|
|
198
|
+
const relevantCheck = checks.find(c => {
|
|
199
|
+
switch (originalError.category) {
|
|
200
|
+
case 'SYNTAX':
|
|
201
|
+
case 'TYPE':
|
|
202
|
+
case 'REFERENCE':
|
|
203
|
+
case 'IMPORT':
|
|
204
|
+
return c.name === 'tsc' || c.name === 'build';
|
|
205
|
+
case 'LINT':
|
|
206
|
+
return c.name === 'lint';
|
|
207
|
+
case 'TEST':
|
|
208
|
+
return c.name === 'test';
|
|
209
|
+
default:
|
|
210
|
+
return c.name === 'build';
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
if (relevantCheck && !relevantCheck.passed) {
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return true;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Generate verification summary
|
|
223
|
+
*/
|
|
224
|
+
generateSummary(verification) {
|
|
225
|
+
const passed = verification.checks.filter(c => c.passed);
|
|
226
|
+
const failed = verification.checks.filter(c => !c.passed);
|
|
227
|
+
|
|
228
|
+
if (verification.passed) {
|
|
229
|
+
return `✅ Fix verified! All ${passed.length} checks passed.`;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const failedNames = failed.map(c => c.name).join(', ');
|
|
233
|
+
return `❌ Fix verification failed. Failed checks: ${failedNames}`;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Generate a detailed verification report
|
|
238
|
+
*/
|
|
239
|
+
generateReport(verification) {
|
|
240
|
+
const lines = [
|
|
241
|
+
'# Fix Verification Report',
|
|
242
|
+
'',
|
|
243
|
+
`**Fix ID**: ${verification.fixId}`,
|
|
244
|
+
`**Timestamp**: ${verification.timestamp}`,
|
|
245
|
+
`**Status**: ${verification.passed ? '✅ PASSED' : '❌ FAILED'}`,
|
|
246
|
+
'',
|
|
247
|
+
'## Original Error',
|
|
248
|
+
`- Type: ${verification.originalError.type}`,
|
|
249
|
+
`- Category: ${verification.originalError.category}`,
|
|
250
|
+
`- Message: ${verification.originalError.message || 'N/A'}`,
|
|
251
|
+
'',
|
|
252
|
+
'## Verification Checks',
|
|
253
|
+
''
|
|
254
|
+
];
|
|
255
|
+
|
|
256
|
+
for (const check of verification.checks) {
|
|
257
|
+
lines.push(`### ${check.name}`);
|
|
258
|
+
lines.push(`- Command: \`${check.command}\``);
|
|
259
|
+
lines.push(`- Status: ${check.passed ? '✅ Passed' : '❌ Failed'}`);
|
|
260
|
+
lines.push(`- Duration: ${check.duration}ms`);
|
|
261
|
+
|
|
262
|
+
if (check.error) {
|
|
263
|
+
lines.push(`- Error: ${check.error.substring(0, 200)}`);
|
|
264
|
+
}
|
|
265
|
+
lines.push('');
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
lines.push('## Summary');
|
|
269
|
+
lines.push(verification.summary);
|
|
270
|
+
|
|
271
|
+
return lines.join('\n');
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Quick check if a specific command passes
|
|
276
|
+
*/
|
|
277
|
+
async quickCheck(command) {
|
|
278
|
+
try {
|
|
279
|
+
await execAsync(command, {
|
|
280
|
+
cwd: this.projectPath,
|
|
281
|
+
timeout: 60000,
|
|
282
|
+
maxBuffer: 5 * 1024 * 1024
|
|
283
|
+
});
|
|
284
|
+
return { passed: true, output: 'Success' };
|
|
285
|
+
} catch (error) {
|
|
286
|
+
return {
|
|
287
|
+
passed: false,
|
|
288
|
+
output: error.stderr || error.stdout || error.message
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Verify that the build succeeds
|
|
295
|
+
*/
|
|
296
|
+
async verifyBuild() {
|
|
297
|
+
return this.runCheck('build');
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Verify that TypeScript compiles
|
|
302
|
+
*/
|
|
303
|
+
async verifyTypeScript() {
|
|
304
|
+
return this.runCheck('tsc');
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Verify that tests pass
|
|
309
|
+
*/
|
|
310
|
+
async verifyTests() {
|
|
311
|
+
return this.runCheck('test');
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Verify that lint passes
|
|
316
|
+
*/
|
|
317
|
+
async verifyLint() {
|
|
318
|
+
return this.runCheck('lint');
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Run all standard verification checks
|
|
323
|
+
*/
|
|
324
|
+
async runAllChecks() {
|
|
325
|
+
const checks = ['tsc', 'lint', 'build', 'test'];
|
|
326
|
+
const results = [];
|
|
327
|
+
|
|
328
|
+
for (const check of checks) {
|
|
329
|
+
const result = await this.runCheck(check);
|
|
330
|
+
results.push(result);
|
|
331
|
+
|
|
332
|
+
// Stop on first failure for efficiency (optional)
|
|
333
|
+
// if (!result.passed) break;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
return {
|
|
337
|
+
checks: results,
|
|
338
|
+
allPassed: results.every(r => r.passed),
|
|
339
|
+
summary: results.map(r => `${r.name}: ${r.passed ? '✅' : '❌'}`).join(', ')
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
export function createFixVerifier(projectPath) {
|
|
345
|
+
return new FixVerifier(projectPath);
|
|
346
|
+
}
|
package/src/index.js
CHANGED
|
@@ -19,6 +19,68 @@ export { snapshotCommand } from './commands/snapshot.js';
|
|
|
19
19
|
// Phase C Commands
|
|
20
20
|
export { configCommand } from './commands/config.js';
|
|
21
21
|
|
|
22
|
+
// Phase E Commands - Magic Mode
|
|
23
|
+
export { goCommand } from './commands/go.js';
|
|
24
|
+
|
|
25
|
+
// Phase F Commands - Agent Mode
|
|
26
|
+
export { agentCommand } from './commands/agent.js';
|
|
27
|
+
|
|
28
|
+
// Phase G Commands - Debug Mode
|
|
29
|
+
export { debugCommand } from './commands/debug.js';
|
|
30
|
+
export { assistCommand } from './commands/assist.js';
|
|
31
|
+
|
|
32
|
+
// Phase H Commands - Smart Defaults
|
|
33
|
+
export { wizardCommand } from './commands/wizard.js';
|
|
34
|
+
|
|
35
|
+
// Phase H4 Commands - Undo/Rollback
|
|
36
|
+
export { undoCommand } from './commands/undo.js';
|
|
37
|
+
export { BackupManager, withBackup, createBackupManager } from './core/backup.js';
|
|
38
|
+
|
|
39
|
+
// Phase H5 Commands - Learning Mode
|
|
40
|
+
export { learnCommand } from './commands/learn.js';
|
|
41
|
+
export { askFeedback, showLearningSuggestion } from './commands/learn.js';
|
|
42
|
+
export { LearningEngine, getLearningEngine, createLearningEngine } from './core/learning.js';
|
|
43
|
+
|
|
44
|
+
// UI exports (Phase H2: Dashboard)
|
|
45
|
+
export {
|
|
46
|
+
ProgressDashboard,
|
|
47
|
+
StepProgress,
|
|
48
|
+
renderInlineProgress,
|
|
49
|
+
updateProgress,
|
|
50
|
+
completeProgress
|
|
51
|
+
} from './ui/dashboard.js';
|
|
52
|
+
|
|
53
|
+
// UI exports (Phase H3: Error Translator)
|
|
54
|
+
export {
|
|
55
|
+
translateError,
|
|
56
|
+
formatTranslatedError,
|
|
57
|
+
showError,
|
|
58
|
+
inlineError,
|
|
59
|
+
getErrorCategory,
|
|
60
|
+
isErrorCategory
|
|
61
|
+
} from './ui/error-translator.js';
|
|
62
|
+
|
|
63
|
+
// Debug exports
|
|
64
|
+
export {
|
|
65
|
+
DebugEngine,
|
|
66
|
+
createDebugEngine,
|
|
67
|
+
EvidenceCollector,
|
|
68
|
+
RootCauseAnalyzer,
|
|
69
|
+
FixGenerator,
|
|
70
|
+
FixVerifier
|
|
71
|
+
} from './debug/index.js';
|
|
72
|
+
|
|
73
|
+
// Agent exports
|
|
74
|
+
export {
|
|
75
|
+
VibecodeAgent,
|
|
76
|
+
createAgent,
|
|
77
|
+
agentBuild,
|
|
78
|
+
DecompositionEngine,
|
|
79
|
+
MemoryEngine,
|
|
80
|
+
SelfHealingEngine,
|
|
81
|
+
Orchestrator
|
|
82
|
+
} from './agent/index.js';
|
|
83
|
+
|
|
22
84
|
// Constants
|
|
23
85
|
export { VERSION, SPEC_HASH, STATES } from './config/constants.js';
|
|
24
86
|
|