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