vibe-coder-mcp
Version:
Production-ready MCP server with complete agent integration, multi-transport support, and comprehensive development automation tools for AI-assisted workflows.
144 lines (143 loc) • 5.16 kB
JavaScript
import logger from '../logger.js';
export class ImportCycleBreaker {
static importStack = new Set();
static importHistory = new Map();
static IMPORT_TIMEOUT = 5000;
static HISTORY_CLEANUP_INTERVAL = 60000;
static cleanupTimer;
static async safeImport(modulePath, importName) {
const importKey = importName ? `${modulePath}:${importName}` : modulePath;
if (this.importStack.has(importKey)) {
logger.warn({
modulePath,
importName,
currentStack: Array.from(this.importStack)
}, 'Circular import detected, using fallback');
this.recordImportAttempt(importKey, false);
return null;
}
const recentAttempt = this.importHistory.get(importKey);
if (recentAttempt && !recentAttempt.success &&
(Date.now() - recentAttempt.timestamp) < this.IMPORT_TIMEOUT) {
logger.debug({
modulePath,
importName,
lastAttempt: recentAttempt.timestamp
}, 'Skipping recent failed import attempt');
return null;
}
this.importStack.add(importKey);
try {
logger.debug({ modulePath, importName }, 'Starting safe import');
const importPromise = this.performImport(modulePath, importName);
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error('Import timeout')), this.IMPORT_TIMEOUT);
});
const module = await Promise.race([importPromise, timeoutPromise]);
logger.debug({ modulePath, importName }, 'Safe import completed successfully');
this.recordImportAttempt(importKey, true);
return module;
}
catch (error) {
logger.warn({
err: error,
modulePath,
importName
}, 'Safe import failed');
this.recordImportAttempt(importKey, false);
return null;
}
finally {
this.importStack.delete(importKey);
this.startCleanupTimer();
}
}
static async performImport(modulePath, importName) {
const module = await import(modulePath);
if (importName) {
if (!(importName in module)) {
throw new Error(`Export '${importName}' not found in module '${modulePath}'`);
}
return module[importName];
}
return module;
}
static recordImportAttempt(importKey, success) {
this.importHistory.set(importKey, {
timestamp: Date.now(),
success
});
}
static startCleanupTimer() {
if (this.cleanupTimer) {
return;
}
this.cleanupTimer = setTimeout(() => {
this.cleanupImportHistory();
this.cleanupTimer = undefined;
}, this.HISTORY_CLEANUP_INTERVAL);
}
static cleanupImportHistory() {
const now = Date.now();
const cutoff = now - (this.HISTORY_CLEANUP_INTERVAL * 2);
let cleanedCount = 0;
for (const [key, entry] of this.importHistory.entries()) {
if (entry.timestamp < cutoff) {
this.importHistory.delete(key);
cleanedCount++;
}
}
if (cleanedCount > 0) {
logger.debug({ cleanedCount }, 'Cleaned up old import history entries');
}
}
static getCurrentImportStack() {
return Array.from(this.importStack);
}
static getImportHistory() {
const history = {};
for (const [key, value] of this.importHistory.entries()) {
history[key] = value;
}
return history;
}
static clearAll() {
this.importStack.clear();
this.importHistory.clear();
if (this.cleanupTimer) {
clearTimeout(this.cleanupTimer);
this.cleanupTimer = undefined;
}
}
static isImportInProgress(modulePath, importName) {
const importKey = importName ? `${modulePath}:${importName}` : modulePath;
return this.importStack.has(importKey);
}
static getStatistics() {
let successfulImports = 0;
let failedImports = 0;
for (const entry of this.importHistory.values()) {
if (entry.success) {
successfulImports++;
}
else {
failedImports++;
}
}
return {
currentImports: this.importStack.size,
historyEntries: this.importHistory.size,
successfulImports,
failedImports
};
}
static createModuleImporter(modulePath) {
return async (importName) => {
return this.safeImport(modulePath, importName);
};
}
static async safeBatchImport(imports) {
const results = await Promise.allSettled(imports.map(({ modulePath, importName }) => this.safeImport(modulePath, importName)));
return results.map(result => result.status === 'fulfilled' ? result.value : null);
}
}