fix(power): avoid redundant macOS display blocking

This commit is contained in:
Neil
2026-08-31 05:43:05 -07:00
parent 21981d0fdc
commit dcc8b5dabd
4 changed files with 53 additions and 12 deletions
@@ -49,13 +49,15 @@ function createPlatformAssertion() {
function createService(
blocker = createBlocker(),
macosAssertion = createPlatformAssertion(),
linuxAssertion = createPlatformAssertion()
linuxAssertion = createPlatformAssertion(),
platform: NodeJS.Platform = 'linux'
): AgentAwakeService {
return new AgentAwakeService({
blocker,
linuxAssertion,
macosAssertion,
now: () => 1_000,
platform,
powerMonitor: null,
logger: {
debug: vi.fn(),
@@ -65,6 +67,18 @@ function createService(
}
describe('AgentAwakeService platform assertions', () => {
it('uses caffeinate without Electron display blocking on macOS', () => {
const blocker = createBlocker()
const macosAssertion = createPlatformAssertion()
const service = createService(blocker, macosAssertion, createPlatformAssertion(), 'darwin')
service.setEnabled(true)
service.setStatuses([workingStatus()])
expect(macosAssertion.start).toHaveBeenCalledTimes(1)
expect(blocker.start).not.toHaveBeenCalled()
})
it('keeps Electron blocker active when macOS assertion start fails', () => {
const blocker = createBlocker()
const macosAssertion = createPlatformAssertion()
@@ -72,7 +86,7 @@ describe('AgentAwakeService platform assertions', () => {
macosAssertion.start.mockImplementation(() => {
throw new Error('caffeinate failed')
})
const service = createService(blocker, macosAssertion, linuxAssertion)
const service = createService(blocker, macosAssertion, linuxAssertion, 'darwin')
service.setEnabled(true)
service.setStatuses([workingStatus()])
@@ -85,6 +99,20 @@ describe('AgentAwakeService platform assertions', () => {
expect(linuxAssertion.stop).toHaveBeenCalled()
})
it('drops the display-blocking fallback after caffeinate recovers', () => {
const blocker = createBlocker()
const macosAssertion = createPlatformAssertion()
macosAssertion.start.mockImplementationOnce(() => false).mockImplementation(() => true)
const service = createService(blocker, macosAssertion, createPlatformAssertion(), 'darwin')
service.setEnabled(true)
service.setStatuses([workingStatus()])
expect(blocker.start).toHaveBeenCalledWith('prevent-display-sleep')
service.setStatuses([{ ...workingStatus(), receivedAt: 1_001 }])
expect(blocker.stop).toHaveBeenCalledWith(1)
})
it('keeps Electron blocker active when Linux assertion start fails', () => {
const blocker = createBlocker()
const macosAssertion = createPlatformAssertion()
+1
View File
@@ -85,6 +85,7 @@ function createService(
linuxAssertion,
macosAssertion,
now,
platform: 'linux',
powerMonitor,
logger: {
debug: vi.fn(),
+13 -5
View File
@@ -23,7 +23,7 @@ type PowerSaveBlocker = {
}
type PlatformAwakeAssertion = {
start: (reason: string) => void
start: (reason: string) => boolean | void
stop: (reason: string) => void
dispose: () => void
}
@@ -41,6 +41,7 @@ type AgentAwakeServiceOptions = {
logger?: Logger
macosAssertion?: PlatformAwakeAssertion
now?: () => number
platform?: NodeJS.Platform
powerMonitor?: PowerMonitorEventSource | null
}
@@ -55,6 +56,7 @@ export class AgentAwakeService {
private readonly linuxAssertion: PlatformAwakeAssertion
private readonly logger: Logger
private readonly macosAssertion: PlatformAwakeAssertion
private readonly platform: NodeJS.Platform
private readonly now: () => number
private readonly unsubscribeResume: (() => void) | null
@@ -78,6 +80,7 @@ export class AgentAwakeService {
now: this.now,
onUnexpectedFailure: (reason) => this.refresh(reason)
})
this.platform = options.platform ?? process.platform
const resumeSource = options.powerMonitor === undefined ? powerMonitor : options.powerMonitor
if (resumeSource) {
const onResume = () => this.refresh('power-resume')
@@ -132,8 +135,12 @@ export class AgentAwakeService {
const runningStatusCount = this.getEligibleRunningStatusCount()
const shouldBlock = this.mode === 'on' || (this.mode === 'auto' && runningStatusCount > 0)
if (shouldBlock) {
this.startBlocker(reason, runningStatusCount)
this.startMacosAssertion(reason)
const macosAssertionActive = this.startMacosAssertion(reason)
if (this.platform !== 'darwin' || !macosAssertionActive) {
this.startBlocker(reason, runningStatusCount)
} else {
this.stopBlocker('macos-assertion-active', runningStatusCount)
}
this.startLinuxAssertion(reason)
} else {
this.stopBlocker(reason, runningStatusCount)
@@ -229,15 +236,16 @@ export class AgentAwakeService {
}
}
private startMacosAssertion(reason: string): void {
private startMacosAssertion(reason: string): boolean {
try {
this.macosAssertion.start(reason)
return this.macosAssertion.start(reason) !== false
} catch (err) {
this.logger.warn('[agent-awake] failed to start macOS system sleep assertion', {
reason,
mode: this.mode,
error: err
})
return false
}
}
+9 -5
View File
@@ -53,13 +53,16 @@ export class MacosSystemSleepAssertion {
this.spawn = options.spawn ?? nodeSpawn
}
start(reason: string): void {
if (this.platform !== 'darwin' || this.child) {
return
start(reason: string): boolean {
if (this.platform !== 'darwin') {
return false
}
if (this.child) {
return true
}
if (this.retryNotBefore !== null && this.now() < this.retryNotBefore) {
this.scheduleRetry()
return
return false
}
let child: CaffeinateProcess
@@ -70,7 +73,7 @@ export class MacosSystemSleepAssertion {
})
} catch (error) {
this.handleFailure('spawn-error', reason, error)
return
return false
}
this.child = child
@@ -91,6 +94,7 @@ export class MacosSystemSleepAssertion {
child.on('exit', onExit)
this.resetRetrySuppression()
this.resetFailureStreak()
return true
}
stop(_reason: string): void {