UNPKG

il2cpp-dump-analyzer-mcp

Version:

Agentic RAG system for analyzing IL2CPP dump.cs files from Unity games

308 lines 13.7 kB
"use strict"; /** * @fileoverview Analyze Type Hierarchies MCP Tool * * Provides comprehensive analysis of IL2CPP type inheritance hierarchies including: * - Inheritance hierarchy analysis and interface implementations * - Multiple inheritance pattern detection * - Orphaned type identification * - Namespace-based filtering and depth-limited analysis * * This tool implements the type hierarchy analysis functionality from TypeAnalyzer * as an MCP tool following established patterns and TFD methodology. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.analyzeTypeHierarchiesSchema = exports.AnalyzeTypeHierarchiesTool = void 0; exports.createAnalyzeTypeHierarchiesTool = createAnalyzeTypeHierarchiesTool; const zod_1 = require("zod"); const base_tool_handler_1 = require("../base-tool-handler"); const mcp_response_formatter_1 = require("../../utils/mcp-response-formatter"); /** * Zod schema for analyze type hierarchies parameters */ const AnalyzeTypeHierarchiesSchema = zod_1.z.object({ target_type: zod_1.z.string().optional().describe('Specific type to analyze (optional, analyzes all types if not provided)'), include_interfaces: zod_1.z.boolean().default(true).describe('Whether to include interface implementations in analysis'), max_depth: zod_1.z.number().min(1).max(10).default(5).describe('Maximum hierarchy depth to analyze (1-10)'), namespace_filter: zod_1.z.string().optional().describe('Filter analysis to specific namespace pattern') }); /** * Analyze Type Hierarchies MCP Tool Implementation * * Analyzes IL2CPP type inheritance hierarchies and relationships using vector store search. * Provides comprehensive hierarchy analysis with interface support and filtering capabilities. */ class AnalyzeTypeHierarchiesTool extends base_tool_handler_1.BaseAnalysisToolHandler { constructor(context) { super({ name: 'analyze_type_hierarchies', description: 'Analyze inheritance hierarchies and interface implementations in IL2CPP dumps', enableParameterValidation: true, enableResponseFormatting: true }, context); } /** * Validate input parameters using Zod schema */ async validateParameters(params) { const errors = []; const warnings = []; const adjustedValues = {}; // Validate max_depth parameter if (params.max_depth !== undefined) { if (typeof params.max_depth !== 'number' || params.max_depth < 1 || params.max_depth > 10) { errors.push('max_depth must be a number between 1 and 10'); } } else { adjustedValues.max_depth = 5; } // Set defaults for boolean parameters if (params.include_interfaces === undefined) { adjustedValues.include_interfaces = true; } if (params.include_abstract_classes === undefined) { adjustedValues.include_abstract_classes = true; } if (params.include_system_types === undefined) { adjustedValues.include_system_types = false; } // Validate target_type if provided if (params.target_type && typeof params.target_type !== 'string') { errors.push('target_type must be a string'); } return { isValid: errors.length === 0, errors, warnings, adjustedValues }; } /** * Execute type hierarchy analysis */ async executeCore(params) { return await this.performAnalysis(async () => { this.context.logger.debug('Starting type hierarchy analysis', { params }); // Step 1: Get all classes or specific target type let classDocuments; if (params.target_type) { // Search for specific target type const targetResults = await this.context.vectorStore.searchWithFilter(params.target_type, { type: 'class' }, 1); if (targetResults.length === 0) { throw new Error(`Target type '${params.target_type}' not found in IL2CPP dump`); } // Get all classes for hierarchy building classDocuments = await this.context.vectorStore.searchWithFilter('', { type: 'class' }, 1000); } else { // Get all classes classDocuments = await this.context.vectorStore.searchWithFilter('', { type: 'class' }, 1000); } if (classDocuments.length === 0) { throw new Error('No classes found in IL2CPP dump for hierarchy analysis'); } this.context.logger.debug(`Found ${classDocuments.length} classes for analysis`); // Step 2: Apply namespace filtering if specified if (params.namespace_filter) { classDocuments = classDocuments.filter(doc => doc.metadata.namespace?.includes(params.namespace_filter)); this.context.logger.debug(`Filtered to ${classDocuments.length} classes in namespace '${params.namespace_filter}'`); } // Step 3: Build type hierarchy analysis const hierarchies = this.buildInheritanceHierarchies(classDocuments, params); const multipleInheritancePatterns = this.detectMultipleInheritancePatterns(classDocuments, params); const orphanedTypes = this.identifyOrphanedTypes(classDocuments); // Step 4: Calculate analysis metrics const maxDepth = Math.max(...hierarchies.map(h => h.maxDepth), 0); const totalHierarchies = hierarchies.length; const result = { hierarchies, multipleInheritancePatterns, orphanedTypes, maxDepth, totalHierarchies, analysisMetadata: { targetType: params.target_type, includeInterfaces: params.include_interfaces ?? true, maxDepthLimit: params.max_depth ?? 5, namespaceFilter: params.namespace_filter, timestamp: new Date().toISOString(), totalTypesAnalyzed: classDocuments.length } }; this.context.logger.debug('Type hierarchy analysis completed', { hierarchies: totalHierarchies, maxDepth, orphanedTypes: orphanedTypes.length, multipleInheritance: multipleInheritancePatterns.length }); return result; }); } /** * Build inheritance hierarchies from class documents */ buildInheritanceHierarchies(classDocuments, params) { const hierarchies = []; const processedTypes = new Set(); const maxDepth = params.max_depth ?? 5; // Create type lookup map const typeMap = new Map(); classDocuments.forEach(doc => { const fullName = `${doc.metadata.namespace}.${doc.metadata.name}`; typeMap.set(fullName, doc); }); // Find root types (types with no base class or base class not in our set) const rootTypes = classDocuments.filter(doc => { const baseClass = doc.metadata.baseClass; if (!baseClass) return true; const baseFullName = baseClass.includes('.') ? baseClass : `${doc.metadata.namespace}.${baseClass}`; return !typeMap.has(baseFullName); }); // Build hierarchy for each root type for (const rootDoc of rootTypes) { const fullName = `${rootDoc.metadata.namespace}.${rootDoc.metadata.name}`; if (processedTypes.has(fullName)) continue; const hierarchy = this.buildHierarchyFromRoot(rootDoc, typeMap, processedTypes, maxDepth, params); if (hierarchy) { hierarchies.push(hierarchy); } } return hierarchies; } /** * Build hierarchy tree from a root type */ buildHierarchyFromRoot(rootDoc, typeMap, processedTypes, maxDepth, params) { const rootNode = this.createHierarchyNode(rootDoc, typeMap, processedTypes, 0, maxDepth, params); if (!rootNode) return null; const hierarchy = { rootType: rootNode, totalNodes: this.countNodes(rootNode), maxDepth: this.calculateMaxDepth(rootNode), hasInterfaces: this.hasInterfaceImplementations(rootNode) }; return hierarchy; } /** * Create a hierarchy node recursively */ createHierarchyNode(doc, typeMap, processedTypes, depth, maxDepth, params) { if (depth >= maxDepth) return null; const fullName = `${doc.metadata.namespace}.${doc.metadata.name}`; if (processedTypes.has(fullName)) return null; processedTypes.add(fullName); const node = { typeName: doc.metadata.name, namespace: doc.metadata.namespace || '', typeDefIndex: doc.metadata.typeDefIndex || 0, baseType: doc.metadata.baseClass, derivedTypes: [], depth, interfaces: params.include_interfaces ? (doc.metadata.interfaces || []) : [] }; // Find derived types const derivedDocs = Array.from(typeMap.values()).filter(derivedDoc => { const derivedBaseClass = derivedDoc.metadata.baseClass; if (!derivedBaseClass) return false; return derivedBaseClass === doc.metadata.name || derivedBaseClass === fullName; }); // Recursively build derived types for (const derivedDoc of derivedDocs) { const derivedNode = this.createHierarchyNode(derivedDoc, typeMap, processedTypes, depth + 1, maxDepth, params); if (derivedNode) { node.derivedTypes.push(derivedNode); } } return node; } /** * Detect multiple inheritance patterns (class + interfaces) */ detectMultipleInheritancePatterns(classDocuments, params) { if (!params.include_interfaces) return []; return classDocuments .filter(doc => doc.metadata.baseClass && doc.metadata.interfaces?.length > 0) .map(doc => ({ typeName: doc.metadata.name, namespace: doc.metadata.namespace || '', baseClass: doc.metadata.baseClass, interfaces: doc.metadata.interfaces || [], complexityScore: (doc.metadata.interfaces?.length || 0) + 1 })) .sort((a, b) => b.complexityScore - a.complexityScore); } /** * Identify orphaned types (no base class, no derived types) */ identifyOrphanedTypes(classDocuments) { const typeNames = new Set(classDocuments.map(doc => doc.metadata.name)); return classDocuments .filter(doc => { const hasBaseClass = !!doc.metadata.baseClass && typeNames.has(doc.metadata.baseClass); const hasDerivedTypes = classDocuments.some(otherDoc => otherDoc.metadata.baseClass === doc.metadata.name); return !hasBaseClass && !hasDerivedTypes; }) .map(doc => `${doc.metadata.namespace}.${doc.metadata.name}`); } /** * Count total nodes in hierarchy tree */ countNodes(node) { return 1 + node.derivedTypes.reduce((sum, child) => sum + this.countNodes(child), 0); } /** * Calculate maximum depth of hierarchy tree */ calculateMaxDepth(node) { if (node.derivedTypes.length === 0) return node.depth; return Math.max(...node.derivedTypes.map(child => this.calculateMaxDepth(child))); } /** * Check if hierarchy has interface implementations */ hasInterfaceImplementations(node) { return node.interfaces.length > 0 || node.derivedTypes.some(child => this.hasInterfaceImplementations(child)); } /** * Format hierarchy analysis results */ formatResponse(result, warnings = []) { let response = mcp_response_formatter_1.MCPResponseFormatter.formatAnalysisResults(result, this.config.name, result.analysisMetadata, Date.now() - this.startTime); if (warnings.length > 0) { response = mcp_response_formatter_1.MCPResponseFormatter.addWarnings(response, warnings); } return response; } } exports.AnalyzeTypeHierarchiesTool = AnalyzeTypeHierarchiesTool; /** * Zod schema for analyze type hierarchies tool parameters */ exports.analyzeTypeHierarchiesSchema = zod_1.z.object({ target_type: zod_1.z.string().optional().describe("Specific type to analyze (optional, analyzes all types if not provided)"), include_interfaces: zod_1.z.boolean().optional().default(true).describe("Include interface implementations in hierarchy analysis"), max_depth: zod_1.z.number().min(1).max(10).optional().default(5).describe("Maximum depth to traverse in hierarchy (1-10)"), namespace_filter: zod_1.z.string().optional().describe("Filter results to specific namespace pattern") }); /** * Factory function to create and register the analyze type hierarchies tool */ function createAnalyzeTypeHierarchiesTool(server, context) { const handler = new AnalyzeTypeHierarchiesTool(context); server.tool("analyze_type_hierarchies", exports.analyzeTypeHierarchiesSchema, async (params) => { return await handler.execute(params); }); return handler; } //# sourceMappingURL=analyze-type-hierarchies-tool.js.map