1import Foundation2import ServiceManagement34@MainActor5protocol AutostartManaging: AnyObject {6 var isEnabled: Bool { get set }7 8 9 10 11 var lastError: String? { get }12}1314class AutostartManager: AutostartManaging {15 static let shared = AutostartManager()1617 private let launchAgentURL: URL18 private let bundleIdentifier = "com.june.Haven"19 private let executablePath: () -> String?20 private let writePlist: (Data, URL) throws -> Void21 private let removePlist: (URL) throws -> Void22 private let ensureLaunchAgentsDirectory: (URL) throws -> Void23 private let fileExists: (String) -> Bool2425 private(set) var lastError: String?2627 init(28 libraryDirectory: URL? = nil,29 executablePath: @escaping () -> String? = { Bundle.main.executablePath },30 writePlist: @escaping (Data, URL) throws -> Void = { data, url in try data.write(to: url) },31 removePlist: @escaping (URL) throws -> Void = { try FileManager.default.removeItem(at: $0) },32 ensureLaunchAgentsDirectory: @escaping (URL) throws -> Void = { url in33 try FileManager.default.createDirectory(at: url, withIntermediateDirectories: true)34 },35 fileExists: @escaping (String) -> Bool = { FileManager.default.fileExists(atPath: $0) }36 ) {37 let libraryDir =38 libraryDirectory39 ?? FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first!40 let launchAgentsDir = libraryDir.appendingPathComponent("LaunchAgents")4142 43 44 45 46 47 do {48 try ensureLaunchAgentsDirectory(launchAgentsDir)49 } catch {50 lastError = "Failed to prepare LaunchAgents directory: \(error.localizedDescription)"51 }5253 self.launchAgentURL = launchAgentsDir.appendingPathComponent("\(bundleIdentifier).plist")54 self.executablePath = executablePath55 self.writePlist = writePlist56 self.removePlist = removePlist57 self.ensureLaunchAgentsDirectory = ensureLaunchAgentsDirectory58 self.fileExists = fileExists59 }6061 var isEnabled: Bool {62 get {63 return fileExists(launchAgentURL.path)64 }65 set {66 if newValue {67 enable()68 } else {69 disable()70 }71 }72 }7374 private func enable() {75 guard !isEnabled else { return }7677 78 guard let appPath = executablePath() else { return }7980 let plistContent: [String: Any] = [81 "Label": bundleIdentifier,82 "ProgramArguments": [appPath],83 "RunAtLoad": true,84 "ProcessType": "Interactive",85 ]8687 do {88 let data = try PropertyListSerialization.data(89 fromPropertyList: plistContent, format: .xml, options: 0)90 try writePlist(data, launchAgentURL)91 lastError = nil92 } catch {93 lastError = "Failed to enable autostart: \(error.localizedDescription)"94 }95 }9697 private func disable() {98 guard isEnabled else { return }99100 do {101 try removePlist(launchAgentURL)102 lastError = nil103 } catch {104 lastError = "Failed to disable autostart: \(error.localizedDescription)"105 }106 }107}