il2cpp-dump-analyzer-mcp
Version:
Agentic RAG system for analyzing IL2CPP dump.cs files from Unity games
377 lines • 17.5 kB
JavaScript
;
/**
* Find Design Patterns Tool Implementation
* Detects common design patterns in IL2CPP code with confidence scoring
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.findDesignPatternsSchema = exports.FindDesignPatternsToolHandler = void 0;
exports.createFindDesignPatternsTool = createFindDesignPatternsTool;
const zod_1 = require("zod");
const base_tool_handler_1 = require("../base-tool-handler");
const parameter_validator_1 = require("../../utils/parameter-validator");
const mcp_response_formatter_1 = require("../../utils/mcp-response-formatter");
/**
* Find Design Patterns Tool Handler
* Detects common design patterns in IL2CPP code with confidence scoring
*/
class FindDesignPatternsToolHandler extends base_tool_handler_1.BaseAnalysisToolHandler {
constructor(context) {
super({
name: 'find_design_patterns',
description: 'Detect common design patterns in IL2CPP code',
enableParameterValidation: true,
enableResponseFormatting: true
}, context);
}
/**
* Validate design patterns parameters
*/
async validateParameters(params) {
const errors = [];
const warnings = [];
const adjustedValues = {};
// Validate pattern_types parameter
const patternValidation = parameter_validator_1.ParameterValidator.validatePatternTypes(params.pattern_types);
errors.push(...patternValidation.errors);
warnings.push(...patternValidation.warnings);
// Validate confidence_threshold parameter
if (params.confidence_threshold !== undefined) {
adjustedValues.confidence_threshold = parameter_validator_1.ParameterValidator.validateConfidence(params.confidence_threshold);
if (adjustedValues.confidence_threshold !== params.confidence_threshold) {
warnings.push(`Confidence threshold adjusted from ${params.confidence_threshold} to ${adjustedValues.confidence_threshold} (valid range: 0.1-1.0)`);
}
}
else {
adjustedValues.confidence_threshold = 0.7;
}
// Validate max_results_per_pattern parameter
if (params.max_results_per_pattern !== undefined) {
adjustedValues.max_results_per_pattern = parameter_validator_1.ParameterValidator.validateMaxResults(params.max_results_per_pattern, 50);
if (adjustedValues.max_results_per_pattern !== params.max_results_per_pattern) {
warnings.push(`max_results_per_pattern adjusted from ${params.max_results_per_pattern} to ${adjustedValues.max_results_per_pattern} (valid range: 1-50)`);
}
}
else {
adjustedValues.max_results_per_pattern = 10;
}
// Set defaults for optional boolean parameters
if (params.include_partial_matches === undefined) {
adjustedValues.include_partial_matches = true;
}
if (params.exclude_unity_patterns === undefined) {
adjustedValues.exclude_unity_patterns = false;
}
return {
isValid: errors.length === 0,
errors,
warnings,
adjustedValues
};
}
/**
* Execute design pattern detection
*/
async executeCore(params) {
return await this.performAnalysis(async () => {
this.context.logger.debug(`Detecting patterns: [${params.pattern_types.join(', ')}], confidence: ${params.confidence_threshold}`);
// Step 1: Get all classes for analysis
const filter = { type: 'class' };
if (params.namespace_scope) {
filter.namespace = params.namespace_scope;
}
const allClassesResults = await this.context.vectorStore.searchWithFilter('', filter, 500);
// Step 2: Initialize result
const result = {
detectedPatterns: {},
summary: {
totalPatternsFound: 0,
patternTypeCount: 0,
averageConfidence: 0,
architecturalInsights: []
},
metadata: {
searchedPatterns: params.pattern_types,
confidenceThreshold: params.confidence_threshold || 0.7,
includePartialMatches: params.include_partial_matches || true,
namespaceScope: params.namespace_scope,
excludeUnityPatterns: params.exclude_unity_patterns || false,
maxResultsPerPattern: params.max_results_per_pattern || 10,
timestamp: new Date().toISOString()
}
};
// Step 3: Detect each pattern type
for (const patternType of params.pattern_types) {
try {
this.context.logger.debug(`Detecting ${patternType} pattern...`);
let matches = await this.detectPattern(patternType, allClassesResults, params);
// Filter by confidence threshold
matches = matches.filter(match => match.confidence >= (params.confidence_threshold || 0.7));
// Filter Unity patterns if excluded
if (params.exclude_unity_patterns) {
matches = matches.filter(match => !match.isUnitySpecific);
}
// Filter partial matches if not included
if (!params.include_partial_matches) {
matches = matches.filter(match => !match.isPartialMatch);
}
result.detectedPatterns[patternType] = matches.slice(0, params.max_results_per_pattern || 10);
this.context.logger.debug(`Found ${matches.length} ${patternType} pattern matches`);
}
catch (patternError) {
this.context.logger.error(`Error detecting ${patternType} pattern:`, patternError);
result.detectedPatterns[patternType] = [];
}
}
// Step 4: Calculate summary
result.summary = this.calculatePatternSummary(result);
return result;
});
}
/**
* Detect a specific design pattern
*/
async detectPattern(patternType, classes, params) {
switch (patternType) {
case 'singleton':
return this.detectSingleton(classes);
case 'observer':
return this.detectObserver(classes);
case 'factory':
return this.detectFactory(classes);
case 'strategy':
return this.detectStrategy(classes);
case 'command':
return this.detectCommand(classes);
default:
this.context.logger.warn(`Pattern detection not implemented for: ${patternType}`);
return [];
}
}
/**
* Detect Singleton pattern
*/
async detectSingleton(classes) {
const matches = [];
for (const classDoc of classes) {
const content = classDoc.pageContent.toLowerCase();
const className = classDoc.metadata.name;
let confidence = 0;
const evidence = [];
const suggestions = [];
// Check for static instance field
const hasStaticInstance = content.includes('static') &&
(content.includes('instance') || content.includes(className.toLowerCase()));
if (hasStaticInstance) {
confidence += 0.4;
evidence.push('Has static instance field');
}
// Check for private constructor
const hasPrivateConstructor = content.includes('private') && content.includes('constructor');
if (hasPrivateConstructor) {
confidence += 0.3;
evidence.push('Has private constructor');
}
else {
suggestions.push('Consider making constructor private');
}
// Check for GetInstance method
const hasGetInstanceMethod = content.includes('getinstance') || content.includes('get_instance');
if (hasGetInstanceMethod) {
confidence += 0.3;
evidence.push('Has GetInstance method');
}
else if (confidence > 0.3) {
suggestions.push('Add public static GetInstance() method');
}
// Unity-specific check
const isUnity = classDoc.metadata.isMonoBehaviour ||
(classDoc.metadata.namespace && classDoc.metadata.namespace.includes('Unity'));
if (confidence >= 0.3) {
matches.push({
className,
fullName: classDoc.metadata.fullName,
namespace: classDoc.metadata.namespace || '',
confidence,
evidence,
implementation: confidence >= 0.8 ? 'full' : 'partial',
isPartialMatch: confidence < 0.8,
suggestions: suggestions.concat(confidence < 0.8 ? ['Ensure thread safety for multi-threaded environments'] : []),
isUnitySpecific: isUnity
});
}
}
return matches;
}
/**
* Detect Observer pattern
*/
async detectObserver(classes) {
const matches = [];
for (const classDoc of classes) {
const content = classDoc.pageContent.toLowerCase();
const className = classDoc.metadata.name;
let confidence = 0;
const evidence = [];
// Check for event/delegate patterns
if (content.includes('event') || content.includes('delegate')) {
confidence += 0.4;
evidence.push('Uses events or delegates');
}
// Check for observer-like method names
if (content.includes('notify') || content.includes('update') || content.includes('observe')) {
confidence += 0.3;
evidence.push('Has observer-pattern method names');
}
// Check for list of observers
if (content.includes('list') && (content.includes('observer') || content.includes('listener'))) {
confidence += 0.3;
evidence.push('Maintains list of observers');
}
const isUnity = classDoc.metadata.isMonoBehaviour ||
(classDoc.metadata.namespace && classDoc.metadata.namespace.includes('Unity'));
if (confidence >= 0.3) {
matches.push({
className,
fullName: classDoc.metadata.fullName,
namespace: classDoc.metadata.namespace || '',
confidence,
evidence,
implementation: confidence >= 0.8 ? 'full' : 'partial',
isPartialMatch: confidence < 0.8,
suggestions: ['Consider implementing IObserver interface', 'Add proper event handling'],
isUnitySpecific: isUnity
});
}
}
return matches;
}
/**
* Detect Factory pattern
*/
async detectFactory(classes) {
const matches = [];
for (const classDoc of classes) {
const content = classDoc.pageContent.toLowerCase();
const className = classDoc.metadata.name;
let confidence = 0;
const evidence = [];
// Check for factory method names
if (content.includes('create') || content.includes('make') || content.includes('build')) {
confidence += 0.3;
evidence.push('Has factory method names');
}
// Check for factory in class name
if (className.toLowerCase().includes('factory')) {
confidence += 0.4;
evidence.push('Class name indicates factory pattern');
}
// Check for static creation methods
if (content.includes('static') && (content.includes('create') || content.includes('make'))) {
confidence += 0.3;
evidence.push('Has static creation methods');
}
const isUnity = classDoc.metadata.isMonoBehaviour ||
(classDoc.metadata.namespace && classDoc.metadata.namespace.includes('Unity'));
if (confidence >= 0.3) {
matches.push({
className,
fullName: classDoc.metadata.fullName,
namespace: classDoc.metadata.namespace || '',
confidence,
evidence,
implementation: confidence >= 0.8 ? 'full' : 'partial',
isPartialMatch: confidence < 0.8,
suggestions: ['Consider implementing abstract factory interface'],
isUnitySpecific: isUnity
});
}
}
return matches;
}
/**
* Detect Strategy pattern
*/
async detectStrategy(classes) {
// Simplified strategy pattern detection
return [];
}
/**
* Detect Command pattern
*/
async detectCommand(classes) {
// Simplified command pattern detection
return [];
}
/**
* Calculate pattern summary statistics
*/
calculatePatternSummary(result) {
const allMatches = Object.values(result.detectedPatterns).flat();
const totalPatternsFound = allMatches.length;
const patternTypeCount = Object.keys(result.detectedPatterns).filter(pattern => result.detectedPatterns[pattern].length > 0).length;
const averageConfidence = totalPatternsFound > 0
? allMatches.reduce((sum, match) => sum + match.confidence, 0) / totalPatternsFound
: 0;
const architecturalInsights = this.generateArchitecturalInsights(result.detectedPatterns);
return {
totalPatternsFound,
patternTypeCount,
averageConfidence,
architecturalInsights
};
}
/**
* Generate architectural insights based on detected patterns
*/
generateArchitecturalInsights(detectedPatterns) {
const insights = [];
if (detectedPatterns.singleton && detectedPatterns.singleton.length > 0) {
insights.push('Codebase uses Singleton pattern for global state management');
}
if (detectedPatterns.observer && detectedPatterns.observer.length > 0) {
insights.push('Event-driven architecture detected with Observer pattern usage');
}
if (detectedPatterns.factory && detectedPatterns.factory.length > 0) {
insights.push('Object creation is abstracted using Factory patterns');
}
if (insights.length === 0) {
insights.push('No significant design patterns detected with the specified criteria');
insights.push('Consider lowering the confidence threshold or enabling partial matches');
insights.push('The codebase may use different architectural patterns not covered by this analysis');
}
return insights;
}
/**
* Format pattern detection results
*/
formatResponse(result, warnings = []) {
let response = mcp_response_formatter_1.MCPResponseFormatter.formatPatternResults(result.detectedPatterns, result.summary, result.metadata);
if (warnings.length > 0) {
response = mcp_response_formatter_1.MCPResponseFormatter.addWarnings(response, warnings);
}
return mcp_response_formatter_1.MCPResponseFormatter.addExecutionTiming(response, this.startTime, this.config.name);
}
}
exports.FindDesignPatternsToolHandler = FindDesignPatternsToolHandler;
/**
* Zod schema for find design patterns tool parameters
*/
exports.findDesignPatternsSchema = zod_1.z.object({
pattern_types: zod_1.z.array(zod_1.z.enum(["singleton", "observer", "factory", "strategy", "command", "state", "decorator", "adapter", "facade", "proxy", "builder", "template_method", "chain_of_responsibility", "mediator", "memento", "visitor", "flyweight", "composite", "bridge", "abstract_factory", "prototype", "iterator"])).describe("Array of design patterns to detect"),
confidence_threshold: zod_1.z.number().optional().default(0.7).describe("Minimum confidence level (0.1-1.0)"),
include_partial_matches: zod_1.z.boolean().optional().default(true).describe("Include partial pattern implementations"),
namespace_scope: zod_1.z.string().optional().describe("Limit search to specific namespace pattern"),
exclude_unity_patterns: zod_1.z.boolean().optional().default(false).describe("Exclude Unity-specific pattern implementations"),
max_results_per_pattern: zod_1.z.number().optional().default(10).describe("Maximum results per pattern type (1-50)")
});
/**
* Factory function to create and register the find design patterns tool
*/
function createFindDesignPatternsTool(server, context) {
const handler = new FindDesignPatternsToolHandler(context);
server.tool("find_design_patterns", exports.findDesignPatternsSchema, async (params) => {
return await handler.execute(params);
});
return handler;
}
//# sourceMappingURL=find-design-patterns-tool.js.map