11import { useCallback , useEffect , useMemo , useRef , useState } from 'react'
2+ import { useTranslation } from '@app/renderer/i18n'
23import type { AgentStandbyNotification } from '../components/AppNotifications'
34import type { GitHubPullRequestSummary , GitWorktreeInfo } from '@shared/contracts/dto'
45import type { WorkspaceState } from '@contexts/workspace/presentation/renderer/types'
@@ -116,6 +117,31 @@ function updateNotification(
116117 return didChange ? next : previous
117118}
118119
120+ export function formatAgentStandbySystemNotification (
121+ notification : Pick <
122+ AgentStandbyNotification ,
123+ 'title' | 'workspaceName' | 'taskTitle' | 'spaceName'
124+ > ,
125+ labels : {
126+ standby : string
127+ task : string
128+ space : string
129+ } ,
130+ ) : { title : string ; body : string } {
131+ const summary = notification . workspaceName
132+ ? `${ labels . standby } · ${ notification . workspaceName } `
133+ : labels . standby
134+ const contextLines = [
135+ notification . taskTitle ? `${ labels . task } : ${ notification . taskTitle } ` : null ,
136+ notification . spaceName ? `${ labels . space } : ${ notification . spaceName } ` : null ,
137+ ] . filter ( ( line ) : line is string => ! ! line )
138+
139+ return {
140+ title : notification . title ,
141+ body : [ summary , ...contextLines ] . join ( '\n' ) ,
142+ }
143+ }
144+
119145export function useAgentStandbyNotifications ( {
120146 maxVisible = 5 ,
121147} : {
@@ -124,11 +150,15 @@ export function useAgentStandbyNotifications({
124150 notifications : AgentStandbyNotification [ ]
125151 dismiss : ( id : string ) => void
126152} {
153+ const { t } = useTranslation ( )
127154 const platform =
128155 typeof window !== 'undefined' && window . opencoveApi ?. meta ?. platform
129156 ? window . opencoveApi . meta . platform
130157 : undefined
131158 const workspaces = useAppStore ( state => state . workspaces )
159+ const areSystemNotificationsEnabled = useAppStore (
160+ state => state . agentSettings . systemNotificationsEnabled ,
161+ )
132162 const isStandbyBannerEnabled = useAppStore ( state => state . agentSettings . standbyBannerEnabled )
133163 const showBranch = useAppStore ( state => state . agentSettings . standbyBannerShowBranch )
134164 const showPullRequest = useAppStore ( state => state . agentSettings . standbyBannerShowPullRequest )
@@ -243,7 +273,7 @@ export function useAgentStandbyNotifications({
243273
244274 const handleAgentEnteredStandby = useCallback (
245275 ( payload : AgentStandbyNotificationPayload ) => {
246- if ( ! isStandbyBannerEnabled ) {
276+ if ( ! isStandbyBannerEnabled && ! areSystemNotificationsEnabled ) {
247277 return
248278 }
249279
@@ -276,6 +306,21 @@ export function useAgentStandbyNotifications({
276306 createdAt : Date . now ( ) ,
277307 }
278308
309+ if ( areSystemNotificationsEnabled && window . opencoveApi ?. meta ?. isTest !== true ) {
310+ const nativeNotification = formatAgentStandbySystemNotification ( next , {
311+ standby : t ( 'agentRuntime.standby' ) ,
312+ task : t ( 'settingsPanel.nav.tasks' ) ,
313+ space : t ( 'commandCenter.sections.spaces' ) ,
314+ } )
315+ void window . opencoveApi ?. system
316+ ?. showNotification ( nativeNotification )
317+ . catch ( ( ) => undefined )
318+ }
319+
320+ if ( ! isStandbyBannerEnabled ) {
321+ return previous
322+ }
323+
279324 if ( ! shouldResolveBranch && ! shouldResolvePullRequest ) {
280325 const updated = [ next , ...previous ]
281326 return updated . length > maxVisible ? updated . slice ( 0 , maxVisible ) : updated
@@ -286,10 +331,12 @@ export function useAgentStandbyNotifications({
286331 } )
287332 } ,
288333 [
334+ areSystemNotificationsEnabled ,
289335 isStandbyBannerEnabled ,
290336 maxVisible ,
291337 shouldResolveBranch ,
292338 shouldResolvePullRequest ,
339+ t ,
293340 workspacesById ,
294341 ] ,
295342 )
0 commit comments