feat(list-handler): hand off to a fresh session after Phase 2
The merge-helper ("Let Claude handle it") system prompt now calls a new
handoff_list_handler MCP tool once every surviving task is enhanced,
instead of continuing into Phases 3-5 in the same session -- avoiding
paying for Phases 0-2's dedupe/rewrite context on every polling round of
the run/review/merge phases.
The tool broadcasts HandoffRequested; Mission Control opens a second
ConPTY tile for the SAME handler task id (no new task, HandlerBaseCommit
untouched) running a fresh handoff brief that starts at Phase 3. The
original tile stays open. Adds PromptKind.MergeHelperHandoff,
InteractiveLaunchSpecService.BuildForMergeHelperHandoffAsync, and the
GetMergeHelperHandoffLaunchSpec hub method.
This commit is contained in:
@@ -20,6 +20,7 @@ public sealed partial class MissionControlViewModel : ViewModelBase, IDisposable
|
||||
private readonly Action<string, string, string, DateTime> _onTaskFinished;
|
||||
private readonly Action<string> _onTaskUpdated;
|
||||
private readonly Action _onConnectionRestored;
|
||||
private readonly Action<string, IReadOnlyList<string>> _onHandoffRequested;
|
||||
|
||||
// Embedded ConPTY sessions (task-based only) — a manual cockpit detached from the
|
||||
// review/merge/status machinery.
|
||||
@@ -77,6 +78,9 @@ public sealed partial class MissionControlViewModel : ViewModelBase, IDisposable
|
||||
_onConnectionRestored = () => { _ = RefreshQueueAsync(); };
|
||||
_worker.ConnectionRestoredEvent += _onConnectionRestored;
|
||||
|
||||
_onHandoffRequested = (taskId, survivingTaskIds) => { _ = OpenMergeHelperHandoffConPtySessionAsync(taskId, survivingTaskIds); };
|
||||
_worker.HandoffRequestedEvent += _onHandoffRequested;
|
||||
|
||||
_ = RefreshQueueAsync();
|
||||
}
|
||||
|
||||
@@ -243,6 +247,34 @@ public sealed partial class MissionControlViewModel : ViewModelBase, IDisposable
|
||||
() => DescribeAsync(() => _worker.GetMergeHelperLaunchSpecAsync(taskIds, listId))));
|
||||
}
|
||||
|
||||
// List-handler handoff: the running session called handoff_list_handler at the end of Phase 2.
|
||||
// Opens a SECOND ConPTY tile for the SAME handler task id to carry out Phases 3-5 — deliberately
|
||||
// NOT deduped by TaskId like OpenMergeHelperConPtySessionAsync above, since the original tile is
|
||||
// meant to stay open (Mika closes it by hand once he has seen its last message). No new task is
|
||||
// created here; see InteractiveLaunchSpecService.BuildForMergeHelperHandoffAsync.
|
||||
public async System.Threading.Tasks.Task OpenMergeHelperHandoffConPtySessionAsync(string taskId, IReadOnlyList<string> survivingTaskIds)
|
||||
{
|
||||
if (string.IsNullOrEmpty(taskId) || survivingTaskIds is not { Count: > 0 }) return;
|
||||
|
||||
var baseTitle = Loc.T("missionControl.mergeHelperTitle");
|
||||
var title = baseTitle + Loc.T("missionControl.mergeHelperHandoffTitleSuffix");
|
||||
try
|
||||
{
|
||||
await using var ctx = await _dbFactory.CreateDbContextAsync();
|
||||
var task = await ctx.Tasks.AsNoTracking().FirstOrDefaultAsync(t => t.Id == taskId);
|
||||
if (task is not null)
|
||||
{
|
||||
var list = await ctx.Lists.AsNoTracking().FirstOrDefaultAsync(l => l.Id == task.ListId);
|
||||
if (list?.Name is { Length: > 0 } name)
|
||||
title = $"{baseTitle} — {name}{Loc.T("missionControl.mergeHelperHandoffTitleSuffix")}";
|
||||
}
|
||||
}
|
||||
catch { /* best-effort title lookup */ }
|
||||
|
||||
AddConPtyPane(new ConPtyPaneViewModel(taskId, title,
|
||||
() => DescribeAsync(() => _worker.GetMergeHelperHandoffLaunchSpecAsync(taskId, survivingTaskIds))));
|
||||
}
|
||||
|
||||
// Wires a freshly built pane and shows it immediately — the pane resolves its own launch spec,
|
||||
// so the tile is on screen (spinner running) while the worker is still preparing the worktree.
|
||||
private void AddConPtyPane(ConPtyPaneViewModel pane)
|
||||
@@ -327,6 +359,7 @@ public sealed partial class MissionControlViewModel : ViewModelBase, IDisposable
|
||||
_worker.TaskFinishedEvent -= _onTaskFinished;
|
||||
_worker.TaskUpdatedEvent -= _onTaskUpdated;
|
||||
_worker.ConnectionRestoredEvent -= _onConnectionRestored;
|
||||
_worker.HandoffRequestedEvent -= _onHandoffRequested;
|
||||
ConPtySessions.CollectionChanged -= OnConPtySessionsChanged;
|
||||
Panes.CollectionChanged -= OnPanesChanged;
|
||||
foreach (var c in ConPtySessions.ToList())
|
||||
|
||||
Reference in New Issue
Block a user