feat(mcp): expose the conflict resolver's hunk API over MCP
get_merge_conflicts and resolve_conflict_hunk let an MCP caller resolve a leaveConflictsInTree merge hunk-by-hunk (ours/theirs/base/literal text) instead of grep-parsing diff3 markers itself. Reuses the existing TaskMergeService/ConflictMarkerParser machinery (adds MergeSegment.StartLine and a non-staging TaskMergeService.WriteConflictFileAsync) rather than a second parser. A partially resolved file is written without git add so continue_merge keeps refusing while any hunk still has markers.
This commit is contained in:
@@ -25,10 +25,13 @@ public sealed record MergeSegment
|
||||
/// <summary>"Theirs" side (the incoming branch) when <see cref="IsConflict"/> is true.</summary>
|
||||
public string Theirs { get; init; } = "";
|
||||
|
||||
public static MergeSegment Stable(string text) => new() { Text = text };
|
||||
/// <summary>1-based line number in the file where this segment starts (the marker line for a conflict).</summary>
|
||||
public int StartLine { get; init; } = 1;
|
||||
|
||||
public static MergeSegment Conflict(string ours, string? @base, string theirs) =>
|
||||
new() { IsConflict = true, Ours = ours, Base = @base, Theirs = theirs };
|
||||
public static MergeSegment Stable(string text, int startLine = 1) => new() { Text = text, StartLine = startLine };
|
||||
|
||||
public static MergeSegment Conflict(string ours, string? @base, string theirs, int startLine = 1) =>
|
||||
new() { IsConflict = true, Ours = ours, Base = @base, Theirs = theirs, StartLine = startLine };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -49,22 +52,25 @@ public static class ConflictMarkerParser
|
||||
var segments = new List<MergeSegment>();
|
||||
var lines = SplitKeepLineEndings(fileText);
|
||||
var stable = new StringBuilder();
|
||||
var stableStartLine = 1;
|
||||
var i = 0;
|
||||
|
||||
while (i < lines.Count)
|
||||
{
|
||||
if (!IsMarker(lines[i], OursMarker))
|
||||
{
|
||||
if (stable.Length == 0) stableStartLine = i + 1;
|
||||
stable.Append(lines[i++]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (stable.Length > 0)
|
||||
{
|
||||
segments.Add(MergeSegment.Stable(stable.ToString()));
|
||||
segments.Add(MergeSegment.Stable(stable.ToString(), stableStartLine));
|
||||
stable.Clear();
|
||||
}
|
||||
|
||||
var conflictStartLine = i + 1;
|
||||
i++; // consume "<<<<<<<"
|
||||
var ours = new StringBuilder();
|
||||
while (i < lines.Count && !IsMarker(lines[i], BaseMarker) && !IsMarker(lines[i], SepMarker))
|
||||
@@ -88,11 +94,11 @@ public static class ConflictMarkerParser
|
||||
|
||||
if (i < lines.Count && IsMarker(lines[i], TheirsMarker)) i++; // consume ">>>>>>>"
|
||||
|
||||
segments.Add(MergeSegment.Conflict(ours.ToString(), @base, theirs.ToString()));
|
||||
segments.Add(MergeSegment.Conflict(ours.ToString(), @base, theirs.ToString(), conflictStartLine));
|
||||
}
|
||||
|
||||
if (stable.Length > 0)
|
||||
segments.Add(MergeSegment.Stable(stable.ToString()));
|
||||
segments.Add(MergeSegment.Stable(stable.ToString(), stableStartLine));
|
||||
|
||||
return segments;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user