@nclamvn/vibecode-cli 2.0.0 → 2.2.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.
Files changed (53) hide show
  1. package/.vibecode/learning/fixes.json +1 -0
  2. package/.vibecode/learning/preferences.json +1 -0
  3. package/README.md +310 -49
  4. package/SESSION_NOTES.md +154 -0
  5. package/bin/vibecode.js +235 -2
  6. package/package.json +5 -2
  7. package/src/agent/decomposition.js +476 -0
  8. package/src/agent/index.js +391 -0
  9. package/src/agent/memory.js +542 -0
  10. package/src/agent/orchestrator.js +917 -0
  11. package/src/agent/self-healing.js +516 -0
  12. package/src/commands/agent.js +349 -0
  13. package/src/commands/ask.js +230 -0
  14. package/src/commands/assist.js +413 -0
  15. package/src/commands/build.js +345 -4
  16. package/src/commands/debug.js +565 -0
  17. package/src/commands/docs.js +167 -0
  18. package/src/commands/git.js +1024 -0
  19. package/src/commands/go.js +635 -0
  20. package/src/commands/learn.js +294 -0
  21. package/src/commands/migrate.js +341 -0
  22. package/src/commands/plan.js +8 -2
  23. package/src/commands/refactor.js +205 -0
  24. package/src/commands/review.js +126 -1
  25. package/src/commands/security.js +229 -0
  26. package/src/commands/shell.js +486 -0
  27. package/src/commands/templates.js +397 -0
  28. package/src/commands/test.js +194 -0
  29. package/src/commands/undo.js +281 -0
  30. package/src/commands/watch.js +556 -0
  31. package/src/commands/wizard.js +322 -0
  32. package/src/config/constants.js +5 -1
  33. package/src/config/templates.js +146 -15
  34. package/src/core/backup.js +325 -0
  35. package/src/core/error-analyzer.js +237 -0
  36. package/src/core/fix-generator.js +195 -0
  37. package/src/core/iteration.js +226 -0
  38. package/src/core/learning.js +295 -0
  39. package/src/core/session.js +18 -2
  40. package/src/core/test-runner.js +281 -0
  41. package/src/debug/analyzer.js +329 -0
  42. package/src/debug/evidence.js +228 -0
  43. package/src/debug/fixer.js +348 -0
  44. package/src/debug/image-analyzer.js +304 -0
  45. package/src/debug/index.js +378 -0
  46. package/src/debug/verifier.js +346 -0
  47. package/src/index.js +102 -0
  48. package/src/providers/claude-code.js +12 -7
  49. package/src/templates/index.js +724 -0
  50. package/src/ui/__tests__/error-translator.test.js +390 -0
  51. package/src/ui/dashboard.js +364 -0
  52. package/src/ui/error-translator.js +775 -0
  53. package/src/utils/image.js +222 -0
