feat(worker): add generic OperationProgress channel, port MergeProgress onto it

Merge/verify phases now broadcast over a generic (opKey, phase, current,
total) Hub event instead of a merge-specific one, so future producers
(worktree cleanup, startup recovery, planning integration) can reuse it.
IWorkerClient.MergeProgressEvent stays as a thin forwarder for existing
consumers (elapsed seconds riding in the generic "current" slot).
This commit is contained in:
Mika Kuns
2026-08-13 08:31:23 +02:00
parent db32e5307f
commit b8caa27027
8 changed files with 39 additions and 17 deletions
@@ -34,9 +34,18 @@ public interface IWorkerClient : INotifyPropertyChanged
event Action<string>? PrepLineEvent;
event Action<bool>? PrepFinishedEvent;
/// <summary>(opKey, phase, current, total) — generic progress channel for long-running worker
/// operations (merge phases, worktree cleanup, startup recovery, planning integration, ...).
/// opKey is the TaskId for a task-bound operation, otherwise a stable string. current/total
/// is meant to be shown as text, never a progress bar — most operations have no meaningful
/// total.</summary>
event Action<string, string, int, int>? OperationProgressEvent;
/// <summary>(taskId, phase, elapsedSeconds) — phase of an in-flight single-task merge
/// ("merging" | "verifying"). Fires while the MergeTask call itself is still pending, so the
/// waiting UI can show what it's blocked on; the verify phase re-fires every 30 s.</summary>
/// waiting UI can show what it's blocked on; the verify phase re-fires every 30 s. A thin
/// forwarder over <see cref="OperationProgressEvent"/> kept for existing consumers (elapsed
/// seconds riding in the generic "current" slot).</summary>
event Action<string, string, int>? MergeProgressEvent;
event Action<string, string>? PlanningMergeStartedEvent;
+7 -2
View File
@@ -64,6 +64,7 @@ public partial class WorkerClient : ObservableObject, IAsyncDisposable, IWorkerC
public event Action<UsageSnapshotDto>? UsageUpdatedEvent;
public event Action<string, string, int, int>? OperationProgressEvent;
public event Action<string, string, int>? MergeProgressEvent;
public event Action<string, string>? PlanningMergeStartedEvent;
@@ -174,9 +175,13 @@ public partial class WorkerClient : ObservableObject, IAsyncDisposable, IWorkerC
WorkerLogReceivedEvent?.Invoke(new WorkerLogEntry(message, level, timestampUtc)));
});
_hub.On<string, string, int>("MergeProgress", (taskId, phase, elapsedSeconds) =>
_hub.On<string, string, int, int>("OperationProgress", (opKey, phase, current, total) =>
{
Dispatcher.UIThread.Post(() => MergeProgressEvent?.Invoke(taskId, phase, elapsedSeconds));
Dispatcher.UIThread.Post(() =>
{
OperationProgressEvent?.Invoke(opKey, phase, current, total);
MergeProgressEvent?.Invoke(opKey, phase, current);
});
});
_hub.On<string, string>("PlanningMergeStarted", (planningTaskId, targetBranch) =>