UNPKG

@memory-bank/mcp

Version:

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

195 lines 7.3 kB
import { promises as fs } from 'node:fs'; import path from 'node:path'; import { BranchInfo } from '../../domain/entities/BranchInfo.js'; import { InfrastructureError, InfrastructureErrorCodes, } from '../../shared/errors/InfrastructureError.js'; /** * Implementation of configuration provider */ export class ConfigProvider { config = null; /** * Initialize configuration * @param options CLI options * @returns Promise resolving to workspace config */ async initialize(options) { try { if (this.config) return this.config; // resolveDocsRoot がパスと解決方法を返すように変更 const { resolvedPath: docsRoot, resolvedBy } = await this.resolveDocsRoot(options); const language = await this.resolveLanguage(options); // 解決方法が 'default' 以外ならプロジェクトモードと判断 const isProjectMode = resolvedBy !== 'default'; this.config = { docsRoot, verbose: options?.verbose ?? false, language, isProjectMode, // isProjectMode を設定 }; await this.ensureDirectories(); return this.config; } catch (error) { if (error instanceof InfrastructureError || error instanceof DomainError) { throw error; } throw new InfrastructureError(InfrastructureErrorCodes.CONFIGURATION_ERROR, `Failed to initialize configuration: ${error.message}`, { originalError: error }); } } /** * Get current configuration * @returns Workspace config */ getConfig() { if (!this.config) { throw new InfrastructureError(InfrastructureErrorCodes.CONFIGURATION_ERROR, 'Configuration not initialized'); } return this.config; } /** * Get global memory bank path * @returns Global memory bank path */ getGlobalMemoryPath() { const config = this.getConfig(); return path.join(config.docsRoot, 'global-memory-bank'); } /** * Get branch memory bank path * @param branchName Branch name * @returns Branch memory bank path */ getBranchMemoryPath(branchName) { try { const config = this.getConfig(); const branchInfo = BranchInfo.create(branchName); return path.join(config.docsRoot, 'branch-memory-bank', branchInfo.safeName); } catch (error) { if (error instanceof DomainError) { throw error; } throw new InfrastructureError(InfrastructureErrorCodes.CONFIGURATION_ERROR, `Invalid branch name: ${branchName}`, { originalError: error }); } } /** * Get language setting * @returns Language setting */ getLanguage() { return this.getConfig().language; } /** * Resolve docs root directory * @param options CLI options * @returns Promise resolving to an object containing the resolved path and how it was resolved ('cli', 'env', or 'default') */ // 戻り値の型を変更 async resolveDocsRoot(options) { try { if (options?.docsRoot) { const resolvedPath = await this.validatePath(options.docsRoot); return { resolvedPath, resolvedBy: 'cli' }; } if (process.env.MEMORY_BANK_ROOT) { const resolvedPath = await this.validatePath(process.env.MEMORY_BANK_ROOT); return { resolvedPath, resolvedBy: 'env' }; } if (process.env.DOCS_ROOT) { const resolvedPath = await this.validatePath(process.env.DOCS_ROOT); return { resolvedPath, resolvedBy: 'env' }; } // デフォルトの場合 const resolvedPath = await this.validatePath('./docs'); return { resolvedPath, resolvedBy: 'default' }; } catch (error) { throw new InfrastructureError(InfrastructureErrorCodes.CONFIGURATION_ERROR, `Invalid docs root: ${error.message}`, { originalError: error }); } } /** * Resolve language setting * @param options CLI options * @returns Promise resolving to language */ async resolveLanguage(options) { try { if (options?.language) { return this.validateLanguage(options.language); } if (process.env.MEMORY_BANK_LANGUAGE) { return this.validateLanguage(process.env.MEMORY_BANK_LANGUAGE); } try { const packageJsonPath = path.join(process.cwd(), 'package.json'); const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf-8')); if (packageJson.config?.language) { return this.validateLanguage(packageJson.config.language); } } catch { // Ignore errors reading package.json } return 'en'; } catch (error) { throw new InfrastructureError(InfrastructureErrorCodes.CONFIGURATION_ERROR, `Invalid language: ${error.message}`, { originalError: error }); } } /** * Validate language * @param language Language to validate * @returns Valid language */ validateLanguage(language) { if (language !== 'en' && language !== 'ja' && language !== 'zh') { throw new InfrastructureError(InfrastructureErrorCodes.CONFIGURATION_ERROR, `Invalid language: ${language}. Supported languages are 'en', 'ja', and 'zh'.`); } return language; } /** * Validate and normalize path * @param p Path to validate * @returns Promise resolving to validated path */ async validatePath(p) { try { if (!p) { throw new Error('Path cannot be empty'); } const absolutePath = path.resolve(p); try { await fs.access(absolutePath); } catch { await fs.mkdir(absolutePath, { recursive: true }); } return absolutePath; } catch (error) { throw new InfrastructureError(InfrastructureErrorCodes.CONFIGURATION_ERROR, `Invalid path: ${p}`, { originalError: error }); } } /** * Ensure required directories exist * @returns Promise resolving when directories are created */ async ensureDirectories() { try { const config = this.getConfig(); const dirs = [ this.getGlobalMemoryPath(), path.join(config.docsRoot, 'branch-memory-bank'), ]; for (const dir of dirs) { await fs.mkdir(dir, { recursive: true }); } } catch (error) { throw new InfrastructureError(InfrastructureErrorCodes.FILE_SYSTEM_ERROR, `Failed to create directories: ${error.message}`, { originalError: error }); } } } import { DomainError } from '../../shared/errors/DomainError.js'; //# sourceMappingURL=ConfigProvider.js.map