// Fixed SelfLearningRefactorPlugin.cs using MarketAlly.AIPlugin; using MarketAlly.AIPlugin.Analysis.Plugins; using MarketAlly.AIPlugin.Refactoring.Plugins; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.MSBuild; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text.Json; using System.Threading.Tasks; namespace MarketAlly.AIPlugin.Learning { [AIPlugin("SelfLearningRefactor", "AI-powered self-learning refactoring system that learns from compilation results")] public class SelfLearningRefactorPlugin : IAIPlugin { [AIParameter("Solution path to analyze and improve", required: true)] public string SolutionPath { get; set; } [AIParameter("RefactorIQ database path", required: true)] public string DatabasePath { get; set; } [AIParameter("ModularMap analysis JSON path", required: false)] public string ModularMapPath { get; set; } [AIParameter("Maximum learning iterations", required: false)] public int MaxIterations { get; set; } = 5; [AIParameter("Apply changes automatically", required: false)] public bool AutoApply { get; set; } = false; [AIParameter("Backup before changes", required: false)] public bool CreateBackup { get; set; } = true; public IReadOnlyDictionary SupportedParameters => new Dictionary { ["solutionPath"] = typeof(string), ["databasePath"] = typeof(string), ["modularMapPath"] = typeof(string), ["maxIterations"] = typeof(int), ["autoApply"] = typeof(bool), ["createBackup"] = typeof(bool) }; public async Task ExecuteAsync(IReadOnlyDictionary parameters) { try { var solutionPath = parameters["solutionPath"].ToString(); var databasePath = parameters["databasePath"].ToString(); var modularMapPath = parameters.TryGetValue("modularMapPath", out var mapPath) ? mapPath?.ToString() : null; var maxIterations = parameters.TryGetValue("maxIterations", out var maxIter) ? Convert.ToInt32(maxIter) : 5; var autoApply = parameters.TryGetValue("autoApply", out var autoApplyVal) ? Convert.ToBoolean(autoApplyVal) : false; var createBackup = parameters.TryGetValue("createBackup", out var backupVal) ? Convert.ToBoolean(backupVal) : true; var learningSession = new LearningSession { SolutionPath = solutionPath, DatabasePath = databasePath, ModularMapPath = modularMapPath, MaxIterations = maxIterations, AutoApply = autoApply, CreateBackup = createBackup, StartTime = DateTime.UtcNow }; // Initialize learning system var learningEngine = new SelfLearningEngine(learningSession); // Execute learning workflow var result = await learningEngine.ExecuteLearningCycleAsync(); return new AIPluginResult(result, "Self-learning refactoring completed"); } catch (Exception ex) { return new AIPluginResult(ex, $"Self-learning refactoring failed: {ex.Message}"); } } } public class SelfLearningEngine { private readonly LearningSession _session; private readonly RefactorIQRepository _repository; private readonly CompilationValidator _validator; private readonly ModularAnalyzer _modularAnalyzer; private readonly ILogger _logger; public SelfLearningEngine(LearningSession session, ILogger logger = null) { _session = session; _repository = new RefactorIQRepository(session.DatabasePath); _validator = new CompilationValidator(); _modularAnalyzer = new ModularAnalyzer(); _logger = logger ?? CreateNullLogger(); } private static ILogger CreateNullLogger() { using var loggerFactory = LoggerFactory.Create(builder => { }); return loggerFactory.CreateLogger(); } public async Task ExecuteLearningCycleAsync() { var result = new LearningResult { SessionId = Guid.NewGuid(), StartTime = _session.StartTime, Iterations = new List() }; Console.WriteLine($"🚀 Starting self-learning cycle for: {Path.GetFileName(_session.SolutionPath)}"); // Load modular analysis if provided ModularMapData modularMap = null; if (!string.IsNullOrEmpty(_session.ModularMapPath) && File.Exists(_session.ModularMapPath)) { modularMap = await _modularAnalyzer.LoadModularMapAsync(_session.ModularMapPath); Console.WriteLine($"📊 Loaded modular analysis: {modularMap.Statistics.TotalModules} modules"); } // Create backup if requested if (_session.CreateBackup) { await CreateBackupAsync(result); } // Get baseline compilation status var baselineCompilation = await _validator.ValidateCompilationAsync(_session.SolutionPath); result.BaselineCompilation = baselineCompilation; Console.WriteLine($"📋 Baseline: {baselineCompilation.Status} ({baselineCompilation.ErrorCount} errors, {baselineCompilation.WarningCount} warnings)"); // Learning iterations for (int iteration = 1; iteration <= _session.MaxIterations; iteration++) { Console.WriteLine($"\n🔄 Learning Iteration {iteration}/{_session.MaxIterations}"); var iterationResult = await ExecuteLearningIterationAsync(iteration, modularMap, result); result.Iterations.Add(iterationResult); // Stop if we achieved perfect compilation or hit critical errors if (iterationResult.PostChangeCompilation?.Status == CompilationStatus.Success || iterationResult.CriticalError) { Console.WriteLine($"🎯 Stopping early: {(iterationResult.PostChangeCompilation?.Status == CompilationStatus.Success ? "Perfect compilation achieved" : "Critical error encountered")}"); break; } // Apply learning from this iteration await ApplyLearningFromIterationAsync(iterationResult); } result.EndTime = DateTime.UtcNow; result.TotalDuration = result.EndTime - result.StartTime; // Store learning session in database await _repository.StoreLearningSessionAsync(result); Console.WriteLine($"✅ Learning complete. Duration: {result.TotalDuration.TotalMinutes:F1} minutes"); return result; } private async Task ExecuteLearningIterationAsync(int iterationNumber, ModularMapData modularMap, LearningResult sessionResult) { var iteration = new LearningIteration { IterationNumber = iterationNumber, StartTime = DateTime.UtcNow, Suggestions = new List(), AppliedChanges = new List() }; try { // 1. Analyze current code state Console.WriteLine("🔍 Analyzing current code state..."); var codeAnalysis = await AnalyzeCurrentCodeStateAsync(modularMap); iteration.CodeAnalysis = codeAnalysis; // 2. Generate AI suggestions based on patterns and database Console.WriteLine("🧠 Generating AI suggestions..."); var suggestions = await GenerateAISuggestionsAsync(codeAnalysis, sessionResult); iteration.Suggestions = suggestions; if (!suggestions.Any()) { Console.WriteLine("ℹ️ No suggestions generated for this iteration"); return iteration; } // 3. Select best suggestion based on learning history var selectedSuggestion = await SelectBestSuggestionAsync(suggestions, sessionResult); Console.WriteLine($"💡 Selected suggestion: {selectedSuggestion.Type} (confidence: {selectedSuggestion.Confidence:F2})"); // 4. Apply suggestion and validate if (_session.AutoApply || await PromptForApplicationAsync(selectedSuggestion)) { var change = await ApplySuggestionAsync(selectedSuggestion); iteration.AppliedChanges.Add(change); // 5. Validate compilation after change Console.WriteLine("🔨 Validating compilation..."); var postCompilation = await _validator.ValidateCompilationAsync(_session.SolutionPath); iteration.PostChangeCompilation = postCompilation; // 6. Update learning metrics await UpdateLearningMetricsAsync(selectedSuggestion, change, postCompilation); Console.WriteLine($"📊 Post-change: {postCompilation.Status} ({postCompilation.ErrorCount} errors, {postCompilation.WarningCount} warnings)"); } } catch (Exception ex) { iteration.CriticalError = true; iteration.ErrorMessage = ex.Message; Console.WriteLine($"❌ Critical error in iteration {iterationNumber}: {ex.Message}"); } finally { iteration.EndTime = DateTime.UtcNow; iteration.Duration = iteration.EndTime - iteration.StartTime; } return iteration; } private async Task AnalyzeCurrentCodeStateAsync(ModularMapData modularMap) { var snapshot = new CodeAnalysisSnapshot { Timestamp = DateTime.UtcNow, Issues = new List(), Metrics = new CodeMetrics() }; // Analyze using Roslyn using var workspace = MSBuildWorkspace.Create(); var solution = await workspace.OpenSolutionAsync(_session.SolutionPath); // Create a simple plugin registry for analysis var logger = CreateNullLogger(); var pluginRegistry = new AIPluginRegistry(logger); pluginRegistry.RegisterPlugin(new CodeAnalysisPlugin()); foreach (var project in solution.Projects) { var compilation = await project.GetCompilationAsync(); foreach (var document in project.Documents) { if (document.FilePath?.EndsWith(".cs") != true) continue; var syntaxTree = await document.GetSyntaxTreeAsync(); var root = await syntaxTree.GetRootAsync(); // Extract metrics and issues try { var analysisResult = await pluginRegistry.CallFunctionAsync("CodeAnalysis", new Dictionary { ["path"] = document.FilePath, ["analysisDepth"] = "detailed" }); if (analysisResult.Success && analysisResult.Data != null) { // Process analysis results await ProcessAnalysisResultsAsync(snapshot, analysisResult.Data, document.FilePath); } } catch (Exception ex) { _logger.LogWarning($"Failed to analyze {document.FilePath}: {ex.Message}"); } } } // Integrate modular map insights if (modularMap != null) { snapshot.ModularInsights = ExtractModularInsights(modularMap); } return snapshot; } private async Task> GenerateAISuggestionsAsync(CodeAnalysisSnapshot analysis, LearningResult sessionResult) { var suggestions = new List(); // Query database for historical patterns var historicalPatterns = await _repository.GetSuccessfulPatternsAsync(); var previousFailures = await _repository.GetFailurePatternsAsync(); // Generate suggestions based on code issues foreach (var issue in analysis.Issues.Take(5)) // Limit to top 5 issues { var suggestion = await GenerateSuggestionForIssueAsync(issue, historicalPatterns, previousFailures); if (suggestion != null) { suggestions.Add(suggestion); } } // Generate modular improvement suggestions if (analysis.ModularInsights?.Any() == true) { var modularSuggestions = await GenerateModularSuggestionsAsync(analysis.ModularInsights); suggestions.AddRange(modularSuggestions); } // Rank suggestions by confidence and learning history return suggestions.OrderByDescending(s => s.Confidence).ToList(); } private async Task GenerateSuggestionForIssueAsync(CodeIssue issue, List patterns, List failures) { // Find matching patterns var matchingPattern = patterns.FirstOrDefault(p => p.IssueType == issue.Type); var avoidPatterns = failures.Where(f => f.IssueType == issue.Type).ToList(); if (matchingPattern == null) return null; var suggestion = new AISuggestion { Id = Guid.NewGuid(), Type = DetermineSuggestionType(issue.Type), Description = GenerateDescriptionFromPattern(matchingPattern, issue), TargetFile = issue.FilePath, TargetLine = issue.LineNumber, Confidence = CalculateConfidence(matchingPattern, avoidPatterns), GeneratedAt = DateTime.UtcNow, ExpectedImprovement = matchingPattern.AverageImprovement, RiskLevel = CalculateRiskLevel(matchingPattern, avoidPatterns) }; // Generate specific code change suggestion (simplified) suggestion.ProposedChange = await GenerateCodeChangeSuggestionAsync(issue, matchingPattern); return suggestion; } // Fixed: Add the missing GenerateCodeChangeSuggestionAsync method private async Task GenerateCodeChangeSuggestionAsync(CodeIssue issue, SuccessPattern pattern) { // Generate a text-based suggestion for the code change var suggestionText = issue.Type.ToLower() switch { "long method" => $"Extract method to reduce complexity in {Path.GetFileName(issue.FilePath)} at line {issue.LineNumber}", "meaningless name" => $"Rename variable to use meaningful name in {Path.GetFileName(issue.FilePath)} at line {issue.LineNumber}", "missing documentation" => $"Add XML documentation to method in {Path.GetFileName(issue.FilePath)} at line {issue.LineNumber}", "complex expression" => $"Simplify expression in {Path.GetFileName(issue.FilePath)} at line {issue.LineNumber}", "unused code" => $"Remove unused code in {Path.GetFileName(issue.FilePath)} at line {issue.LineNumber}", _ => $"Apply {pattern.PatternName} improvement to {Path.GetFileName(issue.FilePath)} at line {issue.LineNumber}" }; return await Task.FromResult(suggestionText); } private async Task SelectBestSuggestionAsync(List suggestions, LearningResult sessionResult) { // Weight suggestions by: // 1. Confidence score // 2. Expected improvement // 3. Risk level (lower is better) // 4. Learning from previous iterations var weighted = suggestions.Select(s => new { Suggestion = s, Score = (s.Confidence * 0.4) + (s.ExpectedImprovement * 0.3) + ((1.0 - s.RiskLevel) * 0.2) + (GetLearningBonus(s, sessionResult) * 0.1) }).OrderByDescending(w => w.Score); return weighted.First().Suggestion; } private async Task ApplySuggestionAsync(AISuggestion suggestion) { var change = new AppliedChange { SuggestionId = suggestion.Id, FilePath = suggestion.TargetFile, StartTime = DateTime.UtcNow, Success = false }; try { // Read original file var originalContent = await File.ReadAllTextAsync(suggestion.TargetFile); change.OriginalContent = originalContent; // Apply the suggested change using appropriate plugin var modifiedContent = await ApplyCodeChangeAsync(originalContent, suggestion); change.ModifiedContent = modifiedContent; // Write modified content await File.WriteAllTextAsync(suggestion.TargetFile, modifiedContent); change.Success = true; Console.WriteLine($"✅ Applied change to {Path.GetFileName(suggestion.TargetFile)}"); } catch (Exception ex) { change.ErrorMessage = ex.Message; Console.WriteLine($"❌ Failed to apply change: {ex.Message}"); } finally { change.EndTime = DateTime.UtcNow; } return change; } private async Task ApplyCodeChangeAsync(string originalContent, AISuggestion suggestion) { // Create a simple plugin registry for applying changes var logger = CreateNullLogger(); var pluginRegistry = new AIPluginRegistry(logger); // Register required plugins pluginRegistry.RegisterPlugin(new EnhancedDocumentationGeneratorPlugin()); pluginRegistry.RegisterPlugin(new CodeFormatterPlugin()); pluginRegistry.RegisterPlugin(new NamingConventionPlugin()); try { // Apply changes based on suggestion type var result = suggestion.Type switch { SuggestionType.AddDocumentation => await pluginRegistry.CallFunctionAsync("EnhancedDocumentationGenerator", new Dictionary { ["filePath"] = suggestion.TargetFile, ["style"] = "intelligent", ["applyChanges"] = false }), SuggestionType.RenameVariable => await pluginRegistry.CallFunctionAsync("NamingConvention", new Dictionary { ["filePath"] = suggestion.TargetFile, ["convention"] = "pascal", ["applyChanges"] = false }), _ => await pluginRegistry.CallFunctionAsync("CodeFormatter", new Dictionary { ["path"] = suggestion.TargetFile, ["formattingStyle"] = "microsoft", ["applyChanges"] = false }) }; if (result.Success && result.Data != null) { // Extract modified content from plugin result var data = JsonSerializer.Deserialize(JsonSerializer.Serialize(result.Data)); if (data.TryGetProperty("ModifiedContent", out var contentElement)) { return contentElement.GetString() ?? originalContent; } } } catch (Exception ex) { _logger.LogWarning($"Failed to apply code change: {ex.Message}"); } // Fallback: return original content with minimal formatting return await FormatCodeBasicAsync(originalContent); } private async Task FormatCodeBasicAsync(string code) { try { // Parse and reformat the code var syntaxTree = CSharpSyntaxTree.ParseText(code); var root = await syntaxTree.GetRootAsync(); return root.NormalizeWhitespace().ToFullString(); } catch { // If parsing fails, return original return code; } } private async Task UpdateLearningMetricsAsync(AISuggestion suggestion, AppliedChange change, CompilationResult compilation) { var learningRecord = new LearningRecord { SuggestionId = suggestion.Id, SuggestionType = suggestion.Type, Confidence = suggestion.Confidence, ExpectedImprovement = suggestion.ExpectedImprovement, ActualImprovement = CalculateActualImprovement(compilation), Success = change.Success && compilation.Status != CompilationStatus.Failed, CompilationStatus = compilation.Status, ErrorCountBefore = compilation.PreviousErrorCount ?? 0, ErrorCountAfter = compilation.ErrorCount, Timestamp = DateTime.UtcNow }; await _repository.StoreLearningRecordAsync(learningRecord); } private async Task ApplyLearningFromIterationAsync(LearningIteration iteration) { // Update confidence models based on results foreach (var change in iteration.AppliedChanges.Where(c => c.Success)) { var suggestion = iteration.Suggestions.First(s => s.Id == change.SuggestionId); // If compilation improved, boost confidence for this pattern if (iteration.PostChangeCompilation?.ErrorCount < iteration.PostChangeCompilation?.PreviousErrorCount) { await _repository.BoostPatternConfidenceAsync(suggestion.Type, 0.1); } else if (iteration.PostChangeCompilation?.Status == CompilationStatus.Failed) { // If compilation failed, reduce confidence await _repository.ReducePatternConfidenceAsync(suggestion.Type, 0.2); } } } // Helper methods private double CalculateConfidence(SuccessPattern pattern, List failures) { var baseConfidence = pattern.SuccessRate; var failurePenalty = failures.Sum(f => f.FailureRate) / Math.Max(failures.Count, 1); return Math.Max(0.1, Math.Min(1.0, baseConfidence - (failurePenalty * 0.5))); } private double CalculateRiskLevel(SuccessPattern pattern, List failures) { return failures.Any() ? failures.Average(f => f.FailureRate) : 0.1; } private double GetLearningBonus(AISuggestion suggestion, LearningResult sessionResult) { // Boost suggestions that worked well in previous iterations var previousSuccesses = sessionResult.Iterations .SelectMany(i => i.AppliedChanges) .Where(c => c.Success) .Count(); return previousSuccesses > 0 ? 0.1 : 0.0; } private async Task CreateBackupAsync(LearningResult result) { var backupDir = Path.Combine(Path.GetDirectoryName(_session.SolutionPath), $"backup_{DateTime.Now:yyyyMMdd_HHmmss}"); Directory.CreateDirectory(backupDir); var solutionDir = Path.GetDirectoryName(_session.SolutionPath); await CopyDirectoryAsync(solutionDir, backupDir); result.BackupPath = backupDir; Console.WriteLine($"💾 Backup created: {backupDir}"); } private async Task CopyDirectoryAsync(string sourceDir, string destDir) { Directory.CreateDirectory(destDir); foreach (var file in Directory.GetFiles(sourceDir)) { var destFile = Path.Combine(destDir, Path.GetFileName(file)); File.Copy(file, destFile, true); } foreach (var subDir in Directory.GetDirectories(sourceDir)) { if (Path.GetFileName(subDir).StartsWith(".") || Path.GetFileName(subDir) == "bin" || Path.GetFileName(subDir) == "obj") continue; var destSubDir = Path.Combine(destDir, Path.GetFileName(subDir)); await CopyDirectoryAsync(subDir, destSubDir); } } private async Task PromptForApplicationAsync(AISuggestion suggestion) { Console.WriteLine($"\n💡 Suggested Change:"); Console.WriteLine($" Type: {suggestion.Type}"); Console.WriteLine($" File: {Path.GetFileName(suggestion.TargetFile)}"); Console.WriteLine($" Line: {suggestion.TargetLine}"); Console.WriteLine($" Description: {suggestion.Description}"); Console.WriteLine($" Confidence: {suggestion.Confidence:F2}"); Console.WriteLine($" Risk: {suggestion.RiskLevel:F2}"); Console.Write("Apply this change? (y/n): "); var response = Console.ReadLine(); return response?.ToLower().StartsWith("y") == true; } private double CalculateActualImprovement(CompilationResult compilation) { if (compilation.PreviousErrorCount.HasValue) { var errorReduction = compilation.PreviousErrorCount.Value - compilation.ErrorCount; return errorReduction / Math.Max(compilation.PreviousErrorCount.Value, 1.0); } return 0.0; } private async Task ProcessAnalysisResultsAsync(CodeAnalysisSnapshot snapshot, object analysisData, string filePath) { // Convert analysis results to code issues var json = JsonSerializer.Serialize(analysisData); var data = JsonSerializer.Deserialize(json); if (data.TryGetProperty("DetailedResults", out var results) && results.ValueKind == JsonValueKind.Array) { foreach (var result in results.EnumerateArray()) { if (result.TryGetProperty("CodeSmells", out var smells) && smells.ValueKind == JsonValueKind.Array) { foreach (var smell in smells.EnumerateArray()) { var issue = new CodeIssue { Type = smell.TryGetProperty("Type", out var type) ? type.GetString() : "Unknown", Description = smell.TryGetProperty("Description", out var desc) ? desc.GetString() : "", FilePath = filePath, Severity = smell.TryGetProperty("Severity", out var sev) ? sev.GetString() : "Medium" }; // Extract line number from location if available if (smell.TryGetProperty("Location", out var location)) { var locationStr = location.GetString(); if (locationStr.StartsWith("Line ")) { if (int.TryParse(locationStr.Substring(5), out var lineNum)) { issue.LineNumber = lineNum; } } } snapshot.Issues.Add(issue); } } } } } private List ExtractModularInsights(ModularMapData modularMap) { var insights = new List(); // Extract insights from coupling metrics if (modularMap.CouplingMetrics?.HighlyCoupledModules?.Any() == true) { foreach (var module in modularMap.CouplingMetrics.HighlyCoupledModules) { insights.Add(new ModularInsight { Type = "HighCoupling", Module = module, Description = $"Module {module} has high coupling", Severity = "High" }); } } return insights; } private SuggestionType DetermineSuggestionType(string issueType) { return issueType.ToLower() switch { "long method" => SuggestionType.ExtractMethod, "meaningless name" => SuggestionType.RenameVariable, "missing documentation" => SuggestionType.AddDocumentation, "complex expression" => SuggestionType.SimplifyExpression, "unused code" => SuggestionType.RemoveDeadCode, _ => SuggestionType.Other }; } private string GenerateDescriptionFromPattern(SuccessPattern pattern, CodeIssue issue) { return $"Apply {pattern.PatternName} to resolve {issue.Type} in {Path.GetFileName(issue.FilePath)}"; } private async Task> GenerateModularSuggestionsAsync(List insights) { var suggestions = new List(); foreach (var insight in insights.Take(3)) // Limit modular suggestions { if (insight.Type == "HighCoupling") { suggestions.Add(new AISuggestion { Id = Guid.NewGuid(), Type = SuggestionType.ReduceCoupling, Description = $"Extract interface to reduce coupling in {insight.Module}", Confidence = 0.7, ExpectedImprovement = 0.3, RiskLevel = 0.2, GeneratedAt = DateTime.UtcNow }); } } return suggestions; } } }