@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.
@@ -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