1import Foundation2import ServiceManagement34@MainActor5protocol AutostartManaging: AnyObject {6 var isEnabled: Bool { get set }7}89class AutostartManager: AutostartManaging {10 static let shared = AutostartManager()1112 private let launchAgentURL: URL13 private let bundleIdentifier = "com.june.Haven"14 private let executablePath: () -> String?15 private let writePlist: (Data, URL) throws -> Void16 private let removePlist: (URL) throws -> Void1718 init(19 libraryDirectory: URL? = nil,20 executablePath: @escaping () -> String? = { Bundle.main.executablePath },21 writePlist: @escaping (Data, URL) throws -> Void = { data, url in try data.write(to: url) },22 removePlist: @escaping (URL) throws -> Void = { try FileManager.default.removeItem(at: $0) }23 ) {24 let libraryDir =25 libraryDirectory26 ?? FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first!27 let launchAgentsDir = libraryDir.appendingPathComponent("LaunchAgents")2829 30 try? FileManager.default.createDirectory(at: launchAgentsDir, withIntermediateDirectories: true)3132 self.launchAgentURL = launchAgentsDir.appendingPathComponent("\(bundleIdentifier).plist")33 self.executablePath = executablePath34 self.writePlist = writePlist35 self.removePlist = removePlist36 }3738 var isEnabled: Bool {39 get {40 return FileManager.default.fileExists(atPath: launchAgentURL.path)41 }42 set {43 if newValue {44 enable()45 } else {46 disable()47 }48 }49 }5051 private func enable() {52 guard !isEnabled else { return }5354 55 guard let appPath = executablePath() else { return }5657 let plistContent: [String: Any] = [58 "Label": bundleIdentifier,59 "ProgramArguments": [appPath],60 "RunAtLoad": true,61 "ProcessType": "Interactive",62 ]6364 do {65 let data = try PropertyListSerialization.data(66 fromPropertyList: plistContent, format: .xml, options: 0)67 try writePlist(data, launchAgentURL)68 } catch {69 print("Failed to enable autostart: \(error)")70 }71 }7273 private func disable() {74 guard isEnabled else { return }7576 do {77 try removePlist(launchAgentURL)78 } catch {79 print("Failed to disable autostart: \(error)")80 }81 }82}