UNPKG

@memory-bank/mcp

Version:

Memory-enabled Co-Pilot (MCP) server for managing project documentation and context

419 lines 28.1 kB
// Import DIContainer for both type and value usage, then re-export it. import { DIContainer } from './DIContainer.js'; export { DIContainer }; import { MCPResponsePresenter } from '../../interface/presenters/MCPResponsePresenter.js'; import { ReadGlobalDocumentUseCase } from '../../application/usecases/global/ReadGlobalDocumentUseCase.js'; import { WriteGlobalDocumentUseCase } from '../../application/usecases/global/WriteGlobalDocumentUseCase.js'; import { ReadDocumentUseCase } from '../../application/usecases/common/ReadDocumentUseCase.js'; import { WriteDocumentUseCase } from '../../application/usecases/common/WriteDocumentUseCase.js'; import { BranchResolverService } from '../../application/services/BranchResolverService.js'; import { DocumentRepositorySelector } from '../../application/services/DocumentRepositorySelector.js'; import path from 'node:path'; // fs は削除されたため、不要になりました import { IndexService } from '../../infrastructure/index/IndexService.js'; import { FileSystemJsonDocumentRepository } from '../../infrastructure/repositories/file-system/FileSystemJsonDocumentRepository.js'; import { ReadRulesUseCase } from '../../application/usecases/common/ReadRulesUseCase.js'; import { ReadContextUseCase } from '../../application/usecases/common/ReadContextUseCase.js'; import { ReadBranchDocumentUseCase } from '../../application/usecases/branch/ReadBranchDocumentUseCase.js'; import { WriteBranchDocumentUseCase } from '../../application/usecases/branch/WriteBranchDocumentUseCase.js'; import { DocumentWriterService } from '../../application/services/DocumentWriterService.js'; // Import DocumentWriterService // import { DocumentRepositorySelector } from '../../application/services/DocumentRepositorySelector.js'; // Already imported above import { SearchDocumentsByTagsUseCase } from '../../application/usecases/common/SearchDocumentsByTagsUseCase.js'; import { UpdateTagIndexUseCase } from '../../application/usecases/common/UpdateTagIndexUseCase.js'; import { UpdateTagIndexUseCaseV2 } from '../../application/usecases/common/UpdateTagIndexUseCaseV2.js'; import { GetRecentBranchesUseCase } from '../../application/usecases/common/GetRecentBranchesUseCase.js'; import { CreateBranchCoreFilesUseCase } from '../../application/usecases/common/CreateBranchCoreFilesUseCase.js'; import { ReadJsonDocumentUseCase } from '../../application/usecases/json/ReadJsonDocumentUseCase.js'; import { WriteJsonDocumentUseCase } from '../../application/usecases/json/WriteJsonDocumentUseCase.js'; import { DeleteJsonDocumentUseCase } from '../../application/usecases/json/DeleteJsonDocumentUseCase.js'; import { SearchJsonDocumentsUseCase } from '../../application/usecases/json/SearchJsonDocumentsUseCase.js'; import { UpdateJsonIndexUseCase } from '../../application/usecases/json/UpdateJsonIndexUseCase.js'; import { TemplateService } from '../../application/templates/TemplateService.js'; // Added import import { FileSystemService } from '../../infrastructure/storage/FileSystemService.js'; import { ConfigProvider } from '../../infrastructure/config/ConfigProvider.js'; import { FileSystemGlobalMemoryBankRepository } from '../../infrastructure/repositories/file-system/FileSystemGlobalMemoryBankRepository.js'; import { FileSystemBranchMemoryBankRepository } from '../../infrastructure/repositories/file-system/FileSystemBranchMemoryBankRepository.js'; import { FileSystemTagIndexRepositoryV1Bridge } from '../../infrastructure/repositories/file-system/FileSystemTagIndexRepositoryV1Bridge.js'; // JsonTemplateLoaderRepositoryはdynamic importで使用するため、staticインポートはしない import { I18nServiceAdapter } from '../../infrastructure/i18n/I18nServiceAdapter.js'; // I18nService adapter for II18nProvider import { ContextController } from '../../interface/controllers/ContextController.js'; import { JsonResponsePresenter } from '../../interface/presenters/JsonResponsePresenter.js'; import { GlobalController } from '../../interface/controllers/GlobalController.js'; import { BranchController } from '../../interface/controllers/BranchController.js'; import { JsonBranchController } from '../../interface/controllers/json/JsonBranchController.js'; import { DocumentController } from '../../interface/controllers/DocumentController.js'; // Removed unused import: import { UseCaseFactory } from '../../factory/use-case-factory.js'; import { ReadBranchCoreFilesUseCase } from '../../application/usecases/index.js'; import { GitService } from '../../infrastructure/git/GitService.js'; /** * Register infrastructure services * @param container DI Container * @param options CLI options */ export async function registerInfrastructureServices(container, options) { // Register concrete class for FileSystemService container.register('fileSystemService', new FileSystemService()); const configProvider = new ConfigProvider(); container.register('configProvider', configProvider); logger.debug('Initializing ConfigProvider...'); // Log before config init await configProvider.initialize(options); logger.debug('ConfigProvider initialized.'); // Log after config init container.registerFactory('globalMemoryBankRepository', async () => { logger.debug('Resolving dependencies for globalMemoryBankRepository...'); const fileSystemService = await container.get('fileSystemService'); const configProvider = await container.get('configProvider'); logger.debug('Dependencies resolved for globalMemoryBankRepository.'); return new FileSystemGlobalMemoryBankRepository(fileSystemService, configProvider); }); container.registerFactory('branchMemoryBankRepository', async () => { logger.debug('Resolving dependencies for branchMemoryBankRepository...'); // Get config provider to resolve root path const configProvider = await container.get('configProvider'); logger.debug('Resolved configProvider for branchMemoryBankRepository.'); const config = configProvider.getConfig(); // Pass the root path (docsRoot) to the constructor return new FileSystemBranchMemoryBankRepository(config.docsRoot); }); container.registerFactory('tagIndexRepository', async () => { logger.debug('Resolving dependencies for tagIndexRepository...'); const configProvider = await container.get('configProvider'); logger.debug('Resolved configProvider for tagIndexRepository.'); const globalRepository = await container.get('globalMemoryBankRepository'); logger.debug('Resolved globalRepository for tagIndexRepository.'); const branchRepository = await container.get('branchMemoryBankRepository'); logger.debug('Resolved branchRepository for tagIndexRepository.'); const config = configProvider.getConfig(); const branchMemoryBankRoot = path.join(config.docsRoot, 'branch-memory-bank'); const globalMemoryBankPath = configProvider.getGlobalMemoryPath(); return new FileSystemTagIndexRepositoryV1Bridge(branchMemoryBankRoot, globalMemoryBankPath, branchRepository, globalRepository); }); container.registerFactory('indexService', async () => { logger.debug('Resolving dependencies for indexService...'); const fileSystemService = await container.get('fileSystemService'); logger.debug('Resolved fileSystemService for indexService.'); const configProvider = await container.get('configProvider'); logger.debug('Resolved configProvider for indexService.'); const config = configProvider.getConfig(); const indexRoot = path.join(config.docsRoot, 'indices'); return new IndexService(fileSystemService, indexRoot); }); container.registerFactory('i18nRepository', async () => { // Get the config provider to determine whether we need to use a custom path const configProvider = await container.get('configProvider'); const config = configProvider.getConfig(); let translationsDir; // Check if we have a custom docsRoot path (for tests) if (config.docsRoot) { // For tests, we use a path relative to docsRoot translationsDir = path.join(config.docsRoot, 'translations'); logger.debug(`Using docsRoot-based path for translations: ${translationsDir}`); } else { // For regular operation, use the dist path const projectRoot = process.cwd(); translationsDir = path.join(projectRoot, 'packages/mcp/dist/infrastructure/i18n/translations'); logger.debug(`Using standard path for translations: ${translationsDir}`); } logger.debug(`[DI] Initializing i18nRepository with translationsDir: ${translationsDir}`); const { FileI18nRepository } = await import('../../infrastructure/i18n/FileI18nRepository.js'); const i18nRepository = new FileI18nRepository(translationsDir); await i18nRepository.initialize(); // Let errors propagate return i18nRepository; }); container.registerFactory('branchJsonDocumentRepository', async () => { logger.debug('Resolving dependencies for branchJsonDocumentRepository...'); const fileSystemService = await container.get('fileSystemService'); logger.debug('Resolved fileSystemService for branchJsonDocumentRepository.'); const indexService = await container.get('indexService'); logger.debug('Resolved indexService for branchJsonDocumentRepository.'); const configProvider = await container.get('configProvider'); logger.debug('Resolved configProvider for branchJsonDocumentRepository.'); const config = configProvider.getConfig(); const branchJsonRoot = path.join(config.docsRoot, 'branch-json'); return new FileSystemJsonDocumentRepository(fileSystemService, indexService, branchJsonRoot); }); container.registerFactory('globalJsonDocumentRepository', async () => { logger.debug('Resolving dependencies for globalJsonDocumentRepository...'); const fileSystemService = await container.get('fileSystemService'); logger.debug('Resolved fileSystemService for globalJsonDocumentRepository.'); const indexService = await container.get('indexService'); logger.debug('Resolved indexService for globalJsonDocumentRepository.'); const configProvider = await container.get('configProvider'); logger.debug('Resolved configProvider for globalJsonDocumentRepository.'); const config = configProvider.getConfig(); const globalJsonRoot = path.join(config.docsRoot, 'global-json'); return new FileSystemJsonDocumentRepository(fileSystemService, indexService, globalJsonRoot); }); // 古いJSON依存のテンプレートローダーは完全に削除 // TS定義のみを使用する新しい実装に変更 container.register('gitService', new GitService()); logger.debug('GitService registered.'); } /** * Register application services * @param container DI Container */ export async function registerApplicationServices(container) { // Register DocumentRepositorySelector - new version with GitService container.registerFactory('documentRepositorySelector', async () => { const branchRepository = await container.get('branchMemoryBankRepository'); const globalRepository = await container.get('globalMemoryBankRepository'); const gitService = await container.get('gitService'); const configProvider = await container.get('configProvider'); return new DocumentRepositorySelector(branchRepository, globalRepository, gitService, configProvider); }); container.registerFactory('readGlobalDocumentUseCase', async () => { const readDocumentUseCase = await container.get('readDocumentUseCase'); return new ReadGlobalDocumentUseCase(readDocumentUseCase); }); // Add missing registration for writeGlobalDocumentUseCase container.registerFactory('writeGlobalDocumentUseCase', async () => { const writeDocumentUseCase = await container.get('writeDocumentUseCase'); return new WriteGlobalDocumentUseCase(writeDocumentUseCase); }); // Register JsonPatchService implementation (using rfc6902) container.registerFactory('jsonPatchService', async () => { // Import the Rfc6902JsonPatchAdapter class const { Rfc6902JsonPatchAdapter } = await import('../../domain/jsonpatch/Rfc6902JsonPatchAdapter.js'); return new Rfc6902JsonPatchAdapter(); // Use rfc6902 adapter }); // Register ヘルパークラス container.registerFactory('branchResolverService', async () => { const gitService = await container.get('gitService'); const configProvider = await container.get('configProvider'); return new BranchResolverService(gitService, configProvider); }); // Remove old version - already registered with new structure // Register 新しいユースケース container.registerFactory('readDocumentUseCase', async () => { const repositorySelector = await container.get('documentRepositorySelector'); return new ReadDocumentUseCase(repositorySelector); }); container.registerFactory('writeDocumentUseCase', async () => { const repositorySelector = await container.get('documentRepositorySelector'); const patchService = await container.get('jsonPatchService'); const documentWriterService = new DocumentWriterService(patchService); return new WriteDocumentUseCase(repositorySelector, documentWriterService); }); // Make the factory async and await the repository and patch service container.registerFactory('writeBranchDocumentUseCase', async () => { const writeDocumentUseCase = await container.get('writeDocumentUseCase'); return new WriteBranchDocumentUseCase(writeDocumentUseCase); }); // Add missing registration for readBranchDocumentUseCase container.registerFactory('readBranchDocumentUseCase', async () => { const readDocumentUseCase = await container.get('readDocumentUseCase'); return new ReadBranchDocumentUseCase(readDocumentUseCase); }); container.registerFactory('readRulesUseCase', async () => { const configProvider = await container.get('configProvider'); // Get configProvider within the factory scope const config = configProvider.getConfig(); const rulesDir = config.docsRoot; // Keep fallback path for now const templateLoader = await container.get('templateService'); // Get TemplateService ★コメント解除★ return new ReadRulesUseCase(rulesDir, templateLoader); // Pass templateLoader ★引数に追加★ }); container.registerFactory('readContextUseCase', async () => { const branchRepository = await container.get('branchMemoryBankRepository'); const globalRepository = await container.get('globalMemoryBankRepository'); // --- Resolve additional dependencies --- const gitService = await container.get('gitService'); const configProvider = await container.get('configProvider'); // --- Pass all dependencies to the constructor --- return new ReadContextUseCase(branchRepository, globalRepository, gitService, configProvider); }); // Register the updated SearchDocumentsByTagsUseCase container.registerFactory('searchDocumentsByTagsUseCase', async () => { const fileSystemService = await container.get('fileSystemService'); return new SearchDocumentsByTagsUseCase(fileSystemService); }); container.registerFactory('updateTagIndexUseCase', async () => { const globalRepository = await container.get('globalMemoryBankRepository'); const branchRepository = await container.get('branchMemoryBankRepository'); return new UpdateTagIndexUseCase(globalRepository, branchRepository); }); container.registerFactory('updateTagIndexUseCaseV2', async () => { const globalRepository = await container.get('globalMemoryBankRepository'); const branchRepository = await container.get('branchMemoryBankRepository'); const tagIndexRepository = await container.get('tagIndexRepository'); return new UpdateTagIndexUseCaseV2(globalRepository, branchRepository, tagIndexRepository); }); container.registerFactory('readJsonDocumentUseCase', async () => { const branchJsonRepo = await container.get('branchJsonDocumentRepository'); const globalJsonRepo = await container.get('globalJsonDocumentRepository'); return new ReadJsonDocumentUseCase(branchJsonRepo, globalJsonRepo); }); container.registerFactory('writeJsonDocumentUseCase', async () => { const branchJsonRepo = await container.get('branchJsonDocumentRepository'); const globalJsonRepo = await container.get('globalJsonDocumentRepository'); const indexService = await container.get('indexService'); return new WriteJsonDocumentUseCase(branchJsonRepo, indexService, globalJsonRepo); }); container.registerFactory('deleteJsonDocumentUseCase', async () => { const branchJsonRepo = await container.get('branchJsonDocumentRepository'); const globalJsonRepo = await container.get('globalJsonDocumentRepository'); const indexService = await container.get('indexService'); return new DeleteJsonDocumentUseCase(branchJsonRepo, indexService, globalJsonRepo); }); container.registerFactory('searchJsonDocumentsUseCase', async () => { const branchJsonRepo = await container.get('branchJsonDocumentRepository'); const globalJsonRepo = await container.get('globalJsonDocumentRepository'); return new SearchJsonDocumentsUseCase(branchJsonRepo, globalJsonRepo); }); container.registerFactory('updateJsonIndexUseCase', async () => { const branchJsonRepo = await container.get('branchJsonDocumentRepository'); const globalJsonRepo = await container.get('globalJsonDocumentRepository'); const indexService = await container.get('indexService'); return new UpdateJsonIndexUseCase(branchJsonRepo, indexService, globalJsonRepo); }); container.registerFactory('getRecentBranchesUseCase', async () => { const branchRepository = await container.get('branchMemoryBankRepository'); return new GetRecentBranchesUseCase(branchRepository); }); container.registerFactory('readBranchCoreFilesUseCase', async () => { const branchRepository = await container.get('branchMemoryBankRepository'); return new ReadBranchCoreFilesUseCase(branchRepository); }); container.registerFactory('createBranchCoreFilesUseCase', async () => { const branchRepository = await container.get('branchMemoryBankRepository'); return new CreateBranchCoreFilesUseCase(branchRepository); }); // Register I18nService using registerFactory (it behaves as singleton) container.registerFactory('i18nService', async () => { const i18nRepository = await container.get('i18nRepository'); const { I18nService } = await import('../../application/i18n/I18nService.js'); const i18nService = new I18nService(i18nRepository); await i18nService.loadAllTranslations(); return i18nService; }); // Register TemplateRepository after I18nService is initialized // TS定義を最優先し、jsonディレクトリが存在しなくても問題ないよう修正 container.registerFactory('templateRepository', async () => { logger.debug('Resolving dependencies for templateRepository...'); // JsonTemplateLoaderRepositoryを使用する // 直接TypeScript定義からテンプレートをロードするため、ディレクトリパスは不要 const i18nService = await container.get('i18nService'); // I18nServiceAdapterを使用してII18nProviderのインターフェースを満たす const i18nProvider = new I18nServiceAdapter(i18nService); // 新しいRepositoryクラスをインポート const { JsonTemplateLoaderRepository } = await import('../../infrastructure/templates/JsonTemplateLoaderRepository.js'); const templateRepository = new JsonTemplateLoaderRepository(i18nProvider); await templateRepository.initialize(); logger.debug('templateRepository (JsonTemplateLoaderRepository) initialized.'); return templateRepository; }); // Register TemplateService container.registerFactory('templateService', async () => { logger.debug('Resolving dependencies for templateService...'); const templateRepository = await container.get('templateRepository'); logger.debug('Resolved templateRepository for templateService.'); return new TemplateService(templateRepository); }); } /** * Register interface services * @param container DI Container */ export async function registerInterfaceServices(container) { container.register('mcpResponsePresenter', new MCPResponsePresenter()); container.register('jsonResponsePresenter', new JsonResponsePresenter()); // Register DocumentController container.registerFactory('documentController', async () => { const readBranchDocumentUseCase = await container.get('readBranchDocumentUseCase'); const writeBranchDocumentUseCase = await container.get('writeBranchDocumentUseCase'); const readGlobalDocumentUseCase = await container.get('readGlobalDocumentUseCase'); const writeGlobalDocumentUseCase = await container.get('writeGlobalDocumentUseCase'); // const repositorySelector = await container.get<DocumentRepositorySelector>('documentRepositorySelector'); // Not used in the current implementation const presenter = await container.get('mcpResponsePresenter'); const configProvider = await container.get('configProvider'); return new DocumentController(readBranchDocumentUseCase, writeBranchDocumentUseCase, readGlobalDocumentUseCase, writeGlobalDocumentUseCase, // repositorySelector, // Not used in the current implementation presenter, configProvider); }); container.registerFactory('contextController', async () => { const readContextUseCase = await container.get('readContextUseCase'); const readRulesUseCase = await container.get('readRulesUseCase'); return new ContextController(readContextUseCase, readRulesUseCase); }); container.registerFactory('jsonBranchController', async () => { const readJsonDocumentUseCase = await container.get('readJsonDocumentUseCase'); const writeJsonDocumentUseCase = await container.get('writeJsonDocumentUseCase'); const deleteJsonDocumentUseCase = await container.get('deleteJsonDocumentUseCase'); const searchJsonDocumentsUseCase = await container.get('searchJsonDocumentsUseCase'); const updateJsonIndexUseCase = await container.get('updateJsonIndexUseCase'); const getRecentBranchesUseCase = await container.get('getRecentBranchesUseCase'); const presenter = await container.get('mcpResponsePresenter'); return new JsonBranchController(readJsonDocumentUseCase, writeJsonDocumentUseCase, deleteJsonDocumentUseCase, searchJsonDocumentsUseCase, updateJsonIndexUseCase, getRecentBranchesUseCase, presenter); }); container.registerFactory('globalController', async () => { const readGlobalDocumentUseCase = await container.get('readGlobalDocumentUseCase'); const writeGlobalDocumentUseCase = await container.get('writeGlobalDocumentUseCase'); // Inject both old and new search use cases for now const searchDocumentsByTagsUseCase = await container.get('searchDocumentsByTagsUseCase'); // Inject the new one (registered with the same key for now) const updateTagIndexUseCase = await container.get('updateTagIndexUseCase'); const presenter = await container.get('mcpResponsePresenter'); const configProvider = await container.get('configProvider'); // Get ConfigProvider // Optional dependencies const updateTagIndexUseCaseV2 = await container.get('updateTagIndexUseCaseV2'); const readJsonDocumentUseCase = await container.get('readJsonDocumentUseCase'); const writeJsonDocumentUseCase = await container.get('writeJsonDocumentUseCase'); const deleteJsonDocumentUseCase = await container.get('deleteJsonDocumentUseCase'); const searchJsonDocumentsUseCase = await container.get('searchJsonDocumentsUseCase'); const updateJsonIndexUseCaseJson = await container.get('updateJsonIndexUseCase'); // Renamed variable return new GlobalController(readGlobalDocumentUseCase, writeGlobalDocumentUseCase, searchDocumentsByTagsUseCase, updateTagIndexUseCase, presenter, configProvider, { updateTagIndexUseCaseV2, readJsonDocumentUseCase, writeJsonDocumentUseCase, deleteJsonDocumentUseCase, searchJsonDocumentsUseCase, updateJsonIndexUseCase: updateJsonIndexUseCaseJson }); }); container.registerFactory('branchController', async () => { const readBranchDocumentUseCase = await container.get('readBranchDocumentUseCase'); const writeBranchDocumentUseCase = await container.get('writeBranchDocumentUseCase'); // Inject IConfigProvider here as well const configProvider = await container.get('configProvider'); const searchDocumentsByTagsUseCase = await container.get('searchDocumentsByTagsUseCase'); const updateTagIndexUseCase = await container.get('updateTagIndexUseCase'); const getRecentBranchesUseCase = await container.get('getRecentBranchesUseCase'); const readBranchCoreFilesUseCase = await container.get('readBranchCoreFilesUseCase'); const createBranchCoreFilesUseCase = await container.get('createBranchCoreFilesUseCase'); const presenter = await container.get('mcpResponsePresenter'); return new BranchController(readBranchDocumentUseCase, writeBranchDocumentUseCase, searchDocumentsByTagsUseCase, updateTagIndexUseCase, getRecentBranchesUseCase, readBranchCoreFilesUseCase, createBranchCoreFilesUseCase, presenter, configProvider // Pass configProvider to constructor ); }); } /** * Initialize repositories * @param container DI Container */ export async function initializeRepositories(container) { const globalRepository = await container.get('globalMemoryBankRepository'); await globalRepository.initialize(); } /** * Setup DI container and register all services * @param options CLI options * @returns Configured DI container */ // import { logger } from '@/shared/utils/logger.js'; // Use alias for logger import - Re-importing logger where needed import { logger } from '../../shared/utils/logger.js'; export async function setupContainer(options) { logger.info('Setting up DI container...'); // Restore original log level and message const container = new DIContainer(); logger.debug('Registering infrastructure services...'); await registerInfrastructureServices(container, options); logger.debug('Infrastructure services registered.'); logger.debug('Registering application services...'); await registerApplicationServices(container); // Restore await logger.debug('Application services registered.'); logger.debug('Registering interface services...'); await registerInterfaceServices(container); // Restore await logger.debug('Interface services registered.'); logger.debug('Initializing repositories...'); await initializeRepositories(container); // Restore await and call logger.debug('Repositories initialized.'); // Restore log logger.info('DI container setup complete'); // Restore original log level and message return container; } //# sourceMappingURL=providers.js.map