debuggingAssistant.ts•15.5 kB
import type { EnhancedVideoAnalysis, ErrorOccurrence } from './enhancedVideoAnalyzer'
export interface DebuggingPlan {
summary: string
rootCauseHypotheses: RootCauseHypothesis[]
investigationSteps: InvestigationStep[]
codeChangeSuggestions: CodeChangeSuggestion[]
testingStrategy: TestingStrategy
}
export interface RootCauseHypothesis {
hypothesis: string
confidence: number
evidence: string[]
investigationPriority: number
}
export interface InvestigationStep {
order: number
action: string
targetFile?: string
targetLine?: number
expectedOutcome: string
tools: ('debugger' | 'console' | 'network' | 'profiler')[]
}
export interface CodeChangeSuggestion {
file: string
line?: number
type: 'fix' | 'validation' | 'error_handling' | 'logging' | 'refactor'
description: string
code?: string
priority: 'high' | 'medium' | 'low'
}
export interface TestingStrategy {
unitTests: TestSuggestion[]
integrationTests: TestSuggestion[]
e2eTests: TestSuggestion[]
}
export interface TestSuggestion {
testName: string
testType: string
coverage: string[]
scenario: string
}
export class DebuggingAssistant {
generateDebuggingPlan(analysis: EnhancedVideoAnalysis): DebuggingPlan {
const rootCauseHypotheses = this.generateRootCauseHypotheses(analysis)
const investigationSteps = this.createInvestigationSteps(analysis, rootCauseHypotheses)
const codeChangeSuggestions = this.suggestCodeChanges(analysis)
const testingStrategy = this.createTestingStrategy(analysis)
const summary = this.generateSummary(analysis, rootCauseHypotheses)
return {
summary,
rootCauseHypotheses,
investigationSteps,
codeChangeSuggestions,
testingStrategy,
}
}
private generateRootCauseHypotheses(analysis: EnhancedVideoAnalysis): RootCauseHypothesis[] {
const hypotheses: RootCauseHypothesis[] = []
// Analyze errors
for (const error of analysis.errors) {
if (error.errorType === 'network') {
hypotheses.push({
hypothesis: 'API endpoint is not responding or returning unexpected data',
confidence: 0.8,
evidence: [`Network error: "${error.errorMessage}"`, ...error.possibleCauses],
investigationPriority: 1,
})
} else if (error.errorType === 'validation') {
hypotheses.push({
hypothesis: 'Form validation logic is incorrectly configured',
confidence: 0.7,
evidence: [
`Validation error: "${error.errorMessage}"`,
`Related form fields: ${analysis.codeContext.components.filter((c) => c.includes('Form')).join(', ')}`,
],
investigationPriority: 2,
})
}
}
// Analyze failed actions
const failedActions = analysis.userActions.filter((a) => a.result === 'error')
if (failedActions.length > 0) {
const failedTypes = [...new Set(failedActions.map((a) => a.type))]
hypotheses.push({
hypothesis: `User interactions failing due to state management issues`,
confidence: 0.6,
evidence: [
`${failedActions.length} actions failed`,
`Failed action types: ${failedTypes.join(', ')}`,
`Components involved: ${failedActions.map((a) => a.target).join(', ')}`,
],
investigationPriority: 3,
})
}
// Analyze data flow issues
const dataFlowIssues = this.identifyDataFlowIssues(analysis)
if (dataFlowIssues.length > 0) {
hypotheses.push({
hypothesis: 'Data is not properly flowing between components',
confidence: 0.5,
evidence: dataFlowIssues,
investigationPriority: 4,
})
}
// Sort by priority
return hypotheses.sort((a, b) => a.investigationPriority - b.investigationPriority)
}
private createInvestigationSteps(
analysis: EnhancedVideoAnalysis,
hypotheses: RootCauseHypothesis[]
): InvestigationStep[] {
const steps: InvestigationStep[] = []
let stepOrder = 1
// For each hypothesis, create investigation steps
for (const hypothesis of hypotheses.slice(0, 3)) {
if (hypothesis.hypothesis.includes('API endpoint')) {
// Network investigation
steps.push({
order: stepOrder++,
action: 'Open Network tab and reproduce the issue',
expectedOutcome: 'Identify failing API calls and response status',
tools: ['network'],
})
// Find API-related files
const apiFile = analysis.relevantFiles.find(
(f) => f.reason.includes('API') || f.path.includes('api')
)
if (apiFile) {
steps.push({
order: stepOrder++,
action: 'Set breakpoint in API call handler',
targetFile: apiFile.path,
targetLine: apiFile.snippets?.[0]?.line,
expectedOutcome: 'Trace request parameters and response',
tools: ['debugger'],
})
}
} else if (hypothesis.hypothesis.includes('validation')) {
// Validation investigation
const validationFile = analysis.relevantFiles.find(
(f) =>
f.snippets?.some((s) => s.content.includes('validate')) ||
f.path.includes('validation')
)
if (validationFile) {
steps.push({
order: stepOrder++,
action: 'Inspect validation rules',
targetFile: validationFile.path,
targetLine: validationFile.snippets?.find((s) =>
s.content.includes('validate')
)?.line,
expectedOutcome: 'Verify validation logic matches requirements',
tools: ['debugger'],
})
}
steps.push({
order: stepOrder++,
action: 'Log form data before validation',
expectedOutcome: 'See actual vs expected data format',
tools: ['console'],
})
} else if (hypothesis.hypothesis.includes('state management')) {
// State investigation
steps.push({
order: stepOrder++,
action: 'Use React DevTools to inspect component state',
expectedOutcome: 'Identify state inconsistencies',
tools: ['debugger'],
})
const stateFile = analysis.relevantFiles.find(
(f) =>
f.path.includes('state') ||
f.path.includes('reducer') ||
f.path.includes('context')
)
if (stateFile) {
steps.push({
order: stepOrder++,
action: 'Add logging to state updates',
targetFile: stateFile.path,
expectedOutcome: 'Track state changes during user interaction',
tools: ['console', 'debugger'],
})
}
}
}
// Add general debugging steps based on reproducible steps
if (analysis.reproducibleSteps.length > 0) {
const errorStep = analysis.reproducibleSteps.find((s) =>
s.actualResult?.includes('Error')
)
if (errorStep) {
steps.push({
order: stepOrder++,
action: `Reproduce issue by: ${errorStep.action}`,
expectedOutcome: 'Observe the exact error in console',
tools: ['console', 'network'],
})
}
}
return steps
}
private suggestCodeChanges(analysis: EnhancedVideoAnalysis): CodeChangeSuggestion[] {
const suggestions: CodeChangeSuggestion[] = []
// Error handling suggestions
for (const error of analysis.errors) {
if (error.relatedCode.length > 0) {
const codeRef = error.relatedCode[0]
suggestions.push({
file: codeRef.file,
line: codeRef.line,
type: 'error_handling',
description: `Add better error handling for: ${error.errorMessage}`,
code: this.generateErrorHandlingCode(error),
priority: 'high',
})
}
}
// Validation suggestions
const validationErrors = analysis.errors.filter((e) => e.errorType === 'validation')
if (validationErrors.length > 0) {
const formComponent = analysis.relevantFiles.find(
(f) => f.reason.includes('Component') && f.path.includes('form')
)
if (formComponent) {
suggestions.push({
file: formComponent.path,
type: 'validation',
description: 'Add input validation before submission',
code: this.generateValidationCode(analysis),
priority: 'high',
})
}
}
// Logging suggestions for debugging
const complexInteractions = analysis.userActions.filter(
(a) => a.type === 'submit' || (a.type === 'click' && a.result === 'error')
)
if (complexInteractions.length > 0) {
suggestions.push({
file: analysis.relevantFiles[0]?.path || 'main component file',
type: 'logging',
description: 'Add debug logging for user interactions',
code: this.generateLoggingCode(),
priority: 'medium',
})
}
return suggestions
}
private createTestingStrategy(analysis: EnhancedVideoAnalysis): TestingStrategy {
const unitTests: TestSuggestion[] = []
const integrationTests: TestSuggestion[] = []
const e2eTests: TestSuggestion[] = []
// Unit tests for validation
if (analysis.errors.some((e) => e.errorType === 'validation')) {
unitTests.push({
testName: 'Form validation rules',
testType: 'unit',
coverage: ['validation functions', 'error messages'],
scenario: 'Test all validation edge cases',
})
}
// Integration tests for API calls
if (analysis.errors.some((e) => e.errorType === 'network')) {
integrationTests.push({
testName: 'API error handling',
testType: 'integration',
coverage: ['API calls', 'error states', 'retry logic'],
scenario: 'Test API failures and recovery',
})
}
// E2E test based on reproducible steps
if (analysis.reproducibleSteps.length > 0) {
e2eTests.push({
testName: 'User flow from video',
testType: 'e2e',
coverage: analysis.reproducibleSteps.map((s) => s.action),
scenario: 'Reproduce exact user journey from video',
})
}
return { unitTests, integrationTests, e2eTests }
}
private generateSummary(
analysis: EnhancedVideoAnalysis,
hypotheses: RootCauseHypothesis[]
): string {
const errorCount = analysis.errors.length
const failedActionCount = analysis.userActions.filter((a) => a.result === 'error').length
const topHypothesis = hypotheses[0]
let summary = `## Debugging Summary\n\n`
summary += `**Issue Overview:**\n`
summary += `- ${errorCount} error(s) detected in the video\n`
summary += `- ${failedActionCount} user action(s) failed\n`
summary += `- ${analysis.relevantFiles.length} relevant code files identified\n\n`
if (topHypothesis) {
summary += `**Most Likely Cause:** ${topHypothesis.hypothesis} (${(topHypothesis.confidence * 100).toFixed(0)}% confidence)\n\n`
}
summary += `**Key Findings:**\n`
if (analysis.errors.length > 0) {
summary += `- Primary error: "${analysis.errors[0].errorMessage}"\n`
}
if (analysis.screenStates.length > 0) {
const routes = [...new Set(analysis.screenStates.map((s) => s.route).filter((r) => r))]
summary += `- Pages affected: ${routes.join(', ')}\n`
}
return summary
}
private identifyDataFlowIssues(analysis: EnhancedVideoAnalysis): string[] {
const issues: string[] = []
// Check for data entered but not appearing
const typeActions = analysis.userActions.filter((a) => a.type === 'type')
const submitActions = analysis.userActions.filter((a) => a.type === 'submit')
if (typeActions.length > 0 && submitActions.some((s) => s.result === 'error')) {
issues.push('Data entered in form may not be properly captured')
}
// Check for missing data in UI
if (
analysis.screenStates.some((s) => Object.keys(s.dataPresent).length === 0) &&
typeActions.length > 0
) {
issues.push('Form data not reflected in component state')
}
return issues
}
private generateErrorHandlingCode(error: ErrorOccurrence): string {
return `
try {
// Existing code here
} catch (error) {
console.error('${error.errorMessage}:', error);
// Add user-friendly error handling
if (error.message.includes('${error.errorMessage.split(' ')[0]}')) {
// Handle specific error
showErrorToUser('${error.possibleCauses[0] || 'An error occurred'}');
}
}`
}
private generateValidationCode(analysis: EnhancedVideoAnalysis): string {
const fields = analysis.codeContext.keywords.filter(
(k) => k.includes('input') || k.includes('field')
)
return `
const validateForm = (data) => {
const errors = {};
${fields
.map(
(field) => `
if (!data.${field}) {
errors.${field} = '${field} is required';
}`
)
.join('\n')}
return Object.keys(errors).length === 0 ? null : errors;
};`
}
private generateLoggingCode(): string {
return `
// Debug logging for user interactions
const logUserAction = (action, data) => {
console.group(\`User Action: \${action}\`);
console.log('Timestamp:', new Date().toISOString());
console.log('Data:', data);
console.log('Current State:', getCurrentState());
console.groupEnd();
};`
}
}