Files
gitcommiteditor/Plugins/GenerateCommitMessagePlugin.cs

136 lines
4.9 KiB
C#

using MarketAlly.AIPlugin;
namespace MarketAlly.GitCommitEditor.Plugins;
/// <summary>
/// Valid conventional commit types
/// </summary>
public enum CommitType
{
/// <summary>New feature</summary>
feat,
/// <summary>Bug fix</summary>
fix,
/// <summary>Documentation only</summary>
docs,
/// <summary>Formatting, whitespace (no code change)</summary>
style,
/// <summary>Code change that neither fixes a bug nor adds a feature</summary>
refactor,
/// <summary>Performance improvement</summary>
perf,
/// <summary>Adding or updating tests</summary>
test,
/// <summary>Build system or dependencies</summary>
build,
/// <summary>CI/CD configuration</summary>
ci,
/// <summary>Maintenance tasks, logging, tooling</summary>
chore
}
/// <summary>
/// Result model for the commit message generation
/// </summary>
public class CommitMessageResult
{
public CommitType Type { get; set; } = CommitType.chore;
public string? Scope { get; set; }
public string Description { get; set; } = string.Empty;
public string Body { get; set; } = string.Empty;
/// <summary>
/// Gets the formatted subject line: type(scope): description
/// </summary>
public string Subject => string.IsNullOrEmpty(Scope)
? $"{Type}: {Description}"
: $"{Type}({Scope}): {Description}";
}
/// <summary>
/// AI Plugin for generating improved commit messages following conventional commit format
/// </summary>
[AIPlugin("GenerateCommitMessage", "Generates an improved git commit message based on the original message, changed files, and diff content. Returns a structured result with subject line and optional body.")]
public class GenerateCommitMessagePlugin : IAIPlugin
{
[AIParameter("The original commit message to improve", required: true)]
public string OriginalMessage { get; set; } = string.Empty;
[AIParameter("List of file paths that were changed in the commit", required: true)]
public List<string> FilesChanged { get; set; } = new();
[AIParameter("Number of lines added in the commit", required: true)]
public int LinesAdded { get; set; }
[AIParameter("Number of lines deleted in the commit", required: true)]
public int LinesDeleted { get; set; }
[AIParameter("Summary of the diff/changes (truncated)", required: false)]
public string? DiffSummary { get; set; }
[AIParameter("List of quality issues detected in the original message", required: false)]
public List<string>? QualityIssues { get; set; }
public IReadOnlyDictionary<string, Type> SupportedParameters => new Dictionary<string, Type>
{
["originalMessage"] = typeof(string),
["filesChanged"] = typeof(List<string>),
["linesAdded"] = typeof(int),
["linesDeleted"] = typeof(int),
["diffSummary"] = typeof(string),
["qualityIssues"] = typeof(List<string>)
};
public Task<AIPluginResult> ExecuteAsync(IReadOnlyDictionary<string, object> parameters)
{
var result = new CommitMessageResult
{
Type = CommitType.chore,
Description = OriginalMessage,
Body = string.Empty
};
return Task.FromResult(new AIPluginResult(result, "Commit message generated"));
}
}
/// <summary>
/// AI Plugin that the AI calls to return the generated commit message
/// </summary>
[AIPlugin("ReturnCommitMessage", "Returns the generated commit message. Call this after analyzing the commit to provide the improved message in conventional commit format.")]
public class ReturnCommitMessagePlugin : IAIPlugin
{
[AIParameter("The commit type", required: true)]
public CommitType Type { get; set; } = CommitType.chore;
[AIParameter("Optional scope/area of the codebase affected (e.g., 'api', 'ui', 'auth'). Omit if not applicable.", required: false)]
public string? Scope { get; set; }
[AIParameter("Short description of the change (max 60 chars, imperative mood, no period). Example: 'add user authentication'", required: true)]
public string Description { get; set; } = string.Empty;
[AIParameter("Optional extended description explaining what changed and why. Leave empty if the subject is self-explanatory.", required: false)]
public string Body { get; set; } = string.Empty;
public IReadOnlyDictionary<string, Type> SupportedParameters => new Dictionary<string, Type>
{
["type"] = typeof(CommitType),
["scope"] = typeof(string),
["description"] = typeof(string),
["body"] = typeof(string)
};
public Task<AIPluginResult> ExecuteAsync(IReadOnlyDictionary<string, object> parameters)
{
var result = new CommitMessageResult
{
Type = Type,
Scope = Scope,
Description = Description,
Body = Body ?? string.Empty
};
return Task.FromResult(new AIPluginResult(result, "Commit message returned"));
}
}