using System.IO; using ClaudeDo.Installer.Core; namespace ClaudeDo.Installer.Steps; public sealed class RegisterAutostartStep : IInstallStep { public const string LegacyTaskName = "ClaudeDoWorker"; private const string LegacyServiceName = "ClaudeDoWorker"; public string Name => "Register Autostart"; public async Task ExecuteAsync(InstallContext ctx, IProgress progress, CancellationToken ct) { var workerExe = Path.Combine(ctx.InstallDirectory, "worker", "ClaudeDo.Worker.exe"); if (!File.Exists(workerExe)) return StepResult.Fail($"Worker executable not found: {workerExe}"); // Legacy service/task cleanup below runs unconditionally on every install/update/repair, // even though it's a no-op once migrated. A cached "already migrated" flag could go stale // (e.g. a user re-adds the legacy service) and strand them with it still running; two // extra process starts per run is the price for that migration safety net. // 1) Migrate away the legacy Windows service if present. progress.Report("Checking for legacy worker service..."); var (queryExit, _) = await ProcessRunner.RunAsync("sc.exe", $"query {LegacyServiceName}", null, progress, ct); if (queryExit == 0) { progress.Report("Removing legacy worker service..."); await ProcessRunner.RunAsync("sc.exe", $"stop {LegacyServiceName}", null, progress, ct); await ProcessRunner.RunAsync("sc.exe", $"delete {LegacyServiceName}", null, progress, ct); for (var i = 0; i < 30; i++) { ct.ThrowIfCancellationRequested(); var (q, _) = await ProcessRunner.RunAsync("sc.exe", $"query {LegacyServiceName}", null, progress, ct); if (q != 0) break; await Task.Delay(1000, ct); } } // 2) Migrate away the legacy logon scheduled task if present (best-effort). progress.Report("Removing legacy logon task..."); await ProcessRunner.RunAsync("schtasks.exe", $"/Delete /TN \"{LegacyTaskName}\" /F", null, progress, ct); // 3) Register per-user autostart via a Startup-folder shortcut. progress.Report("Checking Startup shortcut..."); try { var created = AutostartShortcut.Install(AutostartShortcut.DefaultStartupDir, workerExe); progress.Report(created ? "Startup shortcut created." : "Startup shortcut already up to date."); } catch (Exception ex) { return StepResult.Fail($"Failed to create Startup shortcut: {ex.Message}"); } return StepResult.Ok(); } }