@memory-bank/mcp
Version:
Memory-enabled Co-Pilot (MCP) server for managing project documentation and context
104 lines • 4.7 kB
JavaScript
import { DocumentPath } from '../../../domain/entities/DocumentPath.js';
import { Tag } from '../../../domain/entities/Tag.js';
import { ApplicationErrors } from '../../../shared/errors/ApplicationError.js';
import { logger } from '../../../shared/utils/logger.js';
/**
* Use case for writing a document to either branch or global memory bank
*/
export class WriteDocumentUseCase {
repositorySelector;
documentWriterService;
useCaseLogger = logger.withContext({
component: 'WriteDocumentUseCase'
});
/**
* Constructor
* @param repositorySelector Service to select appropriate repository based on scope
* @param documentWriterService Service for document writing and patching
*/
constructor(repositorySelector, documentWriterService) {
this.repositorySelector = repositorySelector;
this.documentWriterService = documentWriterService;
}
/**
* Execute the use case
* @param input Input data
* @returns Promise resolving to output data
*/
async execute(input) {
try {
// Validate input
this.validateInput(input);
this.useCaseLogger.info('Executing write document use case', {
scope: input.scope,
branch: input.branch,
path: input.path,
hasContent: input.content !== undefined && input.content !== null,
hasPatches: input.patches && Array.isArray(input.patches) && input.patches.length > 0
});
// Get appropriate repository based on scope
const { repository } = await this.repositorySelector.getRepository(input.scope, input.branch);
// Create document path
const documentPath = DocumentPath.create(input.path);
// Prepare tags
const tags = (input.tags ?? []).map(tag => Tag.create(tag));
// Prepare input for DocumentWriterService
const writerInput = {
path: documentPath,
content: input.content,
patches: input.patches,
tags
};
// Use DocumentWriterService to handle the write operation
const savedDocument = await this.documentWriterService.write(repository, writerInput);
// Prepare return data based on returnContent flag
const shouldReturnContent = input.returnContent === true;
const outputDocument = {
path: savedDocument.path.value,
lastModified: savedDocument.lastModified.toISOString(),
...(shouldReturnContent && {
content: savedDocument.content,
tags: savedDocument.tags.map(tag => tag.value)
})
};
return {
document: outputDocument
};
}
catch (error) {
// Re-throw domain or application errors directly
if (error instanceof Error && (error.name === 'DomainError' || error.name === 'ApplicationError')) {
throw error;
}
// Wrap other errors
this.useCaseLogger.error('Unexpected error in WriteDocumentUseCase', { error });
throw ApplicationErrors.executionFailed(`Failed to write document: ${error instanceof Error ? error.message : 'Unknown error'}`, error instanceof Error ? error : undefined);
}
}
/**
* Validates the input parameters
* @param input The input parameters to validate
* @throws ApplicationError if input is invalid
*/
validateInput(input) {
// Validate scope
if (input.scope !== 'branch' && input.scope !== 'global') {
throw ApplicationErrors.invalidInput(`Invalid scope: ${input.scope}. Must be 'branch' or 'global'.`);
}
// Validate path
if (!input.path) {
throw ApplicationErrors.invalidInput('Document path is required');
}
// Validate content and patches (mutually exclusive)
const hasContent = input.content !== undefined && input.content !== null;
const hasPatches = input.patches && Array.isArray(input.patches) && input.patches.length > 0;
if (!hasContent && !hasPatches) {
throw ApplicationErrors.invalidInput('Either document content or patches must be provided');
}
if (hasContent && hasPatches) {
throw ApplicationErrors.invalidInput('Cannot provide both document content and patches simultaneously');
}
// Branch name validation is handled by DocumentRepositorySelector
}
}
//# sourceMappingURL=WriteDocumentUseCase.js.map