import Foundation import ServiceManagement import AppKit import OSLog import SecretKit struct AgentLaunchController { func install(uninstallFirst: Bool = true, completion: (() -> Void)? = nil) { Logger().debug("Installing agent") if uninstallFirst { _ = setEnabled(false) } // This is definitely a bit of a "seems to work better" thing but: // Seems to more reliably hit if these are on separate runloops, otherwise it seems like it sometimes doesn't kill old // and start new? DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { _ = setEnabled(true) DispatchQueue.main.asyncAfter(deadline: .now() + 1) { completion?() } } } func forceLaunch(completion: ((Bool) -> Void)?) { Logger().debug("Agent is still not running, attempting to force launch") let url = Bundle.main.bundleURL.appendingPathComponent("Contents/Library/LoginItems/SecretAgent.app") let config = NSWorkspace.OpenConfiguration() config.activates = false NSWorkspace.shared.openApplication(at: url, configuration: config) { app, error in DispatchQueue.main.async { completion?(error == nil) } if let error = error { Logger().error("Error force launching \(error.localizedDescription)") } else { Logger().debug("Agent force launched") } } } func killNonInstanceAgents(agents: [NSRunningApplication]) { for agent in agents { agent.terminate() } } private func setEnabled(_ enabled: Bool) -> Bool { SMLoginItemSetEnabled(Bundle.main.agentBundleID as CFString, enabled) } }