727 lines
25 KiB
C#
Executable File
727 lines
25 KiB
C#
Executable File
// 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<string, Type> SupportedParameters => new Dictionary<string, Type>
|
||
{
|
||
["solutionPath"] = typeof(string),
|
||
["databasePath"] = typeof(string),
|
||
["modularMapPath"] = typeof(string),
|
||
["maxIterations"] = typeof(int),
|
||
["autoApply"] = typeof(bool),
|
||
["createBackup"] = typeof(bool)
|
||
};
|
||
|
||
public async Task<AIPluginResult> ExecuteAsync(IReadOnlyDictionary<string, object> 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<AIPluginRegistry> _logger;
|
||
|
||
public SelfLearningEngine(LearningSession session, ILogger<AIPluginRegistry> logger = null)
|
||
{
|
||
_session = session;
|
||
_repository = new RefactorIQRepository(session.DatabasePath);
|
||
_validator = new CompilationValidator();
|
||
_modularAnalyzer = new ModularAnalyzer();
|
||
_logger = logger ?? CreateNullLogger();
|
||
}
|
||
|
||
private static ILogger<AIPluginRegistry> CreateNullLogger()
|
||
{
|
||
using var loggerFactory = LoggerFactory.Create(builder => { });
|
||
return loggerFactory.CreateLogger<AIPluginRegistry>();
|
||
}
|
||
|
||
public async Task<LearningResult> ExecuteLearningCycleAsync()
|
||
{
|
||
var result = new LearningResult
|
||
{
|
||
SessionId = Guid.NewGuid(),
|
||
StartTime = _session.StartTime,
|
||
Iterations = new List<LearningIteration>()
|
||
};
|
||
|
||
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<LearningIteration> ExecuteLearningIterationAsync(int iterationNumber, ModularMapData modularMap, LearningResult sessionResult)
|
||
{
|
||
var iteration = new LearningIteration
|
||
{
|
||
IterationNumber = iterationNumber,
|
||
StartTime = DateTime.UtcNow,
|
||
Suggestions = new List<AISuggestion>(),
|
||
AppliedChanges = new List<AppliedChange>()
|
||
};
|
||
|
||
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<CodeAnalysisSnapshot> AnalyzeCurrentCodeStateAsync(ModularMapData modularMap)
|
||
{
|
||
var snapshot = new CodeAnalysisSnapshot
|
||
{
|
||
Timestamp = DateTime.UtcNow,
|
||
Issues = new List<CodeIssue>(),
|
||
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<string, object>
|
||
{
|
||
["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<List<AISuggestion>> GenerateAISuggestionsAsync(CodeAnalysisSnapshot analysis, LearningResult sessionResult)
|
||
{
|
||
var suggestions = new List<AISuggestion>();
|
||
|
||
// 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<AISuggestion> GenerateSuggestionForIssueAsync(CodeIssue issue, List<SuccessPattern> patterns, List<FailurePattern> 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<string> 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<AISuggestion> SelectBestSuggestionAsync(List<AISuggestion> 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<AppliedChange> 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<string> 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<string, object>
|
||
{
|
||
["filePath"] = suggestion.TargetFile,
|
||
["style"] = "intelligent",
|
||
["applyChanges"] = false
|
||
}),
|
||
|
||
SuggestionType.RenameVariable => await pluginRegistry.CallFunctionAsync("NamingConvention", new Dictionary<string, object>
|
||
{
|
||
["filePath"] = suggestion.TargetFile,
|
||
["convention"] = "pascal",
|
||
["applyChanges"] = false
|
||
}),
|
||
|
||
_ => await pluginRegistry.CallFunctionAsync("CodeFormatter", new Dictionary<string, object>
|
||
{
|
||
["path"] = suggestion.TargetFile,
|
||
["formattingStyle"] = "microsoft",
|
||
["applyChanges"] = false
|
||
})
|
||
};
|
||
|
||
if (result.Success && result.Data != null)
|
||
{
|
||
// Extract modified content from plugin result
|
||
var data = JsonSerializer.Deserialize<JsonElement>(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<string> 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<FailurePattern> 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<FailurePattern> 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<bool> 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<JsonElement>(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<ModularInsight> ExtractModularInsights(ModularMapData modularMap)
|
||
{
|
||
var insights = new List<ModularInsight>();
|
||
|
||
// 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<List<AISuggestion>> GenerateModularSuggestionsAsync(List<ModularInsight> insights)
|
||
{
|
||
var suggestions = new List<AISuggestion>();
|
||
|
||
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;
|
||
}
|
||
}
|
||
} |