refactor(ui): remove the stale-worker banner
The banner compared the running worker's build SHA against the selected list's HEAD via a git ancestor check on every list switch and reconnect. It added a git-rev-parse MSBuild target, a hub call, and a poll loop for a corner case that hasn't come up in practice — not worth the moving parts.
This commit is contained in:
@@ -5,7 +5,6 @@ using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using ClaudeDo.Data;
|
||||
using ClaudeDo.Data.Git;
|
||||
using ClaudeDo.Data.Models;
|
||||
using ClaudeDo.Ui.Localization;
|
||||
using ClaudeDo.Ui.Services;
|
||||
@@ -52,7 +51,6 @@ public sealed partial class IslandsShellViewModel : ViewModelBase, IDisposable
|
||||
private readonly UpdateCheckService _updateCheck = null!;
|
||||
private readonly InstallerLocator _installerLocator = null!;
|
||||
private readonly WorkerLocator _workerLocator = null!;
|
||||
private readonly GitService? _git;
|
||||
private readonly IDbContextFactory<ClaudeDoDbContext>? _dbFactory;
|
||||
private readonly Func<WorktreesOverviewModalViewModel> _worktreesOverviewVmFactory = () => null!;
|
||||
private readonly Func<WeeklyReportModalViewModel> _weeklyReportVmFactory = () => null!;
|
||||
@@ -121,11 +119,6 @@ public sealed partial class IslandsShellViewModel : ViewModelBase, IDisposable
|
||||
[ObservableProperty] private string? _updateBannerLatestVersion;
|
||||
private bool _bannerDismissedThisSession;
|
||||
|
||||
// Persistent (not auto-clearing) banner: the running worker predates the selected list's
|
||||
// merged HEAD, so "verified" claims made against the current process are stale. ClaudeDo-repo
|
||||
// only — see RefreshStaleWorkerCheckAsync.
|
||||
[ObservableProperty] private bool _isStaleWorkerBannerVisible;
|
||||
|
||||
// planningTaskId -> subtaskId, for unit-merge conflicts an MCP session (not the UI) started.
|
||||
// Kept as a dictionary so a later conflict on the same planning task updates in place instead
|
||||
// of piling up duplicate entries.
|
||||
@@ -328,8 +321,7 @@ public sealed partial class IslandsShellViewModel : ViewModelBase, IDisposable
|
||||
Func<MergeModalViewModel> mergeVmFactory,
|
||||
Func<RepoImportModalViewModel> repoImportVmFactory,
|
||||
MissionControlViewModel missionControl,
|
||||
UsagePillViewModel usagePill,
|
||||
GitService? git = null)
|
||||
UsagePillViewModel usagePill)
|
||||
{
|
||||
Lists = lists; Tasks = tasks; Details = details; Worker = worker;
|
||||
MissionControl = missionControl;
|
||||
@@ -349,9 +341,7 @@ public sealed partial class IslandsShellViewModel : ViewModelBase, IDisposable
|
||||
_usageMonitorVmFactory = usageMonitorVmFactory;
|
||||
_mergeVmFactory = mergeVmFactory;
|
||||
_repoImportVmFactory = repoImportVmFactory;
|
||||
_git = git;
|
||||
Lists.SelectionChanged += (_, _) => Tasks.LoadForList(Lists.SelectedList);
|
||||
Lists.SelectionChanged += (_, _) => _ = RefreshStaleWorkerCheckAsync();
|
||||
Tasks.SelectionChanged += (_, _) => Details.Bind(Tasks.SelectedTask, Tasks.SelectionSource);
|
||||
Tasks.PrepRequested += () => Details.ShowPrep();
|
||||
Tasks.PropertyChanged += (_, e) =>
|
||||
@@ -418,7 +408,6 @@ public sealed partial class IslandsShellViewModel : ViewModelBase, IDisposable
|
||||
};
|
||||
Worker.OperationProgressEvent += OnOperationProgress;
|
||||
Worker.WorkerLogReceivedEvent += OnWorkerLogReceived;
|
||||
Worker.ConnectionRestoredEvent += () => _ = RefreshStaleWorkerCheckAsync();
|
||||
Worker.PlanningMergeConflictEvent += OnPlanningMergeConflict;
|
||||
Worker.PlanningMergeAbortedEvent += OnPlanningMergeAborted;
|
||||
Worker.PlanningCompletedEvent += OnPlanningMergeCompleted;
|
||||
@@ -471,8 +460,6 @@ public sealed partial class IslandsShellViewModel : ViewModelBase, IDisposable
|
||||
_connectTimer.Dispose();
|
||||
_primeStatusTimer.Stop();
|
||||
_primeStatusTimer.Dispose();
|
||||
_staleWorkerCts?.Cancel();
|
||||
_staleWorkerCts?.Dispose();
|
||||
}
|
||||
|
||||
private void RefreshBannerFromStatus()
|
||||
@@ -492,57 +479,6 @@ public sealed partial class IslandsShellViewModel : ViewModelBase, IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
private CancellationTokenSource? _staleWorkerCts;
|
||||
|
||||
// Re-evaluates the stale-worker banner for the currently selected list. Cheap (one hub call +
|
||||
// up to two git subprocesses) and only ever runs for a git-backed list, so it's fine to fire on
|
||||
// every selection change / reconnect rather than caching.
|
||||
private async Task RefreshStaleWorkerCheckAsync()
|
||||
{
|
||||
_staleWorkerCts?.Cancel();
|
||||
var cts = new CancellationTokenSource();
|
||||
_staleWorkerCts = cts;
|
||||
|
||||
var stale = await ComputeIsStaleWorkerAsync(Lists?.SelectedList?.WorkingDir, cts.Token);
|
||||
if (cts.IsCancellationRequested) return;
|
||||
IsStaleWorkerBannerVisible = stale;
|
||||
}
|
||||
|
||||
private async Task<bool> ComputeIsStaleWorkerAsync(string? workingDir, CancellationToken ct)
|
||||
{
|
||||
if (_git is null || Worker is null || string.IsNullOrWhiteSpace(workingDir)) return false;
|
||||
|
||||
try
|
||||
{
|
||||
var buildInfo = await Worker.GetWorkerBuildInfoAsync();
|
||||
var buildSha = buildInfo?.BuildSha;
|
||||
if (string.IsNullOrWhiteSpace(buildSha)) return false;
|
||||
if (!await _git.IsGitRepoAsync(workingDir, ct)) return false;
|
||||
|
||||
var head = await _git.RevParseHeadAsync(workingDir, ct);
|
||||
var isAncestor = string.Equals(buildSha, head, StringComparison.OrdinalIgnoreCase)
|
||||
? (bool?)false // equal — never "stale" on a match, and no need to ask git
|
||||
: await _git.IsAncestorAsync(workingDir, buildSha, head, ct);
|
||||
return ShouldShowStaleWorkerBanner(buildSha, head, isAncestor);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Worker offline, dir no longer a repo, etc. — unknown, so stay quiet.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Pure decision extracted for testability. isAncestor is the tri-state result of
|
||||
// `git merge-base --is-ancestor buildSha head`: true = worker predates head (stale), false =
|
||||
// equal or diverged (never claim "stale" on a match or an unrelated history), null = unknown
|
||||
// (e.g. buildSha isn't a commit this repo knows about — never treat "unknown" as "stale").
|
||||
internal static bool ShouldShowStaleWorkerBanner(string? buildSha, string? headSha, bool? isAncestor)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(buildSha) || string.IsNullOrWhiteSpace(headSha)) return false;
|
||||
if (string.Equals(buildSha, headSha, StringComparison.OrdinalIgnoreCase)) return false;
|
||||
return isAncestor == true;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void OpenMissionControl()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user