A LocalSystem Windows service can't see the logged-in user's Claude CLI authentication, so the worker now runs as the current user via a hidden per-user logon Scheduled Task with restart-on-failure. - Worker is WinExe (no console window) with a Serilog rolling file sink and a single-instance mutex so the logon task, app ensure-running, and Restart button can't fight over the SignalR port. - Installer replaces the service steps (register/start/stop) with autostart task steps, migrates the legacy ClaudeDoWorker service away on update, and removes the task on uninstall. ServicePage drops the service-account UI. - UI gains a WorkerLocator; the app ensures the worker is running at startup and the Restart button kills+relaunches this install's worker process. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
53 lines
1.8 KiB
C#
53 lines
1.8 KiB
C#
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 $"""
|
|
<?xml version="1.0" encoding="UTF-16"?>
|
|
<Task version="1.4" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
|
|
<RegistrationInfo>
|
|
<Description>ClaudeDo background worker (per-user).</Description>
|
|
</RegistrationInfo>
|
|
<Triggers>
|
|
<LogonTrigger>
|
|
<Enabled>true</Enabled>
|
|
<UserId>{user}</UserId>
|
|
</LogonTrigger>
|
|
</Triggers>
|
|
<Principals>
|
|
<Principal id="Author">
|
|
<UserId>{user}</UserId>
|
|
<LogonType>InteractiveToken</LogonType>
|
|
<RunLevel>LeastPrivilege</RunLevel>
|
|
</Principal>
|
|
</Principals>
|
|
<Settings>
|
|
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
|
|
<DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
|
|
<StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
|
|
<AllowHardTerminate>true</AllowHardTerminate>
|
|
<StartWhenAvailable>true</StartWhenAvailable>
|
|
<Hidden>true</Hidden>
|
|
<ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
|
|
<RestartOnFailure>
|
|
<Interval>PT{minutes}M</Interval>
|
|
<Count>3</Count>
|
|
</RestartOnFailure>
|
|
</Settings>
|
|
<Actions Context="Author">
|
|
<Exec>
|
|
<Command>{cmd}</Command>
|
|
</Exec>
|
|
</Actions>
|
|
</Task>
|
|
""";
|
|
}
|
|
}
|