@@ -4,7 +4,7 @@ import UserNotifications
44import MacsomniaCore
55
66final class AppDelegate : NSObject , NSApplicationDelegate , ObservableObject {
7- let power : PowerControlling = RealPowerController ( )
7+ let power : PowerControlling = XPCPowerController ( )
88 lazy var appState = AppState ( power: power)
99 private let overlay = RedStripOverlay ( )
1010 private var monitor : StateMonitor !
@@ -110,7 +110,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
110110 // MARK: - User actions (from the menu)
111111
112112 func enable( _ duration: MacsomniaDuration ) {
113- if !power . hasPasswordlessAccess ( ) , !ensurePrivilege ( ) { return }
113+ if !HelperManager . isEnabled , !ensureHelper ( ) { return }
114114 do {
115115 try appState. enable ( duration)
116116 tick = Date ( )
@@ -119,36 +119,47 @@ final class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
119119 }
120120 }
121121
122- /// First-run: ask permission, then install the sudoers rule via the native
123- /// admin dialog. Returns true only if password-free pmset now works.
124- private func ensurePrivilege( ) -> Bool {
122+ /// First-run: register the privileged helper daemon via SMAppService. macOS
123+ /// may require the user to approve Macsomnia's background item in System
124+ /// Settings → Login Items before it becomes active. Returns true only once
125+ /// the helper is enabled and ready to serve XPC requests.
126+ private func ensureHelper( ) -> Bool {
127+ switch HelperManager . status {
128+ case . enabled:
129+ return true
130+ case . requiresApproval:
131+ presentApprovalNeeded ( )
132+ return false
133+ default :
134+ do {
135+ try HelperManager . register ( )
136+ } catch {
137+ presentFailure ( error)
138+ return false
139+ }
140+ if HelperManager . isEnabled { return true }
141+ presentApprovalNeeded ( )
142+ return false
143+ }
144+ }
145+
146+ /// Directs the user to approve Macsomnia's background item so the helper can run.
147+ private func presentApprovalNeeded( ) {
125148 let alert = NSAlert ( )
126- alert. messageText = " Macsomnia needs permission to control sleep "
149+ alert. messageText = " Macsomnia needs you to allow its background item "
127150 alert. informativeText = """
128- To disable sleep, Macsomnia runs the system pmset tool, which requires \
129- administrator rights. macOS will ask you to authorize this once. It \
130- installs a rule allowing password-free pmset, which you can remove any \
131- time with: sudo rm /etc/sudoers.d/macsomnia
151+ To control sleep, Macsomnia installs a small privileged helper that runs \
152+ the system pmset tool. macOS requires you to approve it once.
153+
154+ Open System Settings → General → Login Items & Extensions, then enable \
155+ Macsomnia under " Allow in the Background " . Then try again.
132156 """
133- alert. addButton ( withTitle: " Grant Permission… " )
157+ alert. addButton ( withTitle: " Open Login Items Settings " )
134158 alert. addButton ( withTitle: " Cancel " )
135159 NSApp . activate ( ignoringOtherApps: true )
136- guard alert. runModal ( ) == . alertFirstButtonReturn else { return false }
137-
138- do {
139- try PrivilegeProvisioner . installSudoersRule ( )
140- } catch PrivilegeProvisioner . ProvisionError . cancelled {
141- return false
142- } catch {
143- presentFailure ( error)
144- return false
145- }
146-
147- guard power. hasPasswordlessAccess ( ) else {
148- presentFailure ( PrivilegeProvisioner . ProvisionError. failed ( " permission was not granted " ) )
149- return false
160+ if alert. runModal ( ) == . alertFirstButtonReturn {
161+ HelperManager . openLoginItemsSettings ( )
150162 }
151- return true
152163 }
153164
154165 func disable( ) {
@@ -209,9 +220,9 @@ final class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
209220 alert. informativeText = """
210221 \( error)
211222
212- Try enabling again and authorize the permission prompt. If it keeps \
213- failing, you can grant access manually by running install-sudoers.sh \
214- from the Macsomnia source .
223+ Try enabling again. If it keeps failing, make sure Macsomnia's background \
224+ item is allowed in System Settings → General → Login Items & Extensions \
225+ (under " Allow in the Background " ) .
215226 """
216227 alert. alertStyle = . warning
217228 alert. runModal ( )
0 commit comments