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( "Call at the end of Phase 2 of the list handler (\"Let Claude handle it\") to hand this run off " + "to a fresh ConPTY session that carries out Phases 3-5, without dragging along this session's " + "dedupe/rewrite context. Reuses the SAME handler task -- no new task is created, and " + "HandlerBaseCommit is untouched. The current tile stays open; you must end your own turn " + "immediately after calling this.")] public async Task HandoffListHandler( [Description("This session's own handler task id.")] string taskId, [Description("The tasks that made it past dedupe, in the order to run them.")] IReadOnlyList 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); } }