chore(claude-do): Mission Control: allgemeiner Session-Handoff an eine frische
## Ziel Jede Mission-Control-Session (Ad-hoc UND Task-Session) soll ihre Arbeit an eine frische Session uebergeben koennen: "gib das ab an eine neue Session". Die alte Kachel wird geschlossen, an derselben Position oeffnet eine frische Session im selben cwd, die mit einem Brief startet, den die abgebende Session selbst geschrieben hat. Motivation: eine lange Session mit vollem/verrottetem Kontex ClaudeDo-Task: 8b846deb-ad10-4243-9272-9aea2a01ec93
This commit is contained in:
@@ -490,7 +490,7 @@ public class MissionControlViewModelTests : IDisposable
|
||||
|
||||
private sealed class ThrowingAdHocLaunchSpecWorker : StubWorkerClient
|
||||
{
|
||||
public override Task<LaunchSpec> GetAdHocLaunchSpecAsync(string directory, CancellationToken ct = default)
|
||||
public override Task<LaunchSpec> GetAdHocLaunchSpecAsync(string directory, string paneId, CancellationToken ct = default)
|
||||
=> throw new InvalidOperationException("bad directory");
|
||||
}
|
||||
|
||||
@@ -771,6 +771,81 @@ public class MissionControlViewModelTests : IDisposable
|
||||
Assert.Equal(color, vm.ConPtySessions[1].IdentityColorKey);
|
||||
}
|
||||
|
||||
private sealed class RecordingSessionHandoffWorker : StubWorkerClient
|
||||
{
|
||||
public string? AdHocPaneId;
|
||||
public readonly TaskCompletionSource<(string PaneId, string Cwd, string BriefPath, string? TaskId)> HandoffCall = new();
|
||||
public override Task<LaunchSpec> GetAdHocLaunchSpecAsync(string directory, string paneId, CancellationToken ct = default)
|
||||
{
|
||||
AdHocPaneId ??= paneId;
|
||||
return base.GetAdHocLaunchSpecAsync(directory, paneId, ct);
|
||||
}
|
||||
public override Task<LaunchSpec> GetSessionHandoffLaunchSpecAsync(string paneId, string cwd, string briefPath, string? taskId, CancellationToken ct = default)
|
||||
{
|
||||
HandoffCall.TrySetResult((paneId, cwd, briefPath, taskId));
|
||||
return base.GetSessionHandoffLaunchSpecAsync(paneId, cwd, briefPath, taskId, ct);
|
||||
}
|
||||
}
|
||||
|
||||
// handoff_session replaces the tile in place: same slot, same identity colour, same cwd, and the
|
||||
// outgoing pane is really closed rather than left running beside the new one.
|
||||
[Fact]
|
||||
public async Task SessionHandoffRequested_ReplacesPaneInPlace_KeepingIdentityAndCwd()
|
||||
{
|
||||
var worker = new RecordingSessionHandoffWorker();
|
||||
using var vm = BuildVm(worker);
|
||||
var dir = Path.Combine("C:", "Some", "Path");
|
||||
await vm.OpenConPtySessionAsync("t1");
|
||||
await vm.OpenAdHocConPtySessionAsync(dir);
|
||||
await vm.OpenConPtySessionAsync("t2");
|
||||
var outgoing = vm.ConPtySessions[1];
|
||||
Assert.Equal(outgoing.IdentityKey, worker.AdHocPaneId);
|
||||
var color = outgoing.IdentityColorKey;
|
||||
var opened = 0;
|
||||
vm.OpenRequested += () => opened++;
|
||||
|
||||
worker.RaiseSessionHandoffRequested(outgoing.IdentityKey, "brief.md");
|
||||
|
||||
Assert.Equal(3, vm.ConPtySessions.Count);
|
||||
var incoming = vm.ConPtySessions[1];
|
||||
Assert.NotSame(outgoing, incoming);
|
||||
Assert.Null(incoming.TaskId);
|
||||
Assert.Equal(outgoing.IdentityKey, incoming.IdentityKey);
|
||||
Assert.Equal(color, incoming.IdentityColorKey);
|
||||
Assert.Same(incoming, vm.Panes[1]);
|
||||
Assert.Equal(1, opened);
|
||||
Assert.Equal(0, SubscriberCount(outgoing, "SubmitForReviewRequested"));
|
||||
|
||||
var call = await worker.HandoffCall.Task.WaitAsync(TimeSpan.FromSeconds(5));
|
||||
Assert.Equal((outgoing.IdentityKey, dir, "brief.md", (string?)null), call);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SessionHandoffRequested_TaskPane_KeepsTaskId()
|
||||
{
|
||||
var worker = new RecordingSessionHandoffWorker();
|
||||
using var vm = BuildVm(worker);
|
||||
await vm.OpenConPtySessionAsync("t1");
|
||||
|
||||
worker.RaiseSessionHandoffRequested("t1", "brief.md");
|
||||
|
||||
Assert.Equal("t1", Assert.Single(vm.ConPtySessions).TaskId);
|
||||
var call = await worker.HandoffCall.Task.WaitAsync(TimeSpan.FromSeconds(5));
|
||||
Assert.Equal("t1", call.TaskId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SessionHandoffRequested_UnknownPane_DoesNothing()
|
||||
{
|
||||
var worker = new RecordingSessionHandoffWorker();
|
||||
using var vm = BuildVm(worker);
|
||||
|
||||
worker.RaiseSessionHandoffRequested("nope", "brief.md");
|
||||
|
||||
Assert.Empty(vm.ConPtySessions);
|
||||
Assert.False(worker.HandoffCall.Task.IsCompleted);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OpenMergeHelperHandoffConPtySessionAsync_SubmitForReview_ResolvesToSurvivingPane()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user