@nclamvn/vibecode-cli 1.3.0 → 1.5.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,37 @@ 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
+ // Debug exports
33
+ export {
34
+ DebugEngine,
35
+ createDebugEngine,
36
+ EvidenceCollector,
37
+ RootCauseAnalyzer,
38
+ FixGenerator,
39
+ FixVerifier
40
+ } from './debug/index.js';
41
+
42
+ // Agent exports
43
+ export {
44
+ VibecodeAgent,
45
+ createAgent,
46
+ agentBuild,
47
+ DecompositionEngine,
48
+ MemoryEngine,
49
+ SelfHealingEngine,
50
+ Orchestrator
51
+ } from './agent/index.js';
52
+
22
53
  // Constants
23
54
  export { VERSION, SPEC_HASH, STATES } from './config/constants.js';
24
55