feat(ui): add Restart worker menu entry under Help

Stops and starts the ClaudeDoWorker Windows service via
ServiceController. SignalR auto-reconnect plus the existing
ConnectionRestoredEvent handle the refresh, so the UI repopulates
counters and the active list once the worker is back up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
mika kuns
2026-05-18 16:39:40 +02:00
parent 0d55002e5e
commit 8d34db3f9b
3 changed files with 48 additions and 0 deletions

View File

@@ -11,6 +11,7 @@
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="8.0.11" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="System.ServiceProcess.ServiceController" Version="8.0.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -255,6 +255,51 @@ public sealed partial class IslandsShellViewModel : ViewModelBase
await _updateCheck.CheckNowAsync(CancellationToken.None);
}
[ObservableProperty] private string? _restartWorkerStatus;
[RelayCommand]
private async Task RestartWorkerAsync()
{
if (!OperatingSystem.IsWindows())
{
await FlashRestartStatusAsync("Service control is Windows-only.");
return;
}
RestartWorkerStatus = "Restarting worker…";
try
{
await Task.Run(() =>
{
using var sc = new System.ServiceProcess.ServiceController("ClaudeDoWorker");
if (sc.Status != System.ServiceProcess.ServiceControllerStatus.Stopped)
{
sc.Stop();
sc.WaitForStatus(System.ServiceProcess.ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(20));
}
sc.Start();
sc.WaitForStatus(System.ServiceProcess.ServiceControllerStatus.Running, TimeSpan.FromSeconds(20));
});
await FlashRestartStatusAsync("Worker restarted.");
}
catch (InvalidOperationException)
{
// ServiceController throws this when the service is not installed.
await FlashRestartStatusAsync("ClaudeDoWorker service is not installed.");
}
catch (Exception ex)
{
await FlashRestartStatusAsync($"Restart failed: {ex.Message}");
}
}
private async Task FlashRestartStatusAsync(string text)
{
RestartWorkerStatus = text;
await Task.Delay(3000);
if (RestartWorkerStatus == text) RestartWorkerStatus = null;
}
[RelayCommand]
private void DismissBanner()
{

View File

@@ -67,6 +67,8 @@
Foreground="{DynamicResource TextDimBrush}">
<MenuItem Header="Check for updates"
Command="{Binding CheckForUpdatesCommand}"/>
<MenuItem Header="Restart worker"
Command="{Binding RestartWorkerCommand}"/>
<MenuItem Header="About…" Command="{Binding OpenAboutCommand}"/>
</MenuItem>
</Menu>