UNPKG

@memory-bank/mcp

Version:

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

295 lines 11.5 kB
import { BranchInfo } from '../../../domain/entities/BranchInfo.js'; import { DocumentPath } from '../../../domain/entities/DocumentPath.js'; import { MemoryDocument } from '../../../domain/entities/MemoryDocument.js'; import { DomainError, DomainErrorCodes } from '../../../shared/errors/DomainError.js'; import { ApplicationError, ApplicationErrorCodes, } from '../../../shared/errors/ApplicationError.js'; import { Tag } from '../../../domain/entities/Tag.js'; /** * Use case for creating or updating core files in a branch memory bank */ export class CreateBranchCoreFilesUseCase { branchRepository; ACTIVE_CONTEXT_PATH = 'activeContext.json'; PROGRESS_PATH = 'progress.json'; SYSTEM_PATTERNS_PATH = 'systemPatterns.json'; BRANCH_CONTEXT_PATH = 'branchContext.json'; /** * Constructor * @param branchRepository Branch memory bank repository */ constructor(branchRepository) { this.branchRepository = branchRepository; } /** * Execute the use case * @param input Input data * @returns Promise resolving to output data */ async execute(input) { try { if (!input.branchName) { throw new ApplicationError(ApplicationErrorCodes.INVALID_INPUT, 'Branch name is required'); } if (!input.files) { throw new ApplicationError(ApplicationErrorCodes.INVALID_INPUT, 'Core files data is required'); } const branchInfo = BranchInfo.create(input.branchName); const branchExists = await this.branchRepository.exists(input.branchName); if (!branchExists) { throw new DomainError(DomainErrorCodes.BRANCH_NOT_FOUND, `Branch "${input.branchName}" not found`); } const updatedFiles = []; if (input.files.branchContext) { const document = MemoryDocument.create({ path: DocumentPath.create(this.BRANCH_CONTEXT_PATH), content: input.files.branchContext, tags: [Tag.create('core'), Tag.create('branch-context')], lastModified: new Date(), }); await this.branchRepository.saveDocument(branchInfo, document); updatedFiles.push(this.BRANCH_CONTEXT_PATH); } if (input.files.activeContext) { const content = this.generateActiveContextJSON(input.files.activeContext); const document = MemoryDocument.create({ path: DocumentPath.create(this.ACTIVE_CONTEXT_PATH), content, tags: [Tag.create('core'), Tag.create('active-context')], lastModified: new Date(), }); await this.branchRepository.saveDocument(branchInfo, document); updatedFiles.push(this.ACTIVE_CONTEXT_PATH); } if (input.files.progress) { const content = this.generateProgressJSON(input.files.progress); const document = MemoryDocument.create({ path: DocumentPath.create(this.PROGRESS_PATH), content, tags: [Tag.create('core'), Tag.create('progress')], lastModified: new Date(), }); await this.branchRepository.saveDocument(branchInfo, document); updatedFiles.push(this.PROGRESS_PATH); } if (input.files.systemPatterns && input.files.systemPatterns.technicalDecisions) { const content = this.generateSystemPatternsJSON(input.files.systemPatterns); const document = MemoryDocument.create({ path: DocumentPath.create(this.SYSTEM_PATTERNS_PATH), content, tags: [Tag.create('core'), Tag.create('system-patterns')], lastModified: new Date(), }); await this.branchRepository.saveDocument(branchInfo, document); updatedFiles.push(this.SYSTEM_PATTERNS_PATH); } return { message: `Successfully updated ${updatedFiles.length} core files for branch "${input.branchName}"`, updatedFiles, }; } catch (error) { if (error instanceof DomainError || error instanceof ApplicationError) { throw error; } throw new ApplicationError(ApplicationErrorCodes.USE_CASE_EXECUTION_FAILED, `Failed to create/update core files: ${error.message}`, { originalError: error }); } } /** * Generate JSON for active context * @param activeContext Active context DTO * @returns JSON content as string */ generateActiveContextJSON(activeContext) { const now = new Date(); const jsonDoc = { schema: 'memory_document_v2', metadata: { id: this.generateUUID(), title: 'Active Context', // Translated from アクティブコンテキスト documentType: 'active_context', path: this.ACTIVE_CONTEXT_PATH, tags: ['core', 'active-context'], lastModified: now.toISOString(), createdAt: now.toISOString(), version: 1 }, content: { currentWork: activeContext.currentWork || '', recentChanges: this.formatRecentChanges(activeContext.recentChanges || []), activeDecisions: this.formatActiveDecisions(activeContext.activeDecisions || []), considerations: this.formatConsiderations(activeContext.considerations || []), nextSteps: this.formatNextSteps(activeContext.nextSteps || []) } }; return JSON.stringify(jsonDoc, null, 2); } /** * Format recent changes to structured format * @param changes Array of change strings * @returns Structured changes */ formatRecentChanges(changes) { return changes.map(change => ({ date: new Date().toISOString(), description: change })); } /** * Format active decisions to structured format * @param decisions Array of decision strings * @returns Structured decisions */ formatActiveDecisions(decisions) { return decisions.map(decision => ({ id: this.generateUUID(), description: decision })); } /** * Format considerations to structured format * @param considerations Array of consideration strings * @returns Structured considerations */ formatConsiderations(considerations) { return considerations.map(consideration => ({ id: this.generateUUID(), description: consideration, status: 'open' })); } /** * Format next steps to structured format * @param steps Array of step strings * @returns Structured steps */ formatNextSteps(steps) { return steps.map(step => ({ id: this.generateUUID(), description: step, priority: 'medium' })); } /** * Generate JSON for progress * @param progress Progress DTO * @returns JSON content as string */ generateProgressJSON(progress) { const now = new Date(); const jsonDoc = { schema: 'memory_document_v2', metadata: { id: this.generateUUID(), title: 'Progress', // Translated from 進捗状況 documentType: 'progress', path: this.PROGRESS_PATH, tags: ['core', 'progress'], lastModified: now.toISOString(), createdAt: now.toISOString(), version: 1 }, content: { workingFeatures: this.formatWorkingFeatures(progress.workingFeatures || []), pendingImplementation: this.formatPendingImplementation(progress.pendingImplementation || []), status: progress.status || '', completionPercentage: 0, knownIssues: this.formatKnownIssues(progress.knownIssues || []) } }; return JSON.stringify(jsonDoc, null, 2); } /** * Format working features to structured format * @param features Array of feature strings * @returns Structured features */ formatWorkingFeatures(features) { return features.map(feature => ({ id: this.generateUUID(), description: feature, implementedAt: new Date().toISOString() })); } /** * Format pending implementation to structured format * @param items Array of pending item strings * @returns Structured pending items */ formatPendingImplementation(items) { return items.map(item => ({ id: this.generateUUID(), description: item, priority: 'medium' })); } /** * Format known issues to structured format * @param issues Array of issue strings * @returns Structured issues */ formatKnownIssues(issues) { return issues.map(issue => ({ id: this.generateUUID(), description: issue, severity: 'medium' })); } /** * Generate JSON for system patterns * @param systemPatterns System patterns DTO * @returns JSON content as string */ generateSystemPatternsJSON(systemPatterns) { const now = new Date(); const jsonDoc = { schema: 'memory_document_v2', metadata: { id: this.generateUUID(), title: 'System Patterns', // Translated from システムパターン documentType: 'system_patterns', path: this.SYSTEM_PATTERNS_PATH, tags: ['core', 'system-patterns'], lastModified: now.toISOString(), createdAt: now.toISOString(), version: 1 }, content: { technicalDecisions: this.formatTechnicalDecisions(systemPatterns.technicalDecisions || []), implementationPatterns: [] } }; return JSON.stringify(jsonDoc, null, 2); } /** * Format technical decisions to structured format * @param decisions Array of technical decision DTOs * @returns Structured technical decisions */ formatTechnicalDecisions(decisions) { return decisions.map(decision => ({ id: this.generateUUID(), title: decision.title, context: decision.context, decision: decision.decision, consequences: { positive: decision.consequences || [], negative: [] }, status: 'accepted', date: new Date().toISOString(), alternatives: [] })); } /** * Generate a UUID for document IDs * @returns UUID string */ generateUUID() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { const r = Math.random() * 16 | 0; const v = c === 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); } } //# sourceMappingURL=CreateBranchCoreFilesUseCase.js.map