diff --git a/src/ClaudeDo.Installer/Core/ScheduledTaskXml.cs b/src/ClaudeDo.Installer/Core/ScheduledTaskXml.cs deleted file mode 100644 index 7d0cc80..0000000 --- a/src/ClaudeDo.Installer/Core/ScheduledTaskXml.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System.Security; - -namespace ClaudeDo.Installer.Core; - -public static class ScheduledTaskXml -{ - public static string Build(string userId, string workerExePath, int restartIntervalMinutes) - { - var minutes = restartIntervalMinutes < 1 ? 1 : restartIntervalMinutes; - var user = SecurityElement.Escape(userId); - var cmd = SecurityElement.Escape(workerExePath); - return $""" - - - - ClaudeDo background worker (per-user). - - - - true - {user} - - - - - {user} - InteractiveToken - LeastPrivilege - - - - IgnoreNew - false - false - true - true - true - PT0S - - PT{minutes}M - 3 - - - - - {cmd} - - - - """; - } -} diff --git a/src/ClaudeDo.Installer/Steps/RegisterAutostartStep.cs b/src/ClaudeDo.Installer/Steps/RegisterAutostartStep.cs index 0580c3a..359d941 100644 --- a/src/ClaudeDo.Installer/Steps/RegisterAutostartStep.cs +++ b/src/ClaudeDo.Installer/Steps/RegisterAutostartStep.cs @@ -1,12 +1,11 @@ using System.IO; -using System.Security.Principal; using ClaudeDo.Installer.Core; namespace ClaudeDo.Installer.Steps; public sealed class RegisterAutostartStep : IInstallStep { - public const string TaskName = "ClaudeDoWorker"; + public const string LegacyTaskName = "ClaudeDoWorker"; private const string LegacyServiceName = "ClaudeDoWorker"; public string Name => "Register Autostart"; @@ -34,24 +33,19 @@ public sealed class RegisterAutostartStep : IInstallStep } } - // 2) Register (or replace) the per-user logon task. - var userId = WindowsIdentity.GetCurrent().Name; - var minutes = Math.Max(1, ctx.RestartDelayMs / 60000); - var xml = ScheduledTaskXml.Build(userId, workerExe, minutes); + // 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); - var xmlPath = Path.Combine(Path.GetTempPath(), $"ClaudeDoWorker-{Guid.NewGuid():N}.xml"); - await File.WriteAllTextAsync(xmlPath, xml, new System.Text.UnicodeEncoding(false, true), ct); + // 3) Register per-user autostart via a Startup-folder shortcut. + progress.Report("Creating Startup shortcut..."); try { - progress.Report("Registering logon task..."); - var (exit, output) = await ProcessRunner.RunAsync( - "schtasks.exe", $"/Create /TN \"{TaskName}\" /XML \"{xmlPath}\" /F", null, progress, ct); - if (exit != 0) - return StepResult.Fail($"schtasks /Create failed (exit {exit}): {output}"); + AutostartShortcut.Install(AutostartShortcut.DefaultStartupDir, workerExe); } - finally + catch (Exception ex) { - try { File.Delete(xmlPath); } catch { /* best effort */ } + return StepResult.Fail($"Failed to create Startup shortcut: {ex.Message}"); } return StepResult.Ok(); diff --git a/tests/ClaudeDo.Installer.Tests/ScheduledTaskXmlTests.cs b/tests/ClaudeDo.Installer.Tests/ScheduledTaskXmlTests.cs deleted file mode 100644 index 7bfa994..0000000 --- a/tests/ClaudeDo.Installer.Tests/ScheduledTaskXmlTests.cs +++ /dev/null @@ -1,30 +0,0 @@ -using ClaudeDo.Installer.Core; - -namespace ClaudeDo.Installer.Tests; - -public class ScheduledTaskXmlTests -{ - [Fact] - public void Build_EmbedsUserExeAndLogonTrigger() - { - var xml = ScheduledTaskXml.Build( - userId: "MACHINE\\mika", - workerExePath: @"C:\Program Files\ClaudeDo\worker\ClaudeDo.Worker.exe", - restartIntervalMinutes: 1); - - Assert.Contains("", xml); - Assert.Contains("MACHINE\\mika", xml); - Assert.Contains("InteractiveToken", xml); - Assert.Contains("true", xml); - Assert.Contains("LeastPrivilege", xml); - Assert.Contains(@"C:\Program Files\ClaudeDo\worker\ClaudeDo.Worker.exe", xml); - Assert.Contains("PT1M", xml); - } - - [Fact] - public void Build_ClampsRestartIntervalToOneMinuteMinimum() - { - var xml = ScheduledTaskXml.Build("M\\u", @"C:\w.exe", restartIntervalMinutes: 0); - Assert.Contains("PT1M", xml); - } -}