fix(installer): stop the running app before updating, not just the worker
All checks were successful
Release / release (push) Successful in 34s

A running ClaudeDo.App.exe locks the install\app directory, so the extract
step's Directory.Move failed with "Access to the path '...\app' is denied"
during an update. StopWorkerStep now also terminates app processes scoped to
the install dir (benefits uninstall too).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
mika kuns
2026-06-01 13:26:47 +02:00
parent 5783790733
commit 4148dcdb18

View File

@@ -7,15 +7,21 @@ namespace ClaudeDo.Installer.Steps;
public sealed class StopWorkerStep : IInstallStep public sealed class StopWorkerStep : IInstallStep
{ {
public const string LegacyTaskName = "ClaudeDoWorker"; public const string LegacyTaskName = "ClaudeDoWorker";
public const string ProcessName = "ClaudeDo.Worker";
// Both must be stopped before the install dir is touched: a running app/worker
// exe locks its directory, so Directory.Move during extraction would otherwise
// fail with "Access to the path '...\app' is denied".
private static readonly string[] ProcessNames = { "ClaudeDo.Worker", "ClaudeDo.App" };
public string Name => "Stop Worker"; public string Name => "Stop Worker";
public async Task<StepResult> ExecuteAsync(InstallContext ctx, IProgress<string> progress, CancellationToken ct) public async Task<StepResult> ExecuteAsync(InstallContext ctx, IProgress<string> progress, CancellationToken ct)
{ {
progress.Report("Stopping worker process (if running)..."); progress.Report("Stopping ClaudeDo processes (if running)...");
var installDir = ctx.InstallDirectory; var installDir = ctx.InstallDirectory;
foreach (var p in Process.GetProcessesByName(ProcessName)) foreach (var name in ProcessNames)
{
foreach (var p in Process.GetProcessesByName(name))
{ {
try try
{ {
@@ -27,6 +33,7 @@ public sealed class StopWorkerStep : IInstallStep
catch { /* process may have exited or be inaccessible */ } catch { /* process may have exited or be inaccessible */ }
finally { p.Dispose(); } finally { p.Dispose(); }
} }
}
await Task.CompletedTask; await Task.CompletedTask;
return StepResult.Ok(); return StepResult.Ok();
} }