@@ -0,0 +1,304 @@
1
+ /**
2
+ * Image Analyzer for Vibecode CLI
3
+ * Analyze screenshots of errors using AI vision
4
+ */
5
+
6
+ import chalk from 'chalk';
7
+ import fs from 'fs/promises';
8
+ import path from 'path';
9
+ import { spawn } from 'child_process';
10
+ import { imageToBase64, saveClipboardImage, formatFileSize } from '../utils/image.js';
11
+
12
+ /**
13
+ * ImageAnalyzer class for screenshot error analysis
14
+ */
15
+ export class ImageAnalyzer {
16
+ constructor(projectPath = process.cwd()) {
17
+ this.projectPath = projectPath;
18
+ }
19
+
20
+ /**
21
+ * Analyze image file for errors
22
+ */
23
+ async analyzeImage(imagePath) {
24
+ console.log(chalk.cyan('\n Analyzing screenshot...\n'));
25
+
26
+ try {
27
+ // Read and validate image
28
+ const imageInfo = await imageToBase64(imagePath);
29
+
30
+ console.log(chalk.gray(` File: ${path.basename(imageInfo.path)}`));
31
+ console.log(chalk.gray(` Size: ${formatFileSize(imageInfo.size)}\n`));
32
+
33
+ // Run AI analysis
34
+ const analysis = await this.runImageAnalysis(imageInfo);
35
+
36
+ return analysis;
37
+ } catch (error) {
38
+ throw new Error(`Failed to analyze image: ${error.message}`);
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Analyze image from clipboard
44
+ */
45
+ async analyzeClipboard() {
46
+ console.log(chalk.cyan('\n Getting image from clipboard...\n'));
47
+
48
+ try {
49
+ const tempFile = await saveClipboardImage();
50
+ console.log(chalk.green(` Image captured\n`));
51
+
52
+ const result = await this.analyzeImage(tempFile);
53
+
54
+ // Cleanup temp file
55
+ try {
56
+ await fs.unlink(tempFile);
57
+ } catch {
58
+ // Ignore cleanup errors
59
+ }
60
+
61
+ return result;
62
+ } catch (error) {
63
+ throw new Error(`Clipboard error: ${error.message}`);
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Run AI analysis on image
69
+ */
70
+ async runImageAnalysis(imageInfo) {
71
+ // Create analysis prompt
72
+ const prompt = this.buildAnalysisPrompt(imageInfo);
73
+
74
+ // Save prompt to temp file
75
+ const tempDir = path.join(this.projectPath, '.vibecode', 'debug');
76
+ await fs.mkdir(tempDir, { recursive: true });
77
+
78
+ const promptFile = path.join(tempDir, 'image-analysis.md');
79
+ await fs.writeFile(promptFile, prompt);
80
+
81
+ // Also save image reference
82
+ const imageRef = path.join(tempDir, 'screenshot-ref.txt');
83
+ await fs.writeFile(imageRef, imageInfo.path);
84
+
85
+ // Run Claude Code with image
86
+ const result = await this.runClaudeWithImage(imageInfo, promptFile);
87
+
88
+ return this.parseAnalysisResult(result);
89
+ }
90
+
91
+ /**
92
+ * Build analysis prompt
93
+ */
94
+ buildAnalysisPrompt(imageInfo) {
95
+ return `# Screenshot Error Analysis
96
+
97
+ Analyze this screenshot and extract any error information.
98
+
99
+ ## Instructions
100
+ 1. Look for error messages, stack traces, console errors, or warnings
101
+ 2. Identify the error type (TypeError, SyntaxError, Build Error, etc.)
102
+ 3. Extract file names and line numbers if visible
103
+ 4. Note any relevant context visible in the screenshot
104
+ 5. Provide specific fix suggestions
105
+
106
+ ## Response Format
107
+ Respond in this exact format:
108
+
109
+ **Error Type**: [type of error or "None detected"]
110
+ **Error Message**: [main error text]
111
+ **Location**: [file:line if visible]
112
+ **Root Cause**: [explanation of what's wrong]
113
+ **Suggested Fix**: [how to fix it]
114
+ **Confidence**: [High/Medium/Low]
115
+
116
+ If no error is visible, respond with:
117
+ **Error Type**: None detected
118
+ **Error Message**: No error visible in screenshot
119
+ `;
120
+ }
121
+
122
+ /**
123
+ * Run Claude Code with image input
124
+ */
125
+ async runClaudeWithImage(imageInfo, promptFile) {
126
+ return new Promise((resolve) => {
127
+ let output = '';
128
+ let errorOutput = '';
129
+
130
+ // Use claude with image path
131
+ // Claude Code can read images directly
132
+ const args = [
133
+ '--print',
134
+ '-p', `Analyze this image for errors: ${imageInfo.path}
135
+
136
+ Look for:
137
+ - Error messages
138
+ - Stack traces
139
+ - Console errors
140
+ - Type errors
141
+ - Build failures
142
+
143
+ Respond with:
144
+ **Error Type**:
145
+ **Error Message**:
146
+ **Location**:
147
+ **Root Cause**:
148
+ **Suggested Fix**:
149
+ **Confidence**:
150
+
151
+ If no error found, say "No error detected"`
152
+ ];
153
+
154
+ const child = spawn('claude', args, {
155
+ cwd: this.projectPath,
156
+ stdio: ['pipe', 'pipe', 'pipe']
157
+ });
158
+
159
+ child.stdout.on('data', (data) => {
160
+ output += data.toString();
161
+ });
162
+
163
+ child.stderr.on('data', (data) => {
164
+ errorOutput += data.toString();
165
+ });
166
+
167
+ child.on('close', (code) => {
168
+ resolve({
169
+ success: code === 0,
170
+ output: output.trim(),
171
+ error: errorOutput.trim()
172
+ });
173
+ });
174
+
175
+ child.on('error', (error) => {
176
+ resolve({
177
+ success: false,
178
+ output: '',
179
+ error: error.message
180
+ });
181
+ });
182
+
183
+ // Timeout after 60 seconds
184
+ setTimeout(() => {
185
+ child.kill();
186
+ resolve({
187
+ success: false,
188
+ output: '',
189
+ error: 'Analysis timed out'
190
+ });
191
+ }, 60000);
192
+ });
193
+ }
194
+
195
+ /**
196
+ * Parse AI analysis result
197
+ */
198
+ parseAnalysisResult(result) {
199
+ const analysis = {
200
+ errorType: null,
201
+ errorMessage: null,
202
+ location: null,
203
+ rootCause: null,
204
+ suggestedFix: null,
205
+ confidence: 'Low',
206
+ raw: result?.output || '',
207
+ success: result?.success || false
208
+ };
209
+
210
+ const output = result?.output || '';
211
+
212
+ // Extract fields using regex
213
+ const patterns = {
214
+ errorType: /\*\*Error Type\*\*:\s*(.+?)(?:\n|$)/i,
215
+ errorMessage: /\*\*Error Message\*\*:\s*(.+?)(?:\n|$)/i,
216
+ location: /\*\*Location\*\*:\s*(.+?)(?:\n|$)/i,
217
+ rootCause: /\*\*Root Cause\*\*:\s*(.+?)(?:\n|$)/i,
218
+ suggestedFix: /\*\*Suggested Fix\*\*:\s*(.+?)(?:\n|$)/i,
219
+ confidence: /\*\*Confidence\*\*:\s*(.+?)(?:\n|$)/i
220
+ };
221
+
222
+ for (const [key, pattern] of Object.entries(patterns)) {
223
+ const match = output.match(pattern);
224
+ if (match && match[1]) {
225
+ const value = match[1].trim();
226
+ if (value && value.toLowerCase() !== 'none' && value.toLowerCase() !== 'n/a') {
227
+ analysis[key] = value;
228
+ }
229
+ }
230
+ }
231
+
232
+ // Check if error was actually detected
233
+ if (analysis.errorType?.toLowerCase().includes('none detected') ||
234
+ analysis.errorMessage?.toLowerCase().includes('no error')) {
235
+ analysis.errorType = null;
236
+ analysis.errorMessage = null;
237
+ }
238
+
239
+ return analysis;
240
+ }
241
+
242
+ /**
243
+ * Format analysis for display
244
+ */
245
+ formatAnalysis(analysis) {
246
+ // No error case
247
+ if (!analysis.errorType && !analysis.errorMessage) {
248
+ return chalk.yellow('\n No error detected in screenshot.\n');
249
+ }
250
+
251
+ let output = chalk.cyan(`
252
+ +----------------------------------------------------------------------+
253
+ | SCREENSHOT ANALYSIS |
254
+ +----------------------------------------------------------------------+
255
+ `);
256
+
257
+ if (analysis.errorType) {
258
+ output += `\n ${chalk.white('Error Type:')} ${chalk.red(analysis.errorType)}`;
259
+ }
260
+
261
+ if (analysis.errorMessage) {
262
+ output += `\n ${chalk.white('Message:')} ${chalk.yellow(analysis.errorMessage)}`;
263
+ }
264
+
265
+ if (analysis.location) {
266
+ output += `\n ${chalk.white('Location:')} ${chalk.gray(analysis.location)}`;
267
+ }
268
+
269
+ if (analysis.confidence) {
270
+ const confColor = analysis.confidence === 'High' ? chalk.green :
271
+ analysis.confidence === 'Medium' ? chalk.yellow : chalk.gray;
272
+ output += `\n ${chalk.white('Confidence:')} ${confColor(analysis.confidence)}`;
273
+ }
274
+
275
+ if (analysis.rootCause) {
276
+ output += `\n\n ${chalk.cyan('Root Cause:')}`;
277
+ output += `\n ${chalk.gray(analysis.rootCause)}`;
278
+ }
279
+
280
+ if (analysis.suggestedFix) {
281
+ output += `\n\n ${chalk.green('Suggested Fix:')}`;
282
+ output += `\n ${chalk.white(analysis.suggestedFix)}`;
283
+ }
284
+
285
+ output += '\n';
286
+
287
+ return output;
288
+ }
289
+ }
290
+
291
+ /**
292
+ * Helper function for direct use
293
+ */
294
+ export async function analyzeScreenshot(imagePathOrClipboard, options = {}) {
295
+ const analyzer = new ImageAnalyzer(options.projectPath || process.cwd());
296
+
297
+ if (imagePathOrClipboard === 'clipboard') {
298
+ return await analyzer.analyzeClipboard();
299
+ } else {
300
+ return await analyzer.analyzeImage(imagePathOrClipboard);
301
+ }
302
+ }
303
+
304
+ export default ImageAnalyzer;
@@ -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';