vibe-coder-mcp
Version:
Production-ready MCP server with complete agent integration, multi-transport support, and comprehensive development automation tools for AI-assisted workflows.
232 lines (231 loc) • 9 kB
JavaScript
import logger from '../../../logger.js';
import { AppError } from '../../../utils/errors.js';
export class DIContainer {
services = new Map();
resolving = new Set();
scopedInstances = new Map();
register(token, factory, lifecycle = 'singleton', dependencies = []) {
const tokenStr = typeof token === 'string' ? token : String(token);
if (this.services.has(tokenStr)) {
logger.warn(`Service ${tokenStr} is already registered. Overwriting.`);
}
this.services.set(tokenStr, {
factory,
lifecycle,
dependencies
});
logger.debug(`Registered service: ${tokenStr} with lifecycle: ${lifecycle}`);
}
singleton(token, factory, dependencies = []) {
this.register(token, factory, 'singleton', dependencies);
}
transient(token, factory, dependencies = []) {
this.register(token, factory, 'transient', dependencies);
}
scoped(token, factory, dependencies = []) {
this.register(token, factory, 'scoped', dependencies);
}
async resolve(token) {
const tokenStr = typeof token === 'string' ? token : String(token);
return this.resolveInternal(tokenStr);
}
resolveSync(token) {
const tokenStr = typeof token === 'string' ? token : String(token);
return this.resolveInternalSync(tokenStr);
}
resolveInternalSync(token) {
if (this.resolving.has(token)) {
const cycle = Array.from(this.resolving).join(' -> ') + ' -> ' + token;
throw new AppError(`Circular dependency detected: ${cycle}`, { cycle, token, errorCode: 'CIRCULAR_DEPENDENCY_ERROR' });
}
const registration = this.services.get(token);
if (!registration) {
throw new AppError(`Service not registered: ${token}`, { token, errorCode: 'SERVICE_NOT_FOUND_ERROR' });
}
switch (registration.lifecycle) {
case 'singleton':
if (registration.instance) {
return registration.instance;
}
break;
case 'scoped':
if (this.scopedInstances.has(token)) {
return this.scopedInstances.get(token);
}
break;
case 'transient':
break;
}
this.resolving.add(token);
try {
const instance = registration.factory(this);
if (instance instanceof Promise) {
throw new AppError(`Service ${token} requires async resolution. Use resolve() instead.`, { token, errorCode: 'SYNC_RESOLUTION_ERROR' });
}
switch (registration.lifecycle) {
case 'singleton':
registration.instance = instance;
break;
case 'scoped':
this.scopedInstances.set(token, instance);
break;
case 'transient':
break;
}
logger.debug(`Resolved service synchronously: ${token}`);
return instance;
}
finally {
this.resolving.delete(token);
}
}
async resolveInternal(token) {
if (this.resolving.has(token)) {
const cycle = Array.from(this.resolving).join(' -> ') + ' -> ' + token;
throw new AppError(`Circular dependency detected: ${cycle}`, { cycle, token, errorCode: 'CIRCULAR_DEPENDENCY_ERROR' });
}
const registration = this.services.get(token);
if (!registration) {
throw new AppError(`Service not registered: ${token}`, { token, errorCode: 'SERVICE_NOT_FOUND_ERROR' });
}
switch (registration.lifecycle) {
case 'singleton':
if (registration.instance) {
return registration.instance;
}
break;
case 'scoped':
if (this.scopedInstances.has(token)) {
return this.scopedInstances.get(token);
}
break;
case 'transient':
break;
}
this.resolving.add(token);
try {
const instance = await registration.factory(this);
switch (registration.lifecycle) {
case 'singleton':
registration.instance = instance;
break;
case 'scoped':
this.scopedInstances.set(token, instance);
break;
case 'transient':
break;
}
logger.debug(`Resolved service: ${token}`);
return instance;
}
finally {
this.resolving.delete(token);
}
}
isRegistered(token) {
const tokenStr = typeof token === 'string' ? token : String(token);
return this.services.has(tokenStr);
}
getRegisteredServices() {
return Array.from(this.services.keys());
}
clearScoped() {
this.scopedInstances.clear();
logger.debug('Cleared scoped service instances');
}
dispose() {
for (const [token, registration] of this.services) {
if (registration.instance && typeof registration.instance.dispose === 'function') {
try {
registration.instance.dispose();
logger.debug(`Disposed service: ${token}`);
}
catch (error) {
logger.error(`Error disposing service ${token}:`, error);
}
}
}
for (const registration of this.services.values()) {
registration.instance = undefined;
}
this.scopedInstances.clear();
logger.debug('Disposed all service instances');
}
validateDependencyGraph() {
const visited = new Set();
const visiting = new Set();
const visit = (token) => {
if (visiting.has(token)) {
const cycle = Array.from(visiting).join(' -> ') + ' -> ' + token;
throw new AppError(`Circular dependency detected in registration: ${cycle}`, { cycle, token, errorCode: 'CIRCULAR_DEPENDENCY_ERROR' });
}
if (visited.has(token)) {
return;
}
const registration = this.services.get(token);
if (!registration) {
return;
}
visiting.add(token);
for (const dependency of registration.dependencies || []) {
visit(dependency);
}
visiting.delete(token);
visited.add(token);
};
for (const token of this.services.keys()) {
visit(token);
}
logger.debug('Dependency graph validation passed');
}
getDependencyGraph() {
const lines = [];
for (const [token, registration] of this.services) {
const deps = registration.dependencies || [];
const lifecycle = registration.lifecycle;
lines.push(`${token} (${lifecycle}): [${deps.join(', ')}]`);
}
return lines.join('\n');
}
}
export function createServiceToken(name) {
return name;
}
let globalContainer = null;
export function getContainer() {
if (!globalContainer) {
globalContainer = new DIContainer();
}
return globalContainer;
}
export function setContainer(container) {
globalContainer = container;
}
export function resetContainer() {
if (globalContainer) {
globalContainer.dispose();
}
globalContainer = null;
}
export const ServiceTokens = {
StorageManager: createServiceToken('StorageManager'),
ConfigLoader: createServiceToken('ConfigLoader'),
IdGenerator: createServiceToken('IdGenerator'),
TaskOperations: createServiceToken('TaskOperations'),
ProjectOperations: createServiceToken('ProjectOperations'),
DependencyOperations: createServiceToken('DependencyOperations'),
DecompositionService: createServiceToken('DecompositionService'),
EpicService: createServiceToken('EpicService'),
AgentOrchestrator: createServiceToken('AgentOrchestrator'),
RDDEngine: createServiceToken('RDDEngine'),
ContextEnrichmentService: createServiceToken('ContextEnrichmentService'),
DependencyValidator: createServiceToken('DependencyValidator'),
FileUtils: createServiceToken('FileUtils'),
TaskFileManager: createServiceToken('TaskFileManager'),
AtomicDetector: createServiceToken('AtomicDetector'),
UnifiedLifecycleManager: createServiceToken('UnifiedLifecycleManager'),
UnifiedTaskExecutionEngine: createServiceToken('UnifiedTaskExecutionEngine'),
UnifiedStorageEngine: createServiceToken('UnifiedStorageEngine'),
UnifiedSecurityEngine: createServiceToken('UnifiedSecurityEngine'),
UnifiedOrchestrationEngine: createServiceToken('UnifiedOrchestrationEngine')
};