UNPKG

mushcode-mcp-server

Version:

A specialized Model Context Protocol server for MUSHCODE development assistance. Provides AI-powered code generation, validation, optimization, and examples for MUD development.

356 lines 14.7 kB
/** * MUSHCODE code generation engine */ import { ValidationError } from '../utils/test-errors.js'; export class MushcodeGenerator { knowledgeBase; constructor(knowledgeBase) { this.knowledgeBase = knowledgeBase; } /** * Generate MUSHCODE based on user specifications */ async generate(request) { this.validateRequest(request); // Find the best matching pattern const pattern = await this.findBestPattern(request); if (!pattern) { throw new ValidationError(`No suitable pattern found for: ${request.description}`); } // Get server dialect information const dialect = request.serverType ? this.knowledgeBase.dialects.get(request.serverType) : null; // Generate the code const code = this.generateCode(pattern, request, dialect); // Create explanation const explanation = this.generateExplanation(pattern, request); // Create usage example const usageExample = this.generateUsageExample(pattern, request); // Determine compatibility const compatibility = this.determineCompatibility(pattern, dialect); // Generate security notes const securityNotes = this.generateSecurityNotes(pattern, request); // Check for warnings const warnings = this.generateWarnings(pattern, request, dialect); return { code, explanation, usageExample, compatibility, securityNotes, patternUsed: pattern.id, warnings }; } /** * Validate the generation request */ validateRequest(request) { if (!request.description || request.description.trim().length === 0) { throw new ValidationError('Description is required'); } if (request.description.length > 1000) { throw new ValidationError('Description is too long (max 1000 characters)'); } if (request.serverType && !this.knowledgeBase.dialects.has(request.serverType)) { throw new ValidationError(`Unknown server type: ${request.serverType}`); } const validFunctionTypes = ['command', 'function', 'trigger', 'attribute', 'utility']; if (request.functionType && !validFunctionTypes.includes(request.functionType)) { throw new ValidationError(`Invalid function type. Must be one of: ${validFunctionTypes.join(', ')}`); } const validSecurityLevels = ['public', 'player', 'builder', 'wizard', 'god']; if (request.securityLevel && !validSecurityLevels.includes(request.securityLevel)) { throw new ValidationError(`Invalid security level. Must be one of: ${validSecurityLevels.join(', ')}`); } } /** * Find the best matching pattern for the request */ async findBestPattern(request) { // Search for patterns matching the description const searchQuery = { query: request.description, includePatterns: true, includeExamples: false, fuzzyMatch: true, limit: 10 }; if (request.functionType) { searchQuery.category = request.functionType; } if (request.serverType) { searchQuery.serverType = request.serverType; } const searchResult = this.knowledgeBase.search(searchQuery); if (searchResult.patterns.length === 0) { // Try a broader search without category filter const broadSearchQuery = { query: request.description, includePatterns: true, includeExamples: false, fuzzyMatch: true, limit: 10 }; if (request.serverType) { broadSearchQuery.serverType = request.serverType; } const broadSearchResult = this.knowledgeBase.search(broadSearchQuery); if (broadSearchResult.patterns.length === 0) { return null; } return this.selectBestPattern(broadSearchResult.patterns, request); } return this.selectBestPattern(searchResult.patterns, request); } /** * Select the best pattern from search results */ selectBestPattern(matches, request) { // Sort by relevance and confidence const sortedMatches = matches.sort((a, b) => { const scoreA = (a.relevance * 0.7) + (a.confidence * 0.3); const scoreB = (b.relevance * 0.7) + (b.confidence * 0.3); return scoreB - scoreA; }); for (const match of sortedMatches) { const pattern = this.knowledgeBase.patterns.get(match.patternId); if (!pattern) continue; // Check server compatibility if (request.serverType && !pattern.serverCompatibility.includes(request.serverType)) { continue; } // Check security level compatibility if (request.securityLevel) { const securityLevels = ['public', 'player', 'builder', 'wizard', 'god']; const requestLevel = securityLevels.indexOf(request.securityLevel); const patternLevel = securityLevels.indexOf(pattern.securityLevel); if (requestLevel < patternLevel) { continue; // Pattern requires higher permissions than requested } } return pattern; } return null; } /** * Generate code from pattern and request */ generateCode(pattern, request, dialect) { let code = pattern.codeTemplate; // Apply server-specific syntax variations if (dialect) { for (const rule of dialect.syntaxVariations) { if (rule.replacement) { code = code.replace(new RegExp(rule.pattern, 'g'), rule.replacement); } } } // Replace parameter placeholders if (request.parameters && request.parameters.length > 0) { request.parameters.forEach((param, index) => { const placeholder = `%${index}`; code = code.replace(new RegExp(`\\${placeholder}`, 'g'), param); }); } // Add comments if requested if (request.includeComments !== false) { code = this.addComments(code, pattern, request); } // Apply security considerations code = this.applySecurityConsiderations(code, pattern, request); return code.trim(); } /** * Add explanatory comments to the code */ addComments(code, pattern, request) { const lines = code.split('\n'); const commentedLines = []; // Add header comment commentedLines.push(`@@ ${pattern.name} - ${pattern.description}`); commentedLines.push(`@@ Generated for: ${request.description}`); if (request.serverType) { commentedLines.push(`@@ Server: ${request.serverType}`); } commentedLines.push(`@@ Security Level: ${pattern.securityLevel}`); commentedLines.push('@@'); // Add the original code with inline comments for complex sections for (let i = 0; i < lines.length; i++) { const line = lines[i]; if (line !== undefined) { commentedLines.push(line); // Add inline comments for complex patterns if (line.includes('switch(') && !line.includes('@@')) { commentedLines.push('@@ Switch statement for conditional logic'); } else if (line.includes('iter(') && !line.includes('@@')) { commentedLines.push('@@ Iterate over list elements'); } else if (line.includes('setq(') && !line.includes('@@')) { commentedLines.push('@@ Set register variable for later use'); } } } return commentedLines.join('\n'); } /** * Apply security considerations to the generated code */ applySecurityConsiderations(code, pattern, request) { let secureCode = code; // Add permission checks for elevated security levels if (pattern.securityLevel !== 'public') { const permissionCheck = this.generatePermissionCheck(pattern.securityLevel); secureCode = `${permissionCheck}\n${secureCode}`; } // Add input validation for user parameters if (request.parameters && request.parameters.length > 0) { const validationCode = this.generateInputValidation(request.parameters); secureCode = `${validationCode}\n${secureCode}`; } return secureCode; } /** * Generate permission check code */ generatePermissionCheck(securityLevel) { const checks = { 'player': '@switch hasflag(%#,PLAYER)=0,{@pemit %#=Permission denied.;@halt}', 'builder': '@switch orflags(%#,Bb)=0,{@pemit %#=Permission denied.;@halt}', 'wizard': '@switch orflags(%#,Ww)=0,{@pemit %#=Permission denied.;@halt}', 'god': '@switch hasflag(%#,ROYALTY)=0,{@pemit %#=Permission denied.;@halt}' }; return checks[securityLevel] || ''; } /** * Generate input validation code */ generateInputValidation(parameters) { const validations = []; parameters.forEach((param, index) => { if (param && param.trim().length > 0) { validations.push(`@switch strlen(%${index})=0,{@pemit %#=Error: Parameter ${index + 1} is required.;@halt}`); } }); return validations.join('\n'); } /** * Generate explanation for the code */ generateExplanation(pattern, _request) { const parts = []; parts.push(`This code implements ${pattern.name.toLowerCase()}: ${pattern.description}`); if (pattern.parameters.length > 0) { parts.push('\nParameters:'); pattern.parameters.forEach((param, index) => { parts.push(` %${index} - ${param.name}: ${param.description}${param.required ? ' (required)' : ' (optional)'}`); }); } parts.push(`\nSecurity Level: ${pattern.securityLevel} - ${this.getSecurityLevelDescription(pattern.securityLevel)}`); if (pattern.tags.length > 0) { parts.push(`\nTags: ${pattern.tags.join(', ')}`); } parts.push(`\nThis pattern is compatible with: ${pattern.serverCompatibility.join(', ')}`); return parts.join(''); } /** * Get description for security level */ getSecurityLevelDescription(level) { const descriptions = { 'public': 'Can be used by any player', 'player': 'Requires player-level permissions', 'builder': 'Requires builder-level permissions or higher', 'wizard': 'Requires wizard-level permissions or higher', 'god': 'Requires god-level permissions' }; return descriptions[level] || 'Unknown security level'; } /** * Generate usage example */ generateUsageExample(pattern, request) { if (pattern.examples.length > 0 && pattern.examples[0]) { return pattern.examples[0]; } // Generate a basic usage example const exampleParts = []; if (pattern.category === 'command') { exampleParts.push(`+${pattern.name.toLowerCase()}`); if (request.parameters && request.parameters.length > 0) { exampleParts.push(request.parameters.join(' ')); } } else { exampleParts.push(`[${pattern.name.toLowerCase()}(`); if (request.parameters && request.parameters.length > 0) { exampleParts.push(request.parameters.join(', ')); } exampleParts.push(')]'); } return exampleParts.join(''); } /** * Determine server compatibility */ determineCompatibility(pattern, dialect) { if (dialect) { // Check if pattern is compatible with the specific dialect return pattern.serverCompatibility.includes(dialect.name) ? [dialect.name] : pattern.serverCompatibility; } return pattern.serverCompatibility; } /** * Generate security notes */ generateSecurityNotes(pattern, request) { const notes = []; if (pattern.securityLevel !== 'public') { notes.push(`This code requires ${pattern.securityLevel} level permissions to execute.`); } if (request.parameters && request.parameters.length > 0) { notes.push('Input validation has been added to prevent common security issues.'); } // Check for potentially dangerous functions const dangerousFunctions = ['@shutdown', '@restart', '@dump', '@pcreate', '@destroy']; const codeTemplate = pattern.codeTemplate.toLowerCase(); for (const func of dangerousFunctions) { if (codeTemplate.includes(func)) { notes.push(`WARNING: This code uses ${func} which can have significant system impact.`); } } return notes.length > 0 ? notes.join(' ') : undefined; } /** * Generate warnings for potential issues */ generateWarnings(pattern, request, dialect) { const warnings = []; // Check server compatibility if (request.serverType && !pattern.serverCompatibility.includes(request.serverType)) { warnings.push(`This pattern may not be fully compatible with ${request.serverType}`); } // Check for deprecated features if (dialect) { for (const func of dialect.functionLibrary) { if (func.deprecated && pattern.codeTemplate.includes(func.name)) { warnings.push(`Function ${func.name} is deprecated in ${dialect.name}`); if (func.alternativeTo) { warnings.push(`Consider using ${func.alternativeTo} instead`); } } } } // Check complexity level if (pattern.difficulty === 'advanced' && request.functionType === 'command') { warnings.push('This is an advanced pattern that may require additional customization'); } return warnings; } } //# sourceMappingURL=generator.js.map