@nclamvn/vibecode-cli 1.2.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,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
+ }
@@ -0,0 +1,349 @@
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
+
31
+ const execAsync = promisify(exec);
32
+
33
+ /**
34
+ * Debug Engine Class
35
+ * Main orchestrator for the debugging workflow
36
+ */
37
+ export class DebugEngine {
38
+ constructor(projectPath, options = {}) {
39
+ this.projectPath = projectPath;
40
+ this.options = {
41
+ autoFix: options.autoFix || false,
42
+ maxAttempts: options.maxAttempts || 3,
43
+ verbose: options.verbose || false,
44
+ interactive: options.interactive !== false,
45
+ ...options
46
+ };
47
+
48
+ // Initialize components
49
+ this.evidence = new EvidenceCollector(projectPath);
50
+ this.analyzer = new RootCauseAnalyzer();
51
+ this.fixer = new FixGenerator(projectPath);
52
+ this.verifier = new FixVerifier(projectPath);
53
+
54
+ // Debug session state
55
+ this.session = {
56
+ id: `debug-${Date.now()}`,
57
+ startTime: new Date().toISOString(),
58
+ steps: [],
59
+ attempts: 0,
60
+ resolved: false
61
+ };
62
+ }
63
+
64
+ /**
65
+ * Run the full debug workflow
66
+ */
67
+ async debug(input) {
68
+ console.log(chalk.cyan.bold('\n🔍 VIBECODE DEBUG - Intelligent Bug Fixing\n'));
69
+
70
+ try {
71
+ // Step 1: EVIDENCE - Gather error information
72
+ this.logStep(1, 'EVIDENCE', 'Gathering error information...');
73
+ const evidence = await this.evidence.collect(input);
74
+ this.session.steps.push({ step: 'EVIDENCE', data: evidence });
75
+ this.logEvidence(evidence);
76
+
77
+ // Step 2: REPRODUCE - Confirm error exists (if auto mode)
78
+ if (input.auto) {
79
+ this.logStep(2, 'REPRODUCE', 'Confirming error exists...');
80
+ const reproduced = await this.reproduce(evidence);
81
+ this.session.steps.push({ step: 'REPRODUCE', data: reproduced });
82
+
83
+ if (!reproduced.errorFound) {
84
+ console.log(chalk.green(' ✓ No errors found during reproduction check'));
85
+ return this.createResult('no_error', 'No errors found to fix');
86
+ }
87
+ }
88
+
89
+ // Step 3: ANALYZE - Identify root cause
90
+ this.logStep(3, 'ANALYZE', 'Analyzing root cause...');
91
+ const analysis = await this.analyzer.analyze(evidence);
92
+ this.session.steps.push({ step: 'ANALYZE', data: analysis });
93
+ this.logAnalysis(analysis);
94
+
95
+ // Step 4: HYPOTHESIZE - Generate fix hypotheses
96
+ this.logStep(4, 'HYPOTHESIZE', 'Generating fix hypotheses...');
97
+ const hypotheses = this.analyzer.buildHypotheses(analysis);
98
+ this.session.steps.push({ step: 'HYPOTHESIZE', data: hypotheses });
99
+ this.logHypotheses(hypotheses);
100
+
101
+ if (hypotheses.length === 0) {
102
+ console.log(chalk.yellow(' ⚠ No fix hypotheses generated'));
103
+ return this.createResult('no_hypothesis', 'Could not generate fix hypotheses');
104
+ }
105
+
106
+ // Step 5-7: TEST, FIX, VERIFY - Attempt fixes
107
+ let fixResult = null;
108
+ for (let attempt = 0; attempt < this.options.maxAttempts && !this.session.resolved; attempt++) {
109
+ this.session.attempts = attempt + 1;
110
+
111
+ const hypothesis = hypotheses[attempt % hypotheses.length];
112
+ console.log(chalk.cyan(`\n Attempt ${attempt + 1}/${this.options.maxAttempts}:`));
113
+
114
+ // Step 5: TEST - Generate fix prompt
115
+ this.logStep(5, 'TEST', 'Preparing fix...');
116
+ const fixPrompt = this.fixer.generateFixPrompt(evidence, hypothesis);
117
+ const fixAttempt = this.fixer.createFixAttempt(evidence, hypothesis);
118
+
119
+ // Step 6: FIX - Apply fix via Claude Code
120
+ this.logStep(6, 'FIX', 'Applying fix via Claude Code...');
121
+ fixResult = await this.applyFix(fixPrompt);
122
+ fixAttempt.status = fixResult.success ? 'applied' : 'failed';
123
+
124
+ if (!fixResult.success) {
125
+ console.log(chalk.yellow(` ⚠ Fix application failed: ${fixResult.error}`));
126
+ continue;
127
+ }
128
+
129
+ // Step 7: VERIFY - Confirm fix works
130
+ this.logStep(7, 'VERIFY', 'Verifying fix...');
131
+ const verification = await this.verifier.verify(evidence, fixAttempt);
132
+ this.session.steps.push({ step: 'VERIFY', data: verification });
133
+
134
+ if (verification.passed) {
135
+ console.log(chalk.green(' ✓ Fix verified successfully!'));
136
+ this.session.resolved = true;
137
+ fixAttempt.verified = true;
138
+
139
+ // Step 8: DOCUMENT - Log the fix
140
+ this.logStep(8, 'DOCUMENT', 'Documenting fix...');
141
+ await this.fixer.documentFix(fixAttempt);
142
+
143
+ // Step 9: PREVENT - Add prevention rules
144
+ this.logStep(9, 'PREVENT', 'Adding prevention rules...');
145
+ await this.fixer.updateClaudeMd(fixAttempt);
146
+
147
+ console.log(chalk.green.bold('\n✅ Bug fixed and documented!\n'));
148
+ } else {
149
+ console.log(chalk.yellow(' ⚠ Verification failed, trying next approach...'));
150
+ }
151
+ }
152
+
153
+ return this.createResult(
154
+ this.session.resolved ? 'resolved' : 'unresolved',
155
+ this.session.resolved ? 'Bug fixed successfully' : 'Could not resolve after max attempts',
156
+ fixResult
157
+ );
158
+
159
+ } catch (error) {
160
+ console.log(chalk.red(`\n❌ Debug error: ${error.message}\n`));
161
+ return this.createResult('error', error.message);
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Quick debug mode - minimal interaction
167
+ */
168
+ async quickDebug(description) {
169
+ return this.debug({
170
+ description,
171
+ auto: false
172
+ });
173
+ }
174
+
175
+ /**
176
+ * Auto scan and fix mode
177
+ */
178
+ async autoDebug() {
179
+ console.log(chalk.cyan('🔄 Auto-scanning project for errors...\n'));
180
+
181
+ return this.debug({
182
+ auto: true
183
+ });
184
+ }
185
+
186
+ /**
187
+ * Reproduce the error to confirm it exists
188
+ */
189
+ async reproduce(evidence) {
190
+ const result = {
191
+ errorFound: false,
192
+ output: ''
193
+ };
194
+
195
+ // Try to reproduce based on category
196
+ try {
197
+ const checks = {
198
+ SYNTAX: 'npx tsc --noEmit',
199
+ TYPE: 'npx tsc --noEmit',
200
+ IMPORT: 'npx tsc --noEmit',
201
+ BUILD: 'npm run build',
202
+ LINT: 'npm run lint',
203
+ TEST: 'npm test'
204
+ };
205
+
206
+ const command = checks[evidence.category] || 'npm run build';
207
+
208
+ await execAsync(command, {
209
+ cwd: this.projectPath,
210
+ timeout: 60000
211
+ });
212
+
213
+ result.output = 'Command succeeded';
214
+ } catch (error) {
215
+ result.errorFound = true;
216
+ result.output = error.stderr || error.stdout || error.message;
217
+ }
218
+
219
+ return result;
220
+ }
221
+
222
+ /**
223
+ * Apply a fix using Claude Code
224
+ */
225
+ async applyFix(prompt) {
226
+ const result = {
227
+ success: false,
228
+ output: '',
229
+ error: null
230
+ };
231
+
232
+ try {
233
+ // Check if Claude Code is available
234
+ const available = await isClaudeCodeAvailable();
235
+ if (!available) {
236
+ throw new Error('Claude Code CLI not found. Install with: npm install -g @anthropic-ai/claude-code');
237
+ }
238
+
239
+ // Save prompt to debug folder for reference
240
+ const promptFile = path.join(this.projectPath, '.vibecode', 'debug', 'current-fix.md');
241
+ await fs.ensureDir(path.dirname(promptFile));
242
+ await fs.writeFile(promptFile, prompt);
243
+
244
+ if (this.options.verbose) {
245
+ console.log(chalk.gray(` Running Claude Code with fix prompt...`));
246
+ }
247
+
248
+ // Use spawnClaudeCode which handles temp file properly
249
+ const spawnResult = await spawnClaudeCode(prompt, {
250
+ cwd: this.projectPath
251
+ });
252
+
253
+ result.success = spawnResult.success;
254
+ result.output = `Exit code: ${spawnResult.code}`;
255
+
256
+ } catch (error) {
257
+ result.error = error.message;
258
+ result.output = '';
259
+ }
260
+
261
+ return result;
262
+ }
263
+
264
+ /**
265
+ * Log a debug step
266
+ */
267
+ logStep(number, name, message) {
268
+ const stepLabel = chalk.cyan(`[${number}/9 ${name}]`);
269
+ console.log(`${stepLabel} ${message}`);
270
+ }
271
+
272
+ /**
273
+ * Log evidence summary
274
+ */
275
+ logEvidence(evidence) {
276
+ console.log(chalk.gray(` Type: ${evidence.type || 'Unknown'}`));
277
+ console.log(chalk.gray(` Category: ${evidence.category}`));
278
+ if (evidence.message) {
279
+ console.log(chalk.gray(` Message: ${evidence.message.substring(0, 100)}${evidence.message.length > 100 ? '...' : ''}`));
280
+ }
281
+ if (evidence.files.length > 0) {
282
+ console.log(chalk.gray(` Files: ${evidence.files.slice(0, 3).join(', ')}${evidence.files.length > 3 ? '...' : ''}`));
283
+ }
284
+ }
285
+
286
+ /**
287
+ * Log analysis results
288
+ */
289
+ logAnalysis(analysis) {
290
+ console.log(chalk.gray(` Root cause: ${analysis.rootCause || 'Unknown'}`));
291
+ console.log(chalk.gray(` Confidence: ${Math.round(analysis.confidence * 100)}%`));
292
+ if (analysis.patterns.length > 0) {
293
+ console.log(chalk.gray(` Patterns: ${analysis.patterns.join(', ')}`));
294
+ }
295
+ }
296
+
297
+ /**
298
+ * Log hypotheses
299
+ */
300
+ logHypotheses(hypotheses) {
301
+ console.log(chalk.gray(` Generated ${hypotheses.length} hypothesis(es):`));
302
+ for (const h of hypotheses.slice(0, 3)) {
303
+ console.log(chalk.gray(` - ${h.description.substring(0, 60)}... (${Math.round(h.confidence * 100)}%)`));
304
+ }
305
+ }
306
+
307
+ /**
308
+ * Create result object
309
+ */
310
+ createResult(status, message, fixResult = null) {
311
+ return {
312
+ status,
313
+ message,
314
+ session: {
315
+ id: this.session.id,
316
+ attempts: this.session.attempts,
317
+ resolved: this.session.resolved,
318
+ steps: this.session.steps.length
319
+ },
320
+ fixResult
321
+ };
322
+ }
323
+
324
+ /**
325
+ * Get debug session summary
326
+ */
327
+ getSessionSummary() {
328
+ return {
329
+ id: this.session.id,
330
+ startTime: this.session.startTime,
331
+ attempts: this.session.attempts,
332
+ resolved: this.session.resolved,
333
+ stepsCompleted: this.session.steps.map(s => s.step)
334
+ };
335
+ }
336
+ }
337
+
338
+ /**
339
+ * Create a new debug engine instance
340
+ */
341
+ export function createDebugEngine(projectPath, options = {}) {
342
+ return new DebugEngine(projectPath, options);
343
+ }
344
+
345
+ // Re-export components
346
+ export { EvidenceCollector } from './evidence.js';
347
+ export { RootCauseAnalyzer } from './analyzer.js';
348
+ export { FixGenerator } from './fixer.js';
349
+ export { FixVerifier } from './verifier.js';