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:
+44
@@ -0,0 +1,44 @@
|
||||
using System.ComponentModel;
|
||||
using ClaudeDo.Data.Repositories;
|
||||
using ClaudeDo.Worker.Hub;
|
||||
using ModelContextProtocol.Server;
|
||||
|
||||
namespace ClaudeDo.Worker.External;
|
||||
|
||||
public sealed record HandoffListHandlerResult(bool Requested, string TaskId, int SurvivingCount);
|
||||
|
||||
[McpServerToolType]
|
||||
public sealed class HandoffMcpTools
|
||||
{
|
||||
private readonly TaskRepository _tasks;
|
||||
private readonly HubBroadcaster _broadcaster;
|
||||
|
||||
public HandoffMcpTools(TaskRepository tasks, HubBroadcaster broadcaster)
|
||||
{
|
||||
_tasks = tasks;
|
||||
_broadcaster = broadcaster;
|
||||
}
|
||||
|
||||
[McpServerTool, Description(
|
||||
"End of Phase 2 for the list handler (\"Let Claude handle it\"): hand this run off to a fresh " +
|
||||
"ConPTY session that carries out Phases 3-5, without dragging along this session's dedupe/rewrite " +
|
||||
"context. taskId is this session's own handler task id; survivingTaskIds are the tasks that made " +
|
||||
"it past dedupe, in the order to run them. Reuses the SAME handler task -- no new task is created, " +
|
||||
"and HandlerBaseCommit is untouched. The current tile stays open; end your own turn after calling this.")]
|
||||
public async Task<HandoffListHandlerResult> HandoffListHandler(
|
||||
string taskId, IReadOnlyList<string> survivingTaskIds, CancellationToken cancellationToken)
|
||||
{
|
||||
if (survivingTaskIds.Count == 0)
|
||||
throw new InvalidOperationException("survivingTaskIds must contain at least one task id.");
|
||||
|
||||
_ = await _tasks.GetByIdAsync(taskId, cancellationToken)
|
||||
?? throw new InvalidOperationException($"Task {taskId} not found.");
|
||||
|
||||
foreach (var id in survivingTaskIds)
|
||||
_ = await _tasks.GetByIdAsync(id, cancellationToken)
|
||||
?? throw new InvalidOperationException($"Task {id} not found.");
|
||||
|
||||
await _broadcaster.HandoffRequested(taskId, survivingTaskIds);
|
||||
return new HandoffListHandlerResult(true, taskId, survivingTaskIds.Count);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user