UNPKG

claude-flow-multilang

Version:

Revolutionary multilingual AI orchestration framework with cultural awareness and DDD architecture

804 lines (707 loc) 23.2 kB
/** * Claude Flow Multilang Framework - DDD Development Service * Integrates DDD into the development workflow */ import { SupportedLanguage } from '../../polyglot/types.js'; import { ILogger } from '../../core/logger.js'; import { WorkflowAggregate } from '../workflow-aggregate.js'; import { CommandBus, ICommand, ICommandResult } from './command-handler.js'; import { PolyglotAgent } from '../../polyglot/polyglot-agent.js'; import { MultilingualString, EntityId } from '../base-domain.js'; /** * DDD development phase */ export enum DDDPhase { DISCOVERY = 'discovery', MODELING = 'modeling', IMPLEMENTATION = 'implementation', TESTING = 'testing', DEPLOYMENT = 'deployment', } /** * Bounded context definition */ export interface BoundedContext { id: string; name: MultilingualString; description: MultilingualString; aggregates: AggregateDefinition[]; services: ServiceDefinition[]; events: EventDefinition[]; language: SupportedLanguage; team?: string; } /** * Aggregate definition for development */ export interface AggregateDefinition { id: string; name: MultilingualString; description: MultilingualString; properties: PropertyDefinition[]; methods: MethodDefinition[]; events: string[]; invariants: string[]; } /** * Property definition */ export interface PropertyDefinition { name: string; type: string; required: boolean; multilingual: boolean; validation?: string; } /** * Method definition */ export interface MethodDefinition { name: string; description: MultilingualString; parameters: ParameterDefinition[]; returnType: string; businessRules: string[]; } /** * Parameter definition */ export interface ParameterDefinition { name: string; type: string; required: boolean; description?: string; } /** * Service definition */ export interface ServiceDefinition { id: string; name: MultilingualString; description: MultilingualString; operations: MethodDefinition[]; dependencies: string[]; } /** * Event definition */ export interface EventDefinition { id: string; name: string; description: MultilingualString; payload: PropertyDefinition[]; source: string; targets: string[]; } /** * DDD Development Service */ export class DDDDevelopmentService { private boundedContexts: Map<string, BoundedContext> = new Map(); private currentPhase: DDDPhase = DDDPhase.DISCOVERY; private commandBus: CommandBus; private workflows: Map<string, WorkflowAggregate> = new Map(); private commandHandlers: Map<string, any> = new Map(); constructor( private logger: ILogger, private polyglotAgent: PolyglotAgent, ) { this.commandBus = new CommandBus(logger); this.registerDefaultHandlers(); } /** * Register default command handlers */ private registerDefaultHandlers(): void { // Register handlers for workflow commands this.commandBus.register('CreateBoundedContext', { handle: async (command: ICreateCommand) => this.handleCreateBoundedContext(command), canHandle: (cmd) => cmd.type === 'CreateBoundedContext', }); this.commandBus.register('AddAggregate', { handle: async (command: any) => this.handleAddAggregate(command), canHandle: (cmd) => cmd.type === 'AddAggregate', }); this.commandBus.register('GenerateCode', { handle: async (command: any) => this.handleGenerateCode(command), canHandle: (cmd) => cmd.type === 'GenerateCode', }); } /** * Handle create bounded context command */ private async handleCreateBoundedContext(command: ICreateCommand): Promise<ICommandResult> { try { const context = await this.createBoundedContext( command.name, command.description, { team: command.properties?.team, language: command.language, }, ); return { success: true, data: context, aggregateId: context.id, }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : 'Unknown error', }; } } /** * Handle add aggregate command */ private async handleAddAggregate(command: any): Promise<ICommandResult> { try { await this.addAggregate(command.contextId, command.aggregate); return { success: true, data: { message: 'Aggregate added successfully' }, }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : 'Unknown error', }; } } /** * Handle generate code command */ private async handleGenerateCode(command: any): Promise<ICommandResult> { try { const files = await this.generateCode(command.contextId, command.options); return { success: true, data: { files: Array.from(files.entries()) }, }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : 'Unknown error', }; } } /** * Start DDD development process */ async startDevelopment( projectName: Partial<Record<SupportedLanguage, string>>, description: Partial<Record<SupportedLanguage, string>>, options: { methodology?: 'event-storming' | 'domain-storytelling' | 'example-mapping'; team?: string; primaryLanguage?: SupportedLanguage; } = {}, ): Promise<WorkflowAggregate> { this.logger.info('Starting DDD development process', { project: projectName, methodology: options.methodology || 'event-storming', }); // Create DDD workflow const workflow = this.createDDDWorkflow(projectName, description, options); this.workflows.set(workflow.id.toString(), workflow); // Start discovery phase await this.startDiscoveryPhase(workflow, options); return workflow; } /** * Create DDD development workflow */ private createDDDWorkflow( projectName: Partial<Record<SupportedLanguage, string>>, description: Partial<Record<SupportedLanguage, string>>, options: any, ): WorkflowAggregate { const workflow = WorkflowAggregate.create( projectName, description, options.primaryLanguage ? [options.primaryLanguage] : [SupportedLanguage.EN], ); // Add DDD phases as workflow steps this.addDDDPhases(workflow, options.primaryLanguage || SupportedLanguage.EN); workflow.activate(); return workflow; } /** * Add DDD phases to workflow */ private addDDDPhases(workflow: WorkflowAggregate, language: SupportedLanguage): void { const phases = [ { phase: DDDPhase.DISCOVERY, name: { [SupportedLanguage.EN]: 'Domain Discovery', [SupportedLanguage.RU]: 'Исследование домена', [SupportedLanguage.JA]: 'ドメイン探索', [SupportedLanguage.ZH_CN]: '领域发现', }, description: { [SupportedLanguage.EN]: 'Discover domain concepts through event storming', [SupportedLanguage.RU]: 'Обнаружение доменных концепций через event storming', [SupportedLanguage.JA]: 'イベントストーミングによるドメイン概念の発見', [SupportedLanguage.ZH_CN]: '通过事件风暴发现领域概念', }, agent: 'domain-expert', capabilities: ['event-storming', 'domain-analysis', 'ubiquitous-language'], }, { phase: DDDPhase.MODELING, name: { [SupportedLanguage.EN]: 'Domain Modeling', [SupportedLanguage.RU]: 'Моделирование домена', [SupportedLanguage.JA]: 'ドメインモデリング', [SupportedLanguage.ZH_CN]: '领域建模', }, description: { [SupportedLanguage.EN]: 'Create domain models with aggregates and entities', [SupportedLanguage.RU]: 'Создание доменных моделей с агрегатами и сущностями', [SupportedLanguage.JA]: '集約とエンティティを使用したドメインモデルの作成', [SupportedLanguage.ZH_CN]: '使用聚合和实体创建领域模型', }, agent: 'architect', capabilities: ['aggregate-design', 'entity-modeling', 'value-objects'], }, { phase: DDDPhase.IMPLEMENTATION, name: { [SupportedLanguage.EN]: 'Implementation', [SupportedLanguage.RU]: 'Реализация', [SupportedLanguage.JA]: '実装', [SupportedLanguage.ZH_CN]: '实现', }, description: { [SupportedLanguage.EN]: 'Implement domain models and services', [SupportedLanguage.RU]: 'Реализация доменных моделей и сервисов', [SupportedLanguage.JA]: 'ドメインモデルとサービスの実装', [SupportedLanguage.ZH_CN]: '实现领域模型和服务', }, agent: 'developer', capabilities: ['coding', 'repository-pattern', 'domain-services'], }, { phase: DDDPhase.TESTING, name: { [SupportedLanguage.EN]: 'Testing', [SupportedLanguage.RU]: 'Тестирование', [SupportedLanguage.JA]: 'テスト', [SupportedLanguage.ZH_CN]: '测试', }, description: { [SupportedLanguage.EN]: 'Test domain logic and invariants', [SupportedLanguage.RU]: 'Тестирование доменной логики и инвариантов', [SupportedLanguage.JA]: 'ドメインロジックと不変条件のテスト', [SupportedLanguage.ZH_CN]: '测试领域逻辑和不变量', }, agent: 'tester', capabilities: ['unit-testing', 'integration-testing', 'invariant-testing'], }, ]; let previousStep: string | undefined; for (const phase of phases) { workflow.addStep( phase.name, phase.description, phase.agent, phase.capabilities, previousStep ? [previousStep] : [], ); previousStep = `step-${workflow.getProgress().total}`; } } /** * Start discovery phase */ private async startDiscoveryPhase( workflow: WorkflowAggregate, options: any, ): Promise<void> { this.currentPhase = DDDPhase.DISCOVERY; const methodology = options.methodology || 'event-storming'; switch (methodology) { case 'event-storming': await this.runEventStorming(workflow, options); break; case 'domain-storytelling': await this.runDomainStorytelling(workflow, options); break; case 'example-mapping': await this.runExampleMapping(workflow, options); break; } } /** * Run event storming session */ private async runEventStorming( workflow: WorkflowAggregate, options: any, ): Promise<void> { this.logger.info('Running event storming session'); // Use polyglot agent to facilitate event storming const prompt = ` Facilitate an event storming session for ${workflow.getName(options.primaryLanguage || SupportedLanguage.EN)}. Identify: 1. Domain events (things that happen) 2. Commands (triggers for events) 3. Aggregates (consistency boundaries) 4. Bounded contexts (logical boundaries) 5. Read models (queries and views) `; const result = await this.polyglotAgent.processInNativeLanguage( prompt, options.primaryLanguage, ); // Parse and store discovered concepts // In real implementation, this would be interactive this.logger.info('Event storming completed', { language: result.language, confidence: result.confidence, }); } /** * Run domain storytelling session */ private async runDomainStorytelling( workflow: WorkflowAggregate, options: any, ): Promise<void> { this.logger.info('Running domain storytelling session'); // Implementation for domain storytelling } /** * Run example mapping session */ private async runExampleMapping( workflow: WorkflowAggregate, options: any, ): Promise<void> { this.logger.info('Running example mapping session'); // Implementation for example mapping } /** * Create bounded context */ async createBoundedContext( name: Partial<Record<SupportedLanguage, string>>, description: Partial<Record<SupportedLanguage, string>>, options: { team?: string; language?: SupportedLanguage; } = {}, ): Promise<BoundedContext> { const id = EntityId.generate().toString(); const context: BoundedContext = { id, name: new MultilingualString(name), description: new MultilingualString(description), aggregates: [], services: [], events: [], language: options.language || SupportedLanguage.EN, team: options.team, }; this.boundedContexts.set(id, context); this.logger.info('Created bounded context', { id, name: name[SupportedLanguage.EN], }); return context; } /** * Add aggregate to bounded context */ async addAggregate( contextId: string, aggregate: AggregateDefinition, ): Promise<void> { const context = this.boundedContexts.get(contextId); if (!context) { throw new Error(`Bounded context not found: ${contextId}`); } context.aggregates.push(aggregate); this.logger.info('Added aggregate to bounded context', { contextId, aggregateName: aggregate.name.get(SupportedLanguage.EN), }); } /** * Generate code from bounded context */ async generateCode( contextId: string, options: { language?: 'typescript' | 'javascript' | 'python' | 'java'; includeTests?: boolean; includeRepositories?: boolean; includeServices?: boolean; } = {}, ): Promise<Map<string, string>> { const context = this.boundedContexts.get(contextId); if (!context) { throw new Error(`Bounded context not found: ${contextId}`); } const files = new Map<string, string>(); // Generate aggregate files for (const aggregate of context.aggregates) { const code = this.generateAggregateCode(aggregate, options); const fileName = `${aggregate.name.get(SupportedLanguage.EN)}.${options.language === 'python' ? 'py' : 'ts'}`; files.set(fileName, code); if (options.includeTests) { const testCode = this.generateAggregateTests(aggregate, options); const testFileName = `${aggregate.name.get(SupportedLanguage.EN)}.test.${options.language === 'python' ? 'py' : 'ts'}`; files.set(testFileName, testCode); } } // Generate repository interfaces if (options.includeRepositories) { for (const aggregate of context.aggregates) { const repoCode = this.generateRepositoryInterface(aggregate, options); const repoFileName = `${aggregate.name.get(SupportedLanguage.EN)}Repository.${options.language === 'python' ? 'py' : 'ts'}`; files.set(repoFileName, repoCode); } } // Generate domain services if (options.includeServices) { for (const service of context.services) { const serviceCode = this.generateServiceCode(service, options); const serviceFileName = `${service.name.get(SupportedLanguage.EN)}Service.${options.language === 'python' ? 'py' : 'ts'}`; files.set(serviceFileName, serviceCode); } } this.logger.info('Generated code for bounded context', { contextId, filesGenerated: files.size, }); return files; } /** * Generate aggregate code */ private generateAggregateCode( aggregate: AggregateDefinition, options: any, ): string { const className = aggregate.name.get(SupportedLanguage.EN); if (options.language === 'typescript' || !options.language) { return `/** * ${className} Aggregate * ${aggregate.description.get(SupportedLanguage.EN)} */ import { AggregateRoot, EntityId, MultilingualString } from '@claude-flow/domain'; import { SupportedLanguage } from '@claude-flow/types'; export interface ${className}Props { ${aggregate.properties.map(p => ` ${p.name}${p.required ? '' : '?'}: ${p.multilingual ? 'MultilingualString' : p.type};`).join('\n')} } export class ${className} extends AggregateRoot<${className}Props> { constructor(props: ${className}Props, id?: EntityId) { super(props, id); this.validateInvariants(); } private validateInvariants(): void { ${aggregate.invariants.map(inv => ` // ${inv}`).join('\n')} } ${aggregate.methods.map(m => ` ${m.name}(${m.parameters.map(p => `${p.name}: ${p.type}`).join(', ')}): ${m.returnType} { // Business rules: ${m.businessRules.map(rule => ` // - ${rule}`).join('\n')} // Implementation here throw new Error('Not implemented'); }`).join('\n')} } // Domain Events ${aggregate.events.map(event => ` export class ${event} extends DomainEvent { constructor(aggregateId: string, public readonly data: any) { super(aggregateId, '${event}'); } }`).join('\n')}`; } // Python implementation return '# Python implementation not yet available'; } /** * Generate aggregate tests */ private generateAggregateTests( aggregate: AggregateDefinition, options: any, ): string { const className = aggregate.name.get(SupportedLanguage.EN); return `import { ${className} } from './${className}'; describe('${className}', () => { describe('creation', () => { it('should create with valid props', () => { const aggregate = new ${className}({ // Add test props }); expect(aggregate).toBeDefined(); expect(aggregate.id).toBeDefined(); }); }); ${aggregate.methods.map(m => ` describe('${m.name}', () => { it('should ${m.description.get(SupportedLanguage.EN)}', () => { // Test implementation }); });`).join('\n')} describe('invariants', () => { ${aggregate.invariants.map(inv => ` it('should enforce: ${inv}', () => { // Test invariant });`).join('\n')} }); });`; } /** * Generate repository interface */ private generateRepositoryInterface( aggregate: AggregateDefinition, options: any, ): string { const className = aggregate.name.get(SupportedLanguage.EN); return `import { ${className} } from './${className}'; import { IRepository, EntityId } from '@claude-flow/domain'; export interface I${className}Repository extends IRepository<${className}> { // Custom query methods findByName(name: string): Promise<${className} | null>; // Add more custom queries as needed }`; } /** * Generate service code */ private generateServiceCode( service: ServiceDefinition, options: any, ): string { const className = service.name.get(SupportedLanguage.EN); return `import { DomainService } from '@claude-flow/domain'; ${service.dependencies.map(dep => `import { ${dep} } from './${dep}';`).join('\n')} export class ${className} extends DomainService { constructor( ${service.dependencies.map(dep => ` private ${dep.toLowerCase()}: ${dep},`).join('\n')} ) { super('${className}'); } ${service.operations.map(op => ` async ${op.name}(${op.parameters.map(p => `${p.name}: ${p.type}`).join(', ')}): Promise<${op.returnType}> { // ${op.description.get(SupportedLanguage.EN)} throw new Error('Not implemented'); }`).join('\n')} }`; } /** * Validate domain model */ async validateDomainModel(contextId: string): Promise<{ valid: boolean; issues: string[]; suggestions: string[]; }> { const context = this.boundedContexts.get(contextId); if (!context) { throw new Error(`Bounded context not found: ${contextId}`); } const issues: string[] = []; const suggestions: string[] = []; // Validate aggregates for (const aggregate of context.aggregates) { // Check for aggregate root if (!aggregate.properties.some(p => p.name === 'id')) { issues.push(`Aggregate ${aggregate.name.get(SupportedLanguage.EN)} missing id property`); } // Check for at least one method if (aggregate.methods.length === 0) { suggestions.push(`Aggregate ${aggregate.name.get(SupportedLanguage.EN)} has no behavior - consider if it should be a value object`); } // Check for invariants if (aggregate.invariants.length === 0) { suggestions.push(`Aggregate ${aggregate.name.get(SupportedLanguage.EN)} has no invariants - add business rules`); } } // Check for bounded context cohesion if (context.aggregates.length > 10) { suggestions.push('Bounded context might be too large - consider splitting'); } return { valid: issues.length === 0, issues, suggestions, }; } /** * Execute DDD command */ async executeCommand(command: ICommand): Promise<ICommandResult> { this.logger.info('Executing DDD command', { type: command.constructor.name, id: command.id, }); return await this.commandBus.execute(command); } /** * Execute multiple commands in a transaction */ async executeCommandSequence(commands: ICommand[]): Promise<ICommandResult[]> { this.logger.info('Executing command sequence', { count: commands.length, }); const results: ICommandResult[] = []; for (const command of commands) { const result = await this.executeCommand(command); results.push(result); // Stop on first failure if (!result.success) { this.logger.error('Command sequence failed', { failedCommand: command.id, error: result.error, }); break; } } return results; } /** * Register custom command handler */ registerCommandHandler<TCommand extends ICommand>( commandType: string, handler: any, ): void { this.commandBus.register(commandType, handler); this.commandHandlers.set(commandType, handler); this.logger.info('Registered command handler', { commandType }); } /** * Get current development status */ getStatus(): { phase: DDDPhase; boundedContexts: number; aggregates: number; services: number; events: number; } { let totalAggregates = 0; let totalServices = 0; let totalEvents = 0; for (const context of this.boundedContexts.values()) { totalAggregates += context.aggregates.length; totalServices += context.services.length; totalEvents += context.events.length; } return { phase: this.currentPhase, boundedContexts: this.boundedContexts.size, aggregates: totalAggregates, services: totalServices, events: totalEvents, }; } }