@memory-bank/mcp
Version:
Memory-enabled Co-Pilot (MCP) server for managing project documentation and context
195 lines • 7.3 kB
JavaScript
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