vibe-coder-mcp
Version:
Production-ready MCP server with complete agent integration, multi-transport support, and comprehensive development automation tools for AI-assisted workflows.
151 lines (150 loc) • 5.9 kB
JavaScript
import * as path from 'path';
import * as fs from 'fs';
import { DependencyCruiserAdapter } from './dependencyCruiserAdapter.js';
import { ExtendedPythonImportResolver } from './extendedPythonImportResolver.js';
import { ClangdAdapter } from './clangdAdapter.js';
import { SemgrepAdapter } from './semgrepAdapter.js';
import logger from '../../../logger.js';
export class ImportResolverFactory {
options;
dependencyCruiserAdapter = null;
pythonImportResolver = null;
clangdAdapter = null;
semgrepAdapter = null;
adapterLastUsed = new Map();
cleanupTimer = null;
ADAPTER_TTL = 10 * 60 * 1000;
constructor(options) {
this.options = options;
this.scheduleCleanup();
}
getImportResolver(filePath) {
const extension = path.extname(filePath).toLowerCase();
if (['.js', '.jsx', '.ts', '.tsx'].includes(extension)) {
return this.getDependencyCruiserAdapter();
}
if (['.py', '.pyw'].includes(extension)) {
try {
const absolutePath = path.isAbsolute(filePath) ? filePath : path.resolve(this.options.allowedDir, filePath);
const stats = fs.statSync(absolutePath);
if (stats.isFile()) {
return this.getPythonImportResolver();
}
}
catch (error) {
logger.debug({ filePath, error: error.message }, 'Error checking Python file');
return null;
}
}
if (['.c', '.h', '.cpp', '.hpp', '.cc', '.cxx'].includes(extension)) {
return this.getClangdAdapter();
}
if (!this.options.disableSemgrepFallback) {
return this.getSemgrepAdapter();
}
logger.debug({ filePath, extension }, 'No enhanced import resolver available for this file type');
return null;
}
getDependencyCruiserAdapter() {
this.adapterLastUsed.set('dependencyCruiser', Date.now());
if (!this.dependencyCruiserAdapter) {
this.dependencyCruiserAdapter = new DependencyCruiserAdapter(this.options.allowedDir, this.options.outputDir);
this.scheduleCleanup();
}
return this.dependencyCruiserAdapter;
}
getPythonImportResolver() {
this.adapterLastUsed.set('pythonImportResolver', Date.now());
if (!this.pythonImportResolver) {
this.pythonImportResolver = new ExtendedPythonImportResolver(this.options.allowedDir, this.options.outputDir);
this.scheduleCleanup();
}
return this.pythonImportResolver;
}
getClangdAdapter() {
this.adapterLastUsed.set('clangdAdapter', Date.now());
if (!this.clangdAdapter) {
this.clangdAdapter = new ClangdAdapter(this.options.allowedDir, this.options.outputDir);
this.scheduleCleanup();
}
return this.clangdAdapter;
}
getSemgrepAdapter() {
this.adapterLastUsed.set('semgrepAdapter', Date.now());
if (!this.semgrepAdapter) {
this.semgrepAdapter = new SemgrepAdapter(this.options.allowedDir, this.options.outputDir);
this.scheduleCleanup();
}
return this.semgrepAdapter;
}
scheduleCleanup() {
if (!this.cleanupTimer) {
this.cleanupTimer = setTimeout(() => {
this.cleanupUnusedAdapters();
this.cleanupTimer = null;
}, 5 * 60 * 1000);
}
}
cleanupUnusedAdapters() {
const now = Date.now();
let unloadedCount = 0;
if (this.dependencyCruiserAdapter &&
this.adapterLastUsed.has('dependencyCruiser') &&
now - this.adapterLastUsed.get('dependencyCruiser') > this.ADAPTER_TTL) {
this.dependencyCruiserAdapter.dispose();
this.dependencyCruiserAdapter = null;
unloadedCount++;
}
if (this.pythonImportResolver &&
this.adapterLastUsed.has('pythonImportResolver') &&
now - this.adapterLastUsed.get('pythonImportResolver') > this.ADAPTER_TTL) {
this.pythonImportResolver.dispose();
this.pythonImportResolver = null;
unloadedCount++;
}
if (this.clangdAdapter &&
this.adapterLastUsed.has('clangdAdapter') &&
now - this.adapterLastUsed.get('clangdAdapter') > this.ADAPTER_TTL) {
this.clangdAdapter.dispose();
this.clangdAdapter = null;
unloadedCount++;
}
if (this.semgrepAdapter &&
this.adapterLastUsed.has('semgrepAdapter') &&
now - this.adapterLastUsed.get('semgrepAdapter') > this.ADAPTER_TTL) {
this.semgrepAdapter.dispose();
this.semgrepAdapter = null;
unloadedCount++;
}
if (unloadedCount > 0) {
logger.info(`Unloaded ${unloadedCount} unused import resolvers`);
}
if (this.dependencyCruiserAdapter || this.pythonImportResolver ||
this.clangdAdapter || this.semgrepAdapter) {
this.scheduleCleanup();
}
}
dispose() {
if (this.cleanupTimer) {
clearTimeout(this.cleanupTimer);
this.cleanupTimer = null;
}
if (this.dependencyCruiserAdapter) {
this.dependencyCruiserAdapter.dispose();
this.dependencyCruiserAdapter = null;
}
if (this.pythonImportResolver) {
this.pythonImportResolver.dispose();
this.pythonImportResolver = null;
}
if (this.clangdAdapter) {
this.clangdAdapter.dispose();
this.clangdAdapter = null;
}
if (this.semgrepAdapter) {
this.semgrepAdapter.dispose();
this.semgrepAdapter = null;
}
logger.debug('ImportResolverFactory disposed');
}
}