refactor(worker): extract ProgressReporter from TaskMergeService
Pulls the MCP idle-timeout progress loop out of TaskMergeService into a standalone ProgressReporter (Lifecycle namespace) shared by the verify gate and preview-verify call sites, and adds a per-item i/n overload (ReportItem) for upcoming batch progress in D2/D3.
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
using ModelContextProtocol;
|
||||
|
||||
namespace ClaudeDo.Worker.Lifecycle;
|
||||
|
||||
/// <summary>
|
||||
/// Reports MCP/hub progress for a long-running operation so a waiting caller doesn't hit an
|
||||
/// idle-silence abort (Claude Code's MCP client aborts an MCP call after ~300s of silence).
|
||||
/// </summary>
|
||||
internal static class ProgressReporter
|
||||
{
|
||||
/// <summary>
|
||||
/// Awaits <paramref name="work"/> while reporting progress every <paramref name="interval"/>.
|
||||
/// <paramref name="onTick"/> rides the same cadence for non-MCP callers (e.g. the Hub, which
|
||||
/// turns it into an OperationProgress broadcast). No-op passthrough when both are null.
|
||||
/// </summary>
|
||||
public static async Task<T> RunAsync<T>(
|
||||
Task<T> work, TimeSpan interval, IProgress<ProgressNotificationValue>? progress, string message,
|
||||
Action<TimeSpan>? onTick = null)
|
||||
{
|
||||
if (progress is null && onTick is null) return await work;
|
||||
|
||||
var sw = System.Diagnostics.Stopwatch.StartNew();
|
||||
while (true)
|
||||
{
|
||||
var finished = await Task.WhenAny(work, Task.Delay(interval));
|
||||
if (finished == work) return await work;
|
||||
progress?.Report(new ProgressNotificationValue { Progress = 0, Message = $"{message} ({sw.Elapsed:mm\\:ss})" });
|
||||
onTick?.Invoke(sw.Elapsed);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reports progress for one processed item out of a known total, e.g. "cleaning worktrees
|
||||
/// (3/12)". For callers iterating a batch (cleanup_task_worktree, get_task_diff,
|
||||
/// preview_merge_set) instead of awaiting one long-running task.
|
||||
/// </summary>
|
||||
public static void ReportItem(
|
||||
IProgress<ProgressNotificationValue>? progress, string action, int current, int total)
|
||||
{
|
||||
progress?.Report(new ProgressNotificationValue
|
||||
{
|
||||
Progress = current,
|
||||
Total = total,
|
||||
Message = $"{action} ({current}/{total})",
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user