feat(ui): Review-Merge-Button — Claude nimmt Waiting-for-Review pro Liste ab

Neuer Button in der virtuellen Review-Liste: öffnet das Merge-Helper-Auswahlmodal
im Review-Modus (alle WaitingForReview-Tasks repo-verknüpfter Listen, gruppiert
unter Listen-Headern, alle vorgetickt) und startet pro gewählter Liste eine
ConPTY-Handler-Session direkt in der Merge-Phase — via bestehendem Handoff-Spec
(nextPhase "merge"), kein Triage/Wait davor. Handler-Host-Task wie beim vollen
"Let Claude handle it"-Lauf (HandlerBaseCommit, IsManual).
This commit is contained in:
mika kuns
2026-08-27 08:44:33 +02:00
parent d0c726baa0
commit 741c7ac58d
11 changed files with 293 additions and 8 deletions
@@ -628,6 +628,42 @@ public class MissionControlViewModelTests : IDisposable
Assert.NotNull(error);
}
private sealed class RecordingReviewMergeWorker : StubWorkerClient
{
public string TaskId { get; } = "review-handler-task";
public readonly TaskCompletionSource<(string TaskId, IReadOnlyList<string> Ids, string Phase)> HandoffCall = new();
public override Task<string> CreateMergeHelperTaskAsync(
IReadOnlyList<string> taskIds, string listId, string title, string descriptionHeader, CancellationToken ct = default)
=> Task.FromResult(TaskId);
public override Task<LaunchSpec> GetMergeHelperHandoffLaunchSpecAsync(
string taskId, IReadOnlyList<string> survivingTaskIds, string nextPhase, CancellationToken ct = default)
{
HandoffCall.TrySetResult((taskId, survivingTaskIds, nextPhase));
return base.GetMergeHelperHandoffLaunchSpecAsync(taskId, survivingTaskIds, nextPhase, ct);
}
}
// The review-list "merge the reviews" entry: same host-task shape as the full list handler,
// but the pane's launch spec must come from the handoff path with phase "merge" and the
// freshly created handler task id — no triage phase first.
[Fact]
public async Task OpenMergeReviewConPtySessionAsync_AddsPane_LaunchingMergePhaseForHandlerTask()
{
var worker = new RecordingReviewMergeWorker();
using var vm = BuildVm(worker);
await vm.OpenMergeReviewConPtySessionAsync("L1", new[] { "r1", "r2" });
var pane = Assert.Single(vm.ConPtySessions);
Assert.Equal(worker.TaskId, pane.TaskId);
Assert.True(pane.IsTaskBased);
var call = await worker.HandoffCall.Task.WaitAsync(TimeSpan.FromSeconds(5));
Assert.Equal(worker.TaskId, call.TaskId);
Assert.Equal(new[] { "r1", "r2" }, call.Ids);
Assert.Equal("merge", call.Phase);
}
[Fact]
public async Task OpenMergeHelperHandoffConPtySessionAsync_ExistingPaneForTaskId_ClosesOldPane_OpensNewFocusedPane()
{