diff --git a/src/ClaudeDo.Installer/Steps/RegisterServiceStep.cs b/src/ClaudeDo.Installer/Steps/RegisterServiceStep.cs index ef29c15..40364e8 100644 --- a/src/ClaudeDo.Installer/Steps/RegisterServiceStep.cs +++ b/src/ClaudeDo.Installer/Steps/RegisterServiceStep.cs @@ -23,6 +23,24 @@ public sealed class RegisterServiceStep : IInstallStep progress.Report("Removing existing service registration (if any)..."); await RunSc($"delete {ServiceName}", ctx, progress, ct, ignoreErrors: true); + // Wait for the service to actually disappear from SCM. `sc delete` returns + // immediately but the service stays "marked for deletion" until every open + // handle (services.msc, Task Manager, a prior sc query process) is closed. + // Poll up to 30s — then fail with actionable guidance if it's still there. + progress.Report("Waiting for prior service registration to clear..."); + for (var i = 0; i < 30; i++) + { + ct.ThrowIfCancellationRequested(); + var (queryExit, _) = await RunSc($"query {ServiceName}", ctx, progress, ct, ignoreErrors: true); + if (queryExit != 0) break; // service no longer registered — good + if (i == 29) + return StepResult.Fail( + $"Service '{ServiceName}' is marked for deletion but hasn't cleared after 30s. " + + "Close any open Services console (services.msc), Task Manager Services tab, or " + + "Event Viewer showing the service, then retry. A reboot will also clear it."); + await Task.Delay(1000, ct); + } + // Create service var startType = ctx.AutoStart ? "auto" : "demand"; var createArgs = $"create {ServiceName} binPath= \"{workerExe}\" start= {startType}"; @@ -35,6 +53,10 @@ public sealed class RegisterServiceStep : IInstallStep progress.Report("Creating service..."); var (exitCode, output) = await RunSc(createArgs, ctx, progress, ct); + if (exitCode == 1072) + return StepResult.Fail( + $"Service '{ServiceName}' is still marked for deletion. " + + "Close services.msc / Task Manager / Event Viewer and retry, or reboot."); if (exitCode != 0) return StepResult.Fail($"sc.exe create failed (exit {exitCode}): {output}");