From 5c6f4b8b6ebcc45bf16d59c7c672893927b5eba4 Mon Sep 17 00:00:00 2001 From: mika kuns Date: Fri, 24 Apr 2026 19:18:18 +0200 Subject: [PATCH] feat(service): add ServiceCommands skeleton with platform/admin gates --- src/ClaudeMailbox/Cli/ServiceCommands.cs | 99 ++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 src/ClaudeMailbox/Cli/ServiceCommands.cs diff --git a/src/ClaudeMailbox/Cli/ServiceCommands.cs b/src/ClaudeMailbox/Cli/ServiceCommands.cs new file mode 100644 index 0000000..16ca8dd --- /dev/null +++ b/src/ClaudeMailbox/Cli/ServiceCommands.cs @@ -0,0 +1,99 @@ +using System.Diagnostics; +using System.Runtime.Versioning; +using System.Security.Principal; + +namespace ClaudeMailbox.Cli; + +public static class ServiceCommands +{ + public const string ServiceName = "ClaudeMailbox"; + + public static Task RunAsync(string[] args) + { + if (!OperatingSystem.IsWindows()) + { + Console.Error.WriteLine("Service commands are Windows-only."); + return Task.FromResult(2); + } + + var verb = args[0]; + return verb switch + { + "install-service" => Task.FromResult(InstallService(args)), + "uninstall-service" => Task.FromResult(UninstallService(args)), + "start" => Task.FromResult(RunSc("start", ServiceName)), + "stop" => Task.FromResult(RunSc("stop", ServiceName)), + "status" => Task.FromResult(Status()), + _ => Task.FromResult(PrintError($"Unknown service command: {verb}")), + }; + } + + [SupportedOSPlatform("windows")] + private static bool IsAdministrator() + { + using var identity = WindowsIdentity.GetCurrent(); + return new WindowsPrincipal(identity).IsInRole(WindowsBuiltInRole.Administrator); + } + + [SupportedOSPlatform("windows")] + private static int RequireAdmin() + { + if (IsAdministrator()) return 0; + Console.Error.WriteLine("This command requires Administrator privileges."); + return 5; + } + + [SupportedOSPlatform("windows")] + private static int InstallService(string[] args) + { + var admin = RequireAdmin(); + if (admin != 0) return admin; + + Console.Error.WriteLine("install-service: not yet implemented."); + return 1; + } + + [SupportedOSPlatform("windows")] + private static int UninstallService(string[] args) + { + var admin = RequireAdmin(); + if (admin != 0) return admin; + + Console.Error.WriteLine("uninstall-service: not yet implemented."); + return 1; + } + + [SupportedOSPlatform("windows")] + private static int Status() + { + Console.Error.WriteLine("status: not yet implemented."); + return 1; + } + + [SupportedOSPlatform("windows")] + internal static int RunSc(params string[] scArgs) + { + var psi = new ProcessStartInfo("sc.exe") + { + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + }; + foreach (var a in scArgs) psi.ArgumentList.Add(a); + + using var proc = Process.Start(psi)!; + var stdout = proc.StandardOutput.ReadToEnd(); + var stderr = proc.StandardError.ReadToEnd(); + proc.WaitForExit(); + + if (!string.IsNullOrWhiteSpace(stdout)) Console.Write(stdout); + if (!string.IsNullOrWhiteSpace(stderr)) Console.Error.Write(stderr); + return proc.ExitCode; + } + + private static int PrintError(string msg) + { + Console.Error.WriteLine(msg); + return 1; + } +}