fix(ui): suppress auto-open conflict resolver during MCP-driven merges
review_task/continue_merge on a planning parent always leaves conflicts in the tree, and the UI auto-opened the resolver on every PlanningMergeConflict broadcast regardless of who started the merge -- so a running Claude session resolving a unit-merge conflict could race a human editing the same shared checkout in a resolver window neither of them asked for. PlanningMergeOrchestrator.StartAsync now takes an externallyDriven flag (set by ExternalMcpService's MCP-driven review_task path, left false for the UI's ApproveReview) that rides along on the PlanningMergeConflict broadcast. The UI only auto-opens the resolver when it's false; otherwise it shows a persistent banner with a manual "Open resolver" button, cleared on PlanningMergeAborted/PlanningCompleted. A new GetActiveExternalConflictsAsync query (checked against GitService.IsMidMergeAsync rather than the in-memory flag alone) lets the UI resync the banner on reconnect instead of trusting a one-shot broadcast that isn't replayed after a restart. The childless single-task conflict path was checked and needed no change -- it only broadcasts the generic TaskUpdated, never PlanningMergeConflict.
This commit is contained in:
@@ -33,7 +33,7 @@ public abstract class StubWorkerClient : IWorkerClient
|
||||
public event Action<string, bool, string?>? RefineFinishedEvent;
|
||||
public event Action<string, string>? PlanningMergeStartedEvent;
|
||||
public event Action<string, string>? PlanningSubtaskMergedEvent;
|
||||
public event Action<string, string, IReadOnlyList<string>>? PlanningMergeConflictEvent;
|
||||
public event Action<string, string, IReadOnlyList<string>, bool>? PlanningMergeConflictEvent;
|
||||
public event Action<string>? PlanningMergeAbortedEvent;
|
||||
public event Action<string>? PlanningCompletedEvent;
|
||||
public event Action<PrimeFiredEvent>? PrimeFired;
|
||||
@@ -53,6 +53,10 @@ public abstract class StubWorkerClient : IWorkerClient
|
||||
public void RaiseTaskQuestionAsked(string taskId, string questionId, string question) => TaskQuestionAskedEvent?.Invoke(taskId, questionId, question);
|
||||
public void RaiseTaskQuestionResolved(string taskId, string questionId) => TaskQuestionResolvedEvent?.Invoke(taskId, questionId);
|
||||
public void RaiseHandoffRequested(string taskId, IReadOnlyList<string> survivingTaskIds) => HandoffRequestedEvent?.Invoke(taskId, survivingTaskIds);
|
||||
public void RaisePlanningMergeConflict(string planningTaskId, string subtaskId, IReadOnlyList<string> files, bool externallyDriven)
|
||||
=> PlanningMergeConflictEvent?.Invoke(planningTaskId, subtaskId, files, externallyDriven);
|
||||
public void RaisePlanningMergeAborted(string planningTaskId) => PlanningMergeAbortedEvent?.Invoke(planningTaskId);
|
||||
public void RaisePlanningCompleted(string planningTaskId) => PlanningCompletedEvent?.Invoke(planningTaskId);
|
||||
|
||||
public void RaisePrepStarted() => PrepStartedEvent?.Invoke();
|
||||
public void RaisePrepLine(string line) => PrepLineEvent?.Invoke(line);
|
||||
@@ -129,6 +133,8 @@ public abstract class StubWorkerClient : IWorkerClient
|
||||
=> Task.FromResult<CombinedDiffResultDto?>(null);
|
||||
public virtual Task ContinuePlanningMergeAsync(string planningTaskId) => Task.CompletedTask;
|
||||
public virtual Task AbortPlanningMergeAsync(string planningTaskId) => Task.CompletedTask;
|
||||
public virtual Task<IReadOnlyList<PlanningMergeConflictStateDto>> GetActiveExternalPlanningMergeConflictsAsync()
|
||||
=> Task.FromResult<IReadOnlyList<PlanningMergeConflictStateDto>>(Array.Empty<PlanningMergeConflictStateDto>());
|
||||
public virtual Task QueuePlanningSubtasksAsync(string parentTaskId, CancellationToken ct = default) => Task.CompletedTask;
|
||||
public virtual Task<string?> GetWeekReportAsync(DateOnly start, DateOnly end) => Task.FromResult<string?>(null);
|
||||
public virtual Task<string> GenerateWeekReportAsync(DateOnly start, DateOnly end) => Task.FromResult("");
|
||||
|
||||
Reference in New Issue
Block a user