@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,348 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
2
|
+
// VIBECODE DEBUG - Fix Generator
|
|
3
|
+
// Generates fix prompts and documents applied fixes
|
|
4
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
5
|
+
|
|
6
|
+
import fs from 'fs-extra';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Fix Generator Class
|
|
11
|
+
* Creates targeted fix prompts and maintains fix documentation
|
|
12
|
+
*/
|
|
13
|
+
export class FixGenerator {
|
|
14
|
+
constructor(projectPath) {
|
|
15
|
+
this.projectPath = projectPath;
|
|
16
|
+
this.debugDir = path.join(projectPath, '.vibecode', 'debug');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Generate a fix prompt for Claude Code
|
|
21
|
+
*/
|
|
22
|
+
generateFixPrompt(evidence, hypothesis) {
|
|
23
|
+
const parts = [];
|
|
24
|
+
|
|
25
|
+
// Header with context
|
|
26
|
+
parts.push('# Debug Fix Request');
|
|
27
|
+
parts.push('');
|
|
28
|
+
parts.push('## Error Information');
|
|
29
|
+
parts.push(`- **Type**: ${evidence.type || 'Unknown'}`);
|
|
30
|
+
parts.push(`- **Category**: ${evidence.category}`);
|
|
31
|
+
|
|
32
|
+
if (evidence.message) {
|
|
33
|
+
parts.push(`- **Message**: ${evidence.message}`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Files involved
|
|
37
|
+
if (evidence.files.length > 0) {
|
|
38
|
+
parts.push('');
|
|
39
|
+
parts.push('## Affected Files');
|
|
40
|
+
for (const file of evidence.files.slice(0, 5)) {
|
|
41
|
+
parts.push(`- ${file}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Line numbers
|
|
46
|
+
if (evidence.lines.length > 0) {
|
|
47
|
+
parts.push('');
|
|
48
|
+
parts.push('## Line Numbers');
|
|
49
|
+
parts.push(`Lines: ${evidence.lines.slice(0, 10).join(', ')}`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Stack trace (condensed)
|
|
53
|
+
if (evidence.stackTrace.length > 0) {
|
|
54
|
+
parts.push('');
|
|
55
|
+
parts.push('## Stack Trace (top 5 frames)');
|
|
56
|
+
parts.push('```');
|
|
57
|
+
for (const line of evidence.stackTrace.slice(0, 5)) {
|
|
58
|
+
parts.push(line);
|
|
59
|
+
}
|
|
60
|
+
parts.push('```');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Hypothesis and fix
|
|
64
|
+
parts.push('');
|
|
65
|
+
parts.push('## Diagnosis');
|
|
66
|
+
parts.push(`**Root Cause**: ${hypothesis.rootCause}`);
|
|
67
|
+
parts.push('');
|
|
68
|
+
parts.push(`**Suggested Fix**: ${hypothesis.description}`);
|
|
69
|
+
parts.push(`**Confidence**: ${Math.round(hypothesis.confidence * 100)}%`);
|
|
70
|
+
|
|
71
|
+
// Category-specific instructions
|
|
72
|
+
parts.push('');
|
|
73
|
+
parts.push('## Fix Instructions');
|
|
74
|
+
parts.push(this.getCategoryInstructions(evidence.category, evidence));
|
|
75
|
+
|
|
76
|
+
// Verification requirement
|
|
77
|
+
parts.push('');
|
|
78
|
+
parts.push('## Verification');
|
|
79
|
+
parts.push('After fixing, ensure:');
|
|
80
|
+
parts.push('1. The original error no longer occurs');
|
|
81
|
+
parts.push('2. No new errors are introduced');
|
|
82
|
+
parts.push('3. Related tests pass (if applicable)');
|
|
83
|
+
|
|
84
|
+
return parts.join('\n');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Get category-specific fix instructions
|
|
89
|
+
*/
|
|
90
|
+
getCategoryInstructions(category, evidence) {
|
|
91
|
+
const instructions = {
|
|
92
|
+
SYNTAX: `
|
|
93
|
+
1. Navigate to the file(s) with syntax errors
|
|
94
|
+
2. Check the indicated line numbers for:
|
|
95
|
+
- Missing or extra brackets, parentheses, braces
|
|
96
|
+
- Missing semicolons or commas
|
|
97
|
+
- Incorrect JSX syntax (unclosed tags, invalid expressions)
|
|
98
|
+
3. Fix the syntax errors
|
|
99
|
+
4. Run the linter/compiler to verify`,
|
|
100
|
+
|
|
101
|
+
TYPE: `
|
|
102
|
+
1. Locate the code accessing ${evidence.message?.match(/property '(\w+)'/)?.[1] || 'the property'}
|
|
103
|
+
2. Add null/undefined check before access:
|
|
104
|
+
- Use optional chaining: \`obj?.property\`
|
|
105
|
+
- Or guard clause: \`if (obj) { ... }\`
|
|
106
|
+
3. Consider why the value might be undefined:
|
|
107
|
+
- Is data not loaded yet?
|
|
108
|
+
- Is there a race condition?
|
|
109
|
+
- Is the property name correct?`,
|
|
110
|
+
|
|
111
|
+
REFERENCE: `
|
|
112
|
+
1. Find where the undefined variable is used
|
|
113
|
+
2. Either:
|
|
114
|
+
- Import it from the correct module
|
|
115
|
+
- Define it before use
|
|
116
|
+
- Check for typos in the variable name
|
|
117
|
+
3. If it's a function/class, ensure it's exported from the source`,
|
|
118
|
+
|
|
119
|
+
IMPORT: `
|
|
120
|
+
1. Check if the module/package exists:
|
|
121
|
+
- For npm packages: \`npm install <package>\`
|
|
122
|
+
- For local files: verify the path is correct
|
|
123
|
+
2. If the export doesn't exist:
|
|
124
|
+
- Check the source module for available exports
|
|
125
|
+
- Use default vs named import correctly
|
|
126
|
+
3. Verify the file extension if needed`,
|
|
127
|
+
|
|
128
|
+
FILE: `
|
|
129
|
+
1. Check if the referenced file/directory exists
|
|
130
|
+
2. Either:
|
|
131
|
+
- Create the missing file/directory
|
|
132
|
+
- Fix the path in the code/config
|
|
133
|
+
3. Verify permissions if needed`,
|
|
134
|
+
|
|
135
|
+
LINT: `
|
|
136
|
+
1. Review the specific linting rule violation
|
|
137
|
+
2. Either:
|
|
138
|
+
- Fix the code to comply with the rule
|
|
139
|
+
- Add eslint-disable comment if intentional (with explanation)
|
|
140
|
+
3. Consider if the rule should be configured differently`,
|
|
141
|
+
|
|
142
|
+
TEST: `
|
|
143
|
+
1. Review the failing test assertion
|
|
144
|
+
2. Determine if:
|
|
145
|
+
- The test expectation is wrong (update test)
|
|
146
|
+
- The implementation is wrong (fix code)
|
|
147
|
+
- The test is testing the wrong thing
|
|
148
|
+
3. Ensure the fix doesn't break other tests`,
|
|
149
|
+
|
|
150
|
+
NEXTJS: `
|
|
151
|
+
1. Identify the Server/Client Component boundary issue
|
|
152
|
+
2. Common fixes:
|
|
153
|
+
- Don't pass functions as props to Client Components
|
|
154
|
+
- Use "use client" directive where needed
|
|
155
|
+
- Move client-only code to useEffect
|
|
156
|
+
- Use serializable props (strings, numbers, objects)
|
|
157
|
+
3. Check if component should be client or server`,
|
|
158
|
+
|
|
159
|
+
DATABASE: `
|
|
160
|
+
1. For Prisma issues:
|
|
161
|
+
- Run: \`npx prisma generate\`
|
|
162
|
+
- Run: \`npx prisma db push\` or \`npx prisma migrate dev\`
|
|
163
|
+
2. Check DATABASE_URL in .env
|
|
164
|
+
3. Verify database connection and permissions
|
|
165
|
+
4. Check schema matches database state`,
|
|
166
|
+
|
|
167
|
+
RUNTIME: `
|
|
168
|
+
1. Add console.log statements to trace the issue
|
|
169
|
+
2. Check the error stack trace for the source
|
|
170
|
+
3. Look for:
|
|
171
|
+
- Async/await issues
|
|
172
|
+
- State management bugs
|
|
173
|
+
- Race conditions
|
|
174
|
+
4. Use debugger breakpoints if available`
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
return instructions[category] || `
|
|
178
|
+
1. Review the error message and stack trace
|
|
179
|
+
2. Locate the source of the error
|
|
180
|
+
3. Apply the suggested fix
|
|
181
|
+
4. Test to verify the fix works`;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Document a fix in the debug log
|
|
186
|
+
*/
|
|
187
|
+
async documentFix(fixInfo) {
|
|
188
|
+
await fs.ensureDir(this.debugDir);
|
|
189
|
+
|
|
190
|
+
const fixesFile = path.join(this.debugDir, 'fixes.md');
|
|
191
|
+
const timestamp = new Date().toISOString();
|
|
192
|
+
|
|
193
|
+
const entry = `
|
|
194
|
+
## Fix Applied - ${timestamp}
|
|
195
|
+
|
|
196
|
+
**Error Type**: ${fixInfo.errorType || 'Unknown'}
|
|
197
|
+
**Category**: ${fixInfo.category}
|
|
198
|
+
**Confidence**: ${Math.round((fixInfo.confidence || 0) * 100)}%
|
|
199
|
+
|
|
200
|
+
### Root Cause
|
|
201
|
+
${fixInfo.rootCause || 'Not determined'}
|
|
202
|
+
|
|
203
|
+
### Fix Applied
|
|
204
|
+
${fixInfo.description || 'Manual fix'}
|
|
205
|
+
|
|
206
|
+
### Files Modified
|
|
207
|
+
${(fixInfo.files || []).map(f => `- ${f}`).join('\n') || '- Unknown'}
|
|
208
|
+
|
|
209
|
+
### Verification
|
|
210
|
+
- Status: ${fixInfo.verified ? '✅ Verified' : '⏳ Pending verification'}
|
|
211
|
+
${fixInfo.verificationOutput ? `- Output: ${fixInfo.verificationOutput}` : ''}
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
`;
|
|
215
|
+
|
|
216
|
+
// Append to fixes log
|
|
217
|
+
let content = '';
|
|
218
|
+
if (await fs.pathExists(fixesFile)) {
|
|
219
|
+
content = await fs.readFile(fixesFile, 'utf-8');
|
|
220
|
+
} else {
|
|
221
|
+
content = `# Vibecode Debug - Fix History
|
|
222
|
+
|
|
223
|
+
This file tracks all fixes applied through the Vibecode debug system.
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
`;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
await fs.writeFile(fixesFile, content + entry);
|
|
230
|
+
return fixesFile;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Update CLAUDE.md with prevention rules
|
|
235
|
+
*/
|
|
236
|
+
async updateClaudeMd(fix) {
|
|
237
|
+
const claudeMdPath = path.join(this.projectPath, 'CLAUDE.md');
|
|
238
|
+
let content = '';
|
|
239
|
+
|
|
240
|
+
if (await fs.pathExists(claudeMdPath)) {
|
|
241
|
+
content = await fs.readFile(claudeMdPath, 'utf-8');
|
|
242
|
+
} else {
|
|
243
|
+
content = `# CLAUDE.md - Project Guidelines
|
|
244
|
+
|
|
245
|
+
This file contains project-specific guidelines and lessons learned.
|
|
246
|
+
|
|
247
|
+
`;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Check if we already have a debugging section
|
|
251
|
+
const debugSection = '## Debugging History & Prevention';
|
|
252
|
+
if (!content.includes(debugSection)) {
|
|
253
|
+
content += `\n${debugSection}\n\n`;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Generate prevention rule
|
|
257
|
+
const preventionRule = this.generatePreventionRule(fix);
|
|
258
|
+
|
|
259
|
+
// Add to the debugging section
|
|
260
|
+
const sectionIndex = content.indexOf(debugSection);
|
|
261
|
+
const insertPoint = content.indexOf('\n\n', sectionIndex + debugSection.length);
|
|
262
|
+
|
|
263
|
+
if (insertPoint !== -1) {
|
|
264
|
+
content = content.slice(0, insertPoint) +
|
|
265
|
+
'\n' + preventionRule +
|
|
266
|
+
content.slice(insertPoint);
|
|
267
|
+
} else {
|
|
268
|
+
content += preventionRule + '\n';
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
await fs.writeFile(claudeMdPath, content);
|
|
272
|
+
return claudeMdPath;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Generate a prevention rule from a fix
|
|
277
|
+
*/
|
|
278
|
+
generatePreventionRule(fix) {
|
|
279
|
+
const rules = {
|
|
280
|
+
SYNTAX: `- ⚠️ Check syntax carefully: ${fix.message || 'brackets, semicolons, JSX tags'}`,
|
|
281
|
+
TYPE: `- ⚠️ Always use optional chaining (?.) when accessing: ${fix.files?.[0] || 'nested properties'}`,
|
|
282
|
+
REFERENCE: `- ⚠️ Ensure imports exist before using: ${fix.message?.match(/'(\w+)'/)?.[1] || 'variables'}`,
|
|
283
|
+
IMPORT: `- ⚠️ Verify module paths and exports: ${fix.files?.[0] || 'check imports'}`,
|
|
284
|
+
NEXTJS: `- ⚠️ Never pass functions to Client Components - use formatType strings instead`,
|
|
285
|
+
DATABASE: `- ⚠️ Run prisma generate after schema changes`,
|
|
286
|
+
TEST: `- ⚠️ Keep tests in sync with implementation`,
|
|
287
|
+
LINT: `- ⚠️ Follow linting rules: ${fix.message || 'check ESLint config'}`,
|
|
288
|
+
FILE: `- ⚠️ Verify file paths before referencing`,
|
|
289
|
+
RUNTIME: `- ⚠️ Handle edge cases: ${fix.rootCause || 'check for null/undefined'}`
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
const timestamp = new Date().toISOString().split('T')[0];
|
|
293
|
+
const rule = rules[fix.category] || `- ⚠️ Avoid: ${fix.rootCause || fix.description}`;
|
|
294
|
+
|
|
295
|
+
return `### [${timestamp}] ${fix.category} Fix
|
|
296
|
+
${rule}
|
|
297
|
+
`;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Generate a minimal fix prompt (for auto-fix mode)
|
|
302
|
+
*/
|
|
303
|
+
generateMinimalPrompt(evidence, hypothesis) {
|
|
304
|
+
const parts = [
|
|
305
|
+
`Fix this ${evidence.category} error:`,
|
|
306
|
+
'',
|
|
307
|
+
`Error: ${evidence.message || evidence.description}`,
|
|
308
|
+
''
|
|
309
|
+
];
|
|
310
|
+
|
|
311
|
+
if (evidence.files.length > 0) {
|
|
312
|
+
parts.push(`File: ${evidence.files[0]}`);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (evidence.lines.length > 0) {
|
|
316
|
+
parts.push(`Line: ${evidence.lines[0]}`);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
parts.push('');
|
|
320
|
+
parts.push(`Fix: ${hypothesis.description}`);
|
|
321
|
+
|
|
322
|
+
return parts.join('\n');
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Create a fix attempt record
|
|
327
|
+
*/
|
|
328
|
+
createFixAttempt(evidence, hypothesis) {
|
|
329
|
+
return {
|
|
330
|
+
id: `fix-${Date.now()}`,
|
|
331
|
+
timestamp: new Date().toISOString(),
|
|
332
|
+
errorType: evidence.type,
|
|
333
|
+
category: evidence.category,
|
|
334
|
+
message: evidence.message,
|
|
335
|
+
files: evidence.files,
|
|
336
|
+
lines: evidence.lines,
|
|
337
|
+
rootCause: hypothesis.rootCause,
|
|
338
|
+
description: hypothesis.description,
|
|
339
|
+
confidence: hypothesis.confidence,
|
|
340
|
+
status: 'pending',
|
|
341
|
+
verified: false
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
export function createFixGenerator(projectPath) {
|
|
347
|
+
return new FixGenerator(projectPath);
|
|
348
|
+
}
|