fix(worker-client): stop swallowing mutating hub call failures
TryInvokeAsync catches every exception and returns null, which is fine
for read-only calls but hid real HubException reasons behind a generic
"offline" message for the 7 mutating call sites (RestoreDefaultAgents,
UpsertPrimeSchedule, AddDailyNote, CleanupFinishedWorktrees,
ResetAllWorktrees, ForceRemoveWorktree, BuildPlanningIntegrationBranch)
— the same bug class fixed for ApproveReview in e1807fd. Each of the 22
TryInvokeAsync call sites was audited; the 15 read-only ones are left
unchanged (empty/offline is the right display). For the 7 switched to
a direct hub invoke, every caller was checked and, where it had no
catch, one was added so the exception surfaces (StatusMessage,
ShowErrorAsync/CombinedWarning) instead of crashing.
This commit is contained in:
@@ -197,6 +197,11 @@ public sealed partial class DiffViewerViewModel : ViewModelBase
|
||||
DisplayedDiff = "";
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DisplayedDiff = "";
|
||||
CombinedWarning = Loc.T("vm.planningDiff.buildFailed", ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsLoadingCombined = false;
|
||||
|
||||
@@ -46,6 +46,7 @@ public sealed partial class WorktreesSettingsTabViewModel : ViewModelBase
|
||||
var r = await _worker.CleanupFinishedWorktreesAsync();
|
||||
StatusMessage = r is null ? Loc.T("vm.worktreesTab.workerOffline") : Loc.T("vm.worktreesTab.removed", r.Removed);
|
||||
}
|
||||
catch (Exception ex) { StatusMessage = Loc.T("vm.worktreesTab.cleanupFailed", ex.Message); }
|
||||
finally { IsBusy = false; }
|
||||
}
|
||||
|
||||
@@ -63,6 +64,7 @@ public sealed partial class WorktreesSettingsTabViewModel : ViewModelBase
|
||||
else if (r.Blocked) StatusMessage = Loc.T("vm.worktreesTab.blocked", r.RunningTasks);
|
||||
else StatusMessage = Loc.T("vm.worktreesTab.removedFrom", r.Removed, r.TasksAffected);
|
||||
}
|
||||
catch (Exception ex) { StatusMessage = Loc.T("vm.worktreesTab.resetFailed", ex.Message); }
|
||||
finally { IsBusy = false; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,6 +174,7 @@ public sealed partial class WorktreesOverviewModalViewModel : ViewModelBase
|
||||
StatusMessage = result is null ? Loc.T("vm.worktreesOverview.cleanupFailed") : Loc.T("vm.worktreesOverview.removed", result.Removed);
|
||||
await LoadAsync();
|
||||
}
|
||||
catch (Exception ex) { StatusMessage = Loc.T("vm.worktreesOverview.cleanupFailedDetailed", ex.Message); }
|
||||
finally { IsBusy = false; }
|
||||
}
|
||||
|
||||
@@ -241,7 +242,16 @@ public sealed partial class WorktreesOverviewModalViewModel : ViewModelBase
|
||||
if (row.IsRunning) { StatusMessage = Loc.T("vm.worktreesOverview.cannotForceRunning"); return; }
|
||||
if (ConfirmAction is not null && !await ConfirmAction($"Force remove worktree for '{row.TaskTitle}'? This deletes the directory and branch.")) return;
|
||||
|
||||
var result = await _worker.ForceRemoveWorktreeAsync(row.TaskId);
|
||||
ForceRemoveResultDto? result;
|
||||
try
|
||||
{
|
||||
result = await _worker.ForceRemoveWorktreeAsync(row.TaskId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
StatusMessage = Loc.T("vm.worktreesOverview.forceRemoveFailedDetailed", ex.Message);
|
||||
return;
|
||||
}
|
||||
if (result is null || !result.Removed)
|
||||
{
|
||||
StatusMessage = result?.Reason ?? Loc.T("vm.worktreesOverview.forceRemoveFailed");
|
||||
|
||||
Reference in New Issue
Block a user