@@ -8,13 +8,32 @@ enum LaunchAgentManager {
88
99 static func status( ) async -> Bool {
1010 guard FileManager ( ) . fileExists ( atPath: self . plistURL. path) else { return false }
11+ return await self . isLoaded ( )
12+ }
13+
14+ private static func isLoaded( ) async -> Bool {
1115 let result = await self . runLaunchctl ( [ " print " , " gui/ \( getuid ( ) ) / \( launchdLabel) " ] )
1216 return result == 0
1317 }
1418
15- static func set( enabled: Bool , bundlePath: String ) async {
19+ @discardableResult
20+ static func set(
21+ enabled: Bool ,
22+ bundlePath: String ,
23+ loaded: Bool ? = nil ,
24+ writePlist: ( ( String ) -> Void ) ? = nil ) async -> Bool
25+ {
1626 if enabled {
17- self . writePlist ( bundlePath: bundlePath)
27+ let persist = writePlist ?? { self . writePlist ( bundlePath: $0) }
28+ persist ( bundlePath)
29+ let alreadyLoaded = if let loaded {
30+ loaded
31+ } else {
32+ await self . isLoaded ( )
33+ }
34+ // Startup hydrates the toggle from launchd. Reinstalling the active job here
35+ // would boot out the app that is still responsible for bootstrapping it again.
36+ guard !alreadyLoaded else { return false }
1837 _ = await self . runLaunchctl ( [ " bootout " , " gui/ \( getuid ( ) ) / \( launchdLabel) " ] )
1938 _ = await self . runLaunchctl ( [ " bootstrap " , " gui/ \( getuid ( ) ) " , self . plistURL. path] )
2039 _ = await self . runLaunchctl ( [ " kickstart " , " -k " , " gui/ \( getuid ( ) ) / \( launchdLabel) " ] )
@@ -23,6 +42,7 @@ enum LaunchAgentManager {
2342 // bootout would terminate the launchd job immediately (and crash the app if launched via agent).
2443 try ? FileManager ( ) . removeItem ( at: self . plistURL)
2544 }
45+ return true
2646 }
2747
2848 private static func writePlist( bundlePath: String ) {
0 commit comments