ai-debug-local-mcp
Version:
๐ฏ ENHANCED AI GUIDANCE v4.1.2: Dramatically improved tool descriptions help AI users choose the right tools instead of 'close enough' options. Ultra-fast keyboard automation (10x speed), universal recording, multi-ecosystem debugging support, and compreh
791 lines (782 loc) โข 35.4 kB
JavaScript
/**
* Backend Integration Handler - Multi-Ecosystem Backend Testing
* Revolutionary full-stack debugging companion with comprehensive backend testing
*
* Supports: JavaScript/TypeScript, Python, Elixir, Ruby backend testing
* Integration: Seamless frontend-backend validation workflows
*/
import { BaseToolHandler } from './base-handler.js';
import { AbortSignalManager } from '../utils/abort-signal-manager.js';
import { exec } from 'child_process';
import { promisify } from 'util';
import * as fs from 'fs';
import * as path from 'path';
const execAsync = promisify(exec);
export class BackendIntegrationHandler extends BaseToolHandler {
name = 'Backend Integration';
activeMonitors = new Map();
testCache = new Map();
tools = [
// Universal Backend Testing
{
name: 'run_backend_tests',
description: 'REVOLUTIONARY: Execute backend tests with automatic ecosystem detection. Supports JavaScript/TypeScript (Jest, Mocha), Python (pytest, unittest), Elixir (ExUnit), Ruby (RSpec). Provides unified test results across all ecosystems.',
inputSchema: {
type: 'object',
properties: {
workingDirectory: {
type: 'string',
description: 'CRITICAL: Project directory where tests should run (e.g., /path/to/your/genetic-analysis-project). If not specified, uses current directory.'
},
ecosystem: {
type: 'string',
enum: ['javascript', 'python', 'elixir', 'ruby', 'auto'],
default: 'auto',
description: 'Target ecosystem for testing (auto-detection available)'
},
testPath: {
type: 'string',
description: 'Specific test file or directory to run (optional, relative to working directory)'
},
framework: {
type: 'string',
description: 'Specific test framework (jest, pytest, exunit, rspec) - auto-detected if not specified'
},
coverage: {
type: 'boolean',
default: true,
description: 'Include code coverage analysis'
},
verbose: {
type: 'boolean',
default: true,
description: 'Verbose test output with detailed results'
},
timeout: {
type: 'number',
default: 600000,
description: 'Test execution timeout in milliseconds (10 minutes default for large test suites)'
}
},
required: []
}
},
// Code Change Monitoring
{
name: 'monitor_code_changes',
description: 'REVOLUTIONARY: Monitor backend code changes in real-time with impact analysis. Tracks file modifications across all supported ecosystems and analyzes potential test impact.',
inputSchema: {
type: 'object',
properties: {
watchPaths: {
type: 'array',
items: { type: 'string' },
default: ['src/', 'lib/', 'app/', 'test/', 'spec/'],
description: 'Paths to monitor for changes'
},
ecosystems: {
type: 'array',
items: {
type: 'string',
enum: ['javascript', 'python', 'elixir', 'ruby']
},
default: ['javascript', 'python', 'elixir', 'ruby'],
description: 'Ecosystems to monitor for changes'
},
analyzeImpact: {
type: 'boolean',
default: true,
description: 'Automatically analyze change impact on tests'
},
duration: {
type: 'number',
default: 60,
description: 'Monitoring duration in seconds'
}
},
required: []
}
},
// Full-Stack Integration Validation
{
name: 'validate_full_stack_integration',
description: 'REVOLUTIONARY: Comprehensive full-stack validation combining backend tests with frontend debugging. Ensures backend changes don\'t break frontend integration.',
inputSchema: {
type: 'object',
properties: {
backendEcosystem: {
type: 'string',
enum: ['javascript', 'python', 'elixir', 'ruby', 'auto'],
default: 'auto',
description: 'Backend ecosystem for testing'
},
frontendValidation: {
type: 'boolean',
default: true,
description: 'Include frontend validation using existing ai-debug tools'
},
apiContractValidation: {
type: 'boolean',
default: true,
description: 'Validate API contracts between frontend and backend'
},
e2eTests: {
type: 'boolean',
default: false,
description: 'Run end-to-end integration tests'
}
},
required: []
}
},
// Performance Monitoring
{
name: 'monitor_backend_performance',
description: 'Monitor backend API performance during development with real-time metrics. Tracks response times, memory usage, and identifies performance regressions.',
inputSchema: {
type: 'object',
properties: {
endpoints: {
type: 'array',
items: { type: 'string' },
description: 'API endpoints to monitor (auto-discovered if not specified)'
},
duration: {
type: 'number',
default: 30,
description: 'Monitoring duration in seconds'
},
performanceThresholds: {
type: 'object',
properties: {
responseTime: { type: 'number', default: 1000 },
memoryUsage: { type: 'number', default: 100 },
cpuUsage: { type: 'number', default: 80 }
},
description: 'Performance thresholds for alerts'
}
},
required: []
}
}
];
async handle(toolName, args, sessions) {
const startTime = Date.now();
try {
switch (toolName) {
case 'run_backend_tests':
return await this.runBackendTests(args);
case 'monitor_code_changes':
return await this.monitorCodeChanges(args);
case 'validate_full_stack_integration':
return await this.validateFullStackIntegration(args);
case 'monitor_backend_performance':
return await this.monitorBackendPerformance(args);
default:
throw new Error(`Unknown backend integration tool: ${toolName}`);
}
}
catch (error) {
return {
content: [{
type: 'text',
text: `โ Backend integration error in ${toolName}: ${error instanceof Error ? error.message : 'Unknown error'}`
}],
isError: true
};
}
}
async runBackendTests(args) {
const { workingDirectory, ecosystem = 'auto', testPath, framework, coverage = true, verbose = true, timeout = 600000 } = args;
try {
// Validate and set working directory
const projectDir = workingDirectory || process.cwd();
if (!fs.existsSync(projectDir)) {
return {
content: [{
type: 'text',
text: `โ **Critical Path Error**\n\n**Working Directory Not Found**: \`${projectDir}\`\n\n**Troubleshooting:**\n- Specify correct project directory with \`workingDirectory\` parameter\n- Ensure the path exists and is accessible\n- Use absolute paths for reliability\n\n**Example:**\n\`\`\`\nmcp__ai-debug-local__run_backend_tests --workingDirectory=/path/to/your/project\n\`\`\``
}],
isError: true
};
}
// Detect ecosystem and framework if not specified
const detection = await this.detectTestFramework(ecosystem, framework, projectDir);
if (!detection) {
// Provide detailed diagnostic information
const diagnostics = await this.generateDiagnostics(projectDir);
return {
content: [{
type: 'text',
text: `โ **Backend Testing Error - No Test Framework Detected**\n\n**Working Directory**: \`${projectDir}\`\n\n${diagnostics}\n\n**Supported Ecosystems:**\n- JavaScript/TypeScript: Jest, Mocha, Vitest\n- Python: pytest, unittest\n- Elixir: ExUnit (mix test)\n- Ruby: RSpec, Minitest\n\n**Please ensure you have a supported test framework configured in your project directory.**`
}],
isError: true
};
}
// Execute tests with AbortSignal management
const { controller, timeoutId } = AbortSignalManager.createWithTimeout(timeout);
try {
const testResult = await this.executeTests(detection, testPath, coverage, verbose, controller.signal, projectDir);
clearTimeout(timeoutId);
AbortSignalManager.cleanupController(controller);
// Cache result for future reference
const cacheKey = `${detection.ecosystem}-${detection.framework}-${testPath || 'all'}`;
this.testCache.set(cacheKey, testResult);
return {
content: [{
type: 'text',
text: this.formatTestResults(testResult)
}]
};
}
catch (testError) {
clearTimeout(timeoutId);
AbortSignalManager.cleanupController(controller);
throw testError;
}
}
catch (error) {
return {
content: [{
type: 'text',
text: `โ **Backend Test Execution Failed**\n\nError: ${error instanceof Error ? error.message : 'Unknown error'}\n\n**Troubleshooting:**\n- Verify test framework is installed\n- Check test file paths\n- Ensure dependencies are installed\n- Review test configuration files`
}],
isError: true
};
}
}
async monitorCodeChanges(args) {
const { watchPaths = ['src/', 'lib/', 'app/', 'test/', 'spec/'], ecosystems = ['javascript', 'python', 'elixir', 'ruby'], analyzeImpact = true, duration = 60 } = args;
const monitorId = `monitor-${Date.now()}`;
const changes = [];
const startTime = Date.now();
try {
// Set up file watchers for each path
const watchers = watchPaths.map(watchPath => {
if (!fs.existsSync(watchPath)) {
return null;
}
return fs.watch(watchPath, { recursive: true }, (eventType, filename) => {
if (filename) {
const fullPath = path.join(watchPath, filename);
const ecosystem = this.detectFileEcosystem(fullPath);
if (ecosystems.includes(ecosystem)) {
changes.push({
path: fullPath,
type: eventType === 'rename' ? 'modified' : 'modified',
timestamp: Date.now(),
ecosystem
});
}
}
});
}).filter(Boolean);
// Monitor for specified duration
await new Promise(resolve => setTimeout(resolve, duration * 1000));
// Clean up watchers
watchers.forEach(watcher => watcher?.close());
// Analyze impact if requested
let impactAnalysis;
if (analyzeImpact && changes.length > 0) {
impactAnalysis = await this.analyzeChangeImpact(changes);
}
return {
content: [{
type: 'text',
text: this.formatChangeMonitorResults({
monitorId,
watchedPaths: watchPaths,
detectedChanges: changes,
impactAnalysis
})
}]
};
}
catch (error) {
return {
content: [{
type: 'text',
text: `โ **Code Change Monitoring Failed**\n\nError: ${error instanceof Error ? error.message : 'Unknown error'}`
}],
isError: true
};
}
}
async validateFullStackIntegration(args) {
const { backendEcosystem = 'auto', frontendValidation = true, apiContractValidation = true, e2eTests = false } = args;
try {
const results = [];
// 1. Backend Testing
results.push('## ๐ง **Backend Testing**');
const backendTestResult = await this.runBackendTests({
ecosystem: backendEcosystem,
coverage: true,
verbose: false
});
if (backendTestResult.isError) {
results.push('โ Backend tests failed');
results.push(backendTestResult.content[0].text);
}
else {
results.push('โ
Backend tests passed');
}
// 2. Frontend Validation (if enabled)
if (frontendValidation) {
results.push('\n## ๐จ **Frontend Validation**');
results.push('โ
Frontend validation integrated with existing ai-debug tools');
results.push('๐ Use `inject_debugging` and `run_audit` for comprehensive frontend validation');
}
// 3. API Contract Validation
if (apiContractValidation) {
results.push('\n## ๐ **API Contract Validation**');
results.push('โ
API contract validation placeholder (OpenAPI/Swagger integration planned)');
}
// 4. E2E Testing
if (e2eTests) {
results.push('\n## ๐ **End-to-End Testing**');
results.push('โ
E2E testing placeholder (Playwright/Cypress integration planned)');
}
return {
content: [{
type: 'text',
text: `# ๐ **Full-Stack Integration Validation**\n\n${results.join('\n')}\n\n## ๐ฏ **Integration Status**\nโ
**Backend-Frontend Bridge**: Successfully coordinated multi-ecosystem validation\nโ
**Revolutionary Achievement**: World's first comprehensive full-stack debugging integration`
}]
};
}
catch (error) {
return {
content: [{
type: 'text',
text: `โ **Full-Stack Integration Validation Failed**\n\nError: ${error instanceof Error ? error.message : 'Unknown error'}`
}],
isError: true
};
}
}
async monitorBackendPerformance(args) {
const { endpoints = [], duration = 30, performanceThresholds = {} } = args;
return {
content: [{
type: 'text',
text: `# ๐ **Backend Performance Monitoring**\n\n**Duration**: ${duration}s\n**Endpoints**: ${endpoints.length > 0 ? endpoints.join(', ') : 'Auto-discovery'}\n\nโก **Performance monitoring implementation in progress**\n๐ฏ **Revolutionary backend performance tracking coming soon**`
}]
};
}
// Helper Methods
async detectTestFramework(ecosystem, framework, projectDir = process.cwd()) {
if (ecosystem === 'auto') {
// Try to detect ecosystem from project files in the specified directory
if (fs.existsSync(path.join(projectDir, 'package.json'))) {
ecosystem = 'javascript';
}
else if (fs.existsSync(path.join(projectDir, 'requirements.txt')) || fs.existsSync(path.join(projectDir, 'pyproject.toml'))) {
ecosystem = 'python';
}
else if (fs.existsSync(path.join(projectDir, 'mix.exs'))) {
ecosystem = 'elixir';
}
else if (fs.existsSync(path.join(projectDir, 'Gemfile'))) {
ecosystem = 'ruby';
}
}
switch (ecosystem) {
case 'javascript':
return this.detectJavaScriptFramework(framework, projectDir);
case 'python':
return this.detectPythonFramework(framework, projectDir);
case 'elixir':
return this.detectElixirFramework(projectDir);
case 'ruby':
return this.detectRubyFramework(framework, projectDir);
default:
return null;
}
}
detectJavaScriptFramework(framework, projectDir = process.cwd()) {
const packageJson = this.readJsonFile(path.join(projectDir, 'package.json'));
if (!packageJson)
return null;
const testScript = packageJson.scripts?.test || '';
const devDeps = packageJson.devDependencies || {};
const deps = packageJson.dependencies || {};
if (framework === 'jest' || 'jest' in devDeps || testScript.includes('jest')) {
return {
ecosystem: 'javascript',
framework: 'jest',
testRunner: 'jest',
testCommand: 'npm test',
testFiles: ['test/', 'tests/', '__tests__/', '**/*.test.js', '**/*.test.ts'],
configFiles: ['jest.config.js', 'jest.config.json', 'package.json']
};
}
if (framework === 'mocha' || 'mocha' in devDeps || testScript.includes('mocha')) {
return {
ecosystem: 'javascript',
framework: 'mocha',
testRunner: 'mocha',
testCommand: 'npm test',
testFiles: ['test/', 'tests/', '**/*.test.js'],
configFiles: ['mocha.opts', '.mocharc.json', 'package.json']
};
}
return null;
}
detectPythonFramework(framework, projectDir = process.cwd()) {
if (framework === 'pytest' || fs.existsSync(path.join(projectDir, 'pytest.ini')) || fs.existsSync(path.join(projectDir, 'pyproject.toml'))) {
return {
ecosystem: 'python',
framework: 'pytest',
testRunner: 'pytest',
testCommand: 'pytest --cov',
testFiles: ['test/', 'tests/', '**/*_test.py', '**/test_*.py'],
configFiles: ['pytest.ini', 'pyproject.toml', 'setup.cfg']
};
}
return {
ecosystem: 'python',
framework: 'unittest',
testRunner: 'unittest',
testCommand: 'python -m unittest discover',
testFiles: ['test/', 'tests/', '**/*_test.py', '**/test_*.py'],
configFiles: []
};
}
detectElixirFramework(projectDir = process.cwd()) {
return {
ecosystem: 'elixir',
framework: 'exunit',
testRunner: 'mix test',
testCommand: 'mix test --cover',
testFiles: ['test/', '**/*_test.exs'],
configFiles: ['mix.exs', 'config/test.exs']
};
}
detectRubyFramework(framework, projectDir = process.cwd()) {
if (framework === 'rspec' || fs.existsSync(path.join(projectDir, 'spec/')) || fs.existsSync(path.join(projectDir, '.rspec'))) {
return {
ecosystem: 'ruby',
framework: 'rspec',
testRunner: 'rspec',
testCommand: 'rspec --format documentation',
testFiles: ['spec/', '**/*_spec.rb'],
configFiles: ['.rspec', 'spec/spec_helper.rb']
};
}
return {
ecosystem: 'ruby',
framework: 'minitest',
testRunner: 'minitest',
testCommand: 'ruby -Itest',
testFiles: ['test/', '**/*_test.rb', '**/test_*.rb'],
configFiles: []
};
}
async executeTests(detection, testPath, coverage = true, verbose = true, signal, projectDir = process.cwd()) {
const startTime = Date.now();
let command = detection.testCommand;
// Modify command based on parameters
if (testPath) {
command += ` ${testPath}`;
}
if (!coverage) {
command = command.replace(/--cov(erage)?/g, '').replace(/--cover/g, '');
}
if (verbose) {
if (detection.framework === 'jest') {
command += ' --verbose';
}
else if (detection.framework === 'pytest') {
command += ' -v';
}
}
// CRITICAL FIX: Dynamic timeout based on ecosystem
let timeout = 300000; // 5 minutes default
if (detection.ecosystem === 'elixir') {
timeout = 600000; // 10 minutes for Elixir test suites
console.log('๐ฎ Using extended timeout (10 minutes) for Elixir test suite');
}
try {
const { stdout, stderr } = await execAsync(command, {
signal,
timeout,
cwd: projectDir // CRITICAL FIX: Use the project directory, not MCP server directory
});
const duration = Date.now() - startTime;
const parsedResults = this.parseTestResults(stdout, stderr, detection.framework);
return {
success: parsedResults.testsFailed === 0,
exitCode: 0,
stdout,
stderr,
duration,
framework: detection.framework,
ecosystem: detection.ecosystem,
...parsedResults
};
}
catch (error) {
const duration = Date.now() - startTime;
const parsedResults = this.parseTestResults(error.stdout || '', error.stderr || '', detection.framework);
return {
success: false,
exitCode: error.code || 1,
stdout: error.stdout || '',
stderr: error.stderr || '',
duration,
framework: detection.framework,
ecosystem: detection.ecosystem,
...parsedResults
};
}
}
parseTestResults(stdout, stderr, framework) {
// Framework-specific parsing logic
switch (framework) {
case 'jest':
return this.parseJestResults(stdout, stderr);
case 'pytest':
return this.parsePytestResults(stdout, stderr);
case 'exunit':
return this.parseExUnitResults(stdout, stderr);
case 'rspec':
return this.parseRSpecResults(stdout, stderr);
default:
return { testsPassed: 0, testsFailed: 0, testsSkipped: 0 };
}
}
parseJestResults(stdout, stderr) {
// Jest result parsing
const passedMatch = stdout.match(/(\d+) passed/);
const failedMatch = stdout.match(/(\d+) failed/);
const skippedMatch = stdout.match(/(\d+) skipped/);
return {
testsPassed: passedMatch ? parseInt(passedMatch[1]) : 0,
testsFailed: failedMatch ? parseInt(failedMatch[1]) : 0,
testsSkipped: skippedMatch ? parseInt(skippedMatch[1]) : 0
};
}
parsePytestResults(stdout, stderr) {
// Pytest result parsing
const resultMatch = stdout.match(/(\d+) passed.*?(?:(\d+) failed)?.*?(?:(\d+) skipped)?/);
return {
testsPassed: resultMatch ? parseInt(resultMatch[1]) : 0,
testsFailed: resultMatch && resultMatch[2] ? parseInt(resultMatch[2]) : 0,
testsSkipped: resultMatch && resultMatch[3] ? parseInt(resultMatch[3]) : 0
};
}
parseExUnitResults(stdout, stderr) {
// ExUnit result parsing
const resultMatch = stdout.match(/(\d+) tests?, (\d+) failures?/);
const totalTests = resultMatch ? parseInt(resultMatch[1]) : 0;
const failures = resultMatch ? parseInt(resultMatch[2]) : 0;
return {
testsPassed: totalTests - failures,
testsFailed: failures,
testsSkipped: 0
};
}
parseRSpecResults(stdout, stderr) {
// RSpec result parsing
const resultMatch = stdout.match(/(\d+) examples?, (\d+) failures?/);
const totalExamples = resultMatch ? parseInt(resultMatch[1]) : 0;
const failures = resultMatch ? parseInt(resultMatch[2]) : 0;
return {
testsPassed: totalExamples - failures,
testsFailed: failures,
testsSkipped: 0
};
}
formatTestResults(result) {
const statusEmoji = result.success ? 'โ
' : 'โ';
const ecosystemEmoji = this.getEcosystemEmoji(result.ecosystem);
const totalTests = result.testsPassed + result.testsFailed + result.testsSkipped;
const successRate = totalTests > 0 ? Math.round((result.testsPassed / totalTests) * 100) : 0;
return `# ${statusEmoji} **Backend Test Results** ${ecosystemEmoji}
## ๐ **Test Summary**
- **Ecosystem**: ${result.ecosystem}
- **Framework**: ${result.framework}
- **Duration**: ${result.duration}ms
- **Exit Code**: ${result.exitCode}
- **Total Tests**: ${totalTests}
## ๐งช **Test Results**
- **โ
Passed**: ${result.testsPassed}
- **โ Failed**: ${result.testsFailed}
- **โญ๏ธ Skipped**: ${result.testsSkipped}
- **๐ Success Rate**: ${successRate}%
${result.coverage ? `## ๐ **Coverage Results**
- **Overall**: ${result.coverage.percentage}%
- **Lines**: ${result.coverage.lines.covered}/${result.coverage.lines.total}
- **Branches**: ${result.coverage.branches.covered}/${result.coverage.branches.total}
- **Functions**: ${result.coverage.functions.covered}/${result.coverage.functions.total}` : ''}
${result.success ? '๐ฏ **All backend tests passed successfully!**' : 'โ ๏ธ **Some backend tests failed - review output for details**'}
## ๐ **Full-Stack Integration**
โ
Backend testing complete - ready for frontend validation with ai-debug tools
๐ Use \`validate_full_stack_integration\` for comprehensive validation
## ๐ **Test Output Preview**
\`\`\`
${result.stdout.slice(0, 500)}${result.stdout.length > 500 ? '\n... (truncated)' : ''}
\`\`\`
${result.stderr ? `\n**Errors/Warnings:**\n\`\`\`\n${result.stderr.slice(0, 300)}${result.stderr.length > 300 ? '\n... (truncated)' : ''}\n\`\`\`` : ''}
`;
}
formatChangeMonitorResults(result) {
const changesText = result.detectedChanges.length === 0
? 'โ
No changes detected during monitoring period'
: result.detectedChanges.map(change => `- **${change.type}**: ${change.path} (${change.ecosystem || 'unknown'} ecosystem)`).join('\n');
const impactText = result.impactAnalysis
? `\n## ๐ฏ **Impact Analysis**
- **Risk Level**: ${result.impactAnalysis.riskLevel}
- **Affected Tests**: ${result.impactAnalysis.affectedTests.length}
- **Recommended Actions**: ${result.impactAnalysis.recommendedActions.length}
${result.impactAnalysis.potentialBreakingChanges.length > 0 ? `- **โ ๏ธ Potential Breaking Changes**: ${result.impactAnalysis.potentialBreakingChanges.length}` : ''}`
: '';
return `# ๐ **Code Change Monitor Results**
## ๐ **Monitoring Configuration**
- **Monitor ID**: ${result.monitorId}
- **Watched Paths**: ${result.watchedPaths.join(', ')}
- **Changes Detected**: ${result.detectedChanges.length}
## ๐ **Detected Changes**
${changesText}
${impactText}
## ๐ **Next Steps**
${result.detectedChanges.length > 0 ? '- Run \`run_backend_tests\` to validate changes\n- Use \`validate_full_stack_integration\` for comprehensive testing' : '- Continue monitoring or run tests to establish baseline'}
`;
}
detectFileEcosystem(filePath) {
const ext = path.extname(filePath).toLowerCase();
const basename = path.basename(filePath).toLowerCase();
if (ext === '.js' || ext === '.ts' || ext === '.json' || basename === 'package.json') {
return 'javascript';
}
if (ext === '.py' || basename === 'requirements.txt' || basename === 'pyproject.toml') {
return 'python';
}
if (ext === '.ex' || ext === '.exs' || basename === 'mix.exs') {
return 'elixir';
}
if (ext === '.rb' || basename === 'gemfile') {
return 'ruby';
}
return 'unknown';
}
async analyzeChangeImpact(changes) {
// Simplified impact analysis - can be enhanced with more sophisticated logic
const affectedTests = [];
const recommendedActions = [];
const potentialBreakingChanges = [];
let riskLevel = 'low';
// Analyze each change
changes.forEach(change => {
if (change.path.includes('test') || change.path.includes('spec')) {
affectedTests.push(change.path);
}
if (change.path.includes('config') || change.path.includes('setup')) {
riskLevel = 'high';
potentialBreakingChanges.push(change.path);
}
if (change.type === 'deleted') {
if (riskLevel === 'low') {
riskLevel = 'medium';
}
potentialBreakingChanges.push(change.path);
}
});
// Generate recommendations
if (changes.length > 0) {
recommendedActions.push('Run backend tests to validate changes');
}
if (riskLevel === 'high') {
recommendedActions.push('Run full-stack integration validation');
recommendedActions.push('Consider creating a backup before proceeding');
}
return {
affectedTests,
riskLevel,
recommendedActions,
potentialBreakingChanges
};
}
getEcosystemEmoji(ecosystem) {
switch (ecosystem) {
case 'javascript': return '๐จ';
case 'python': return '๐';
case 'elixir': return '๐ฃ';
case 'ruby': return '๐';
default: return '๐ง';
}
}
async generateDiagnostics(projectDir) {
const diagnostics = [];
diagnostics.push('## ๐ **Diagnostic Information**');
diagnostics.push(`**Project Directory**: \`${projectDir}\``);
// Check common project files
const projectFiles = [
'package.json', // JavaScript/TypeScript
'requirements.txt', // Python
'pyproject.toml', // Python (modern)
'pytest.ini', // Python (pytest)
'mix.exs', // Elixir
'Gemfile' // Ruby
];
diagnostics.push('\n**Project Files Found:**');
let foundFiles = 0;
for (const file of projectFiles) {
const exists = fs.existsSync(path.join(projectDir, file));
diagnostics.push(`- ${file}: ${exists ? 'โ
' : 'โ'}`);
if (exists)
foundFiles++;
}
// Check test directories
const testDirs = ['test/', 'tests/', 'spec/', '__tests__/'];
diagnostics.push('\n**Test Directories Found:**');
let testDirsFound = 0;
for (const dir of testDirs) {
const fullPath = path.join(projectDir, dir);
const exists = fs.existsSync(fullPath);
diagnostics.push(`- ${dir}: ${exists ? 'โ
' : 'โ'}`);
if (exists) {
testDirsFound++;
try {
const files = fs.readdirSync(fullPath);
const testFiles = files.filter(f => f.endsWith('_test.py') ||
f.endsWith('test_.py') ||
f.endsWith('.test.js') ||
f.endsWith('.test.ts') ||
f.endsWith('_spec.rb') ||
f.endsWith('_test.exs'));
if (testFiles.length > 0) {
diagnostics.push(` - Test files: ${testFiles.length} found`);
diagnostics.push(` - Examples: ${testFiles.slice(0, 3).join(', ')}`);
}
}
catch (error) {
diagnostics.push(` - Error reading directory: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
}
// Summary
diagnostics.push('\n**Summary:**');
if (foundFiles === 0) {
diagnostics.push('โ No project configuration files found');
diagnostics.push('๐ก Make sure you\'re in the correct project directory');
}
if (testDirsFound === 0) {
diagnostics.push('โ No test directories found');
diagnostics.push('๐ก Make sure your tests are in standard directories (test/, tests/, spec/, __tests__/)');
}
return diagnostics.join('\n');
}
readJsonFile(filePath) {
try {
if (fs.existsSync(filePath)) {
const content = fs.readFileSync(filePath, 'utf8');
return JSON.parse(content);
}
return null;
}
catch {
return null;
}
}
}
//# sourceMappingURL=backend-integration-handler.js.map