source dump of claude code
at main 65 lines 2.5 kB view raw
1import { useEffect } from 'react' 2import { 3 getLastInteractionTime, 4 updateLastInteractionTime, 5} from '../bootstrap/state.js' 6import { useTerminalNotification } from '../ink/useTerminalNotification.js' 7import { sendNotification } from '../services/notifier.js' 8// The time threshold in milliseconds for considering an interaction "recent" (6 seconds) 9export const DEFAULT_INTERACTION_THRESHOLD_MS = 6000 10 11function getTimeSinceLastInteraction(): number { 12 return Date.now() - getLastInteractionTime() 13} 14 15function hasRecentInteraction(threshold: number): boolean { 16 return getTimeSinceLastInteraction() < threshold 17} 18 19function shouldNotify(threshold: number): boolean { 20 return process.env.NODE_ENV !== 'test' && !hasRecentInteraction(threshold) 21} 22 23// NOTE: User interaction tracking is now done in App.tsx's processKeysInBatch 24// function, which calls updateLastInteractionTime() when any input is received. 25// This avoids having a separate stdin 'data' listener that would compete with 26// the main 'readable' listener and cause dropped input characters. 27 28/** 29 * Hook that manages desktop notifications after a timeout period. 30 * 31 * Shows a notification in two cases: 32 * 1. Immediately if the app has been idle for longer than the threshold 33 * 2. After the specified timeout if the user doesn't interact within that time 34 * 35 * @param message - The notification message to display 36 * @param timeout - The timeout in milliseconds (defaults to 6000ms) 37 */ 38export function useNotifyAfterTimeout( 39 message: string, 40 notificationType: string, 41): void { 42 const terminal = useTerminalNotification() 43 44 // Reset interaction time when hook is called to make sure that requests 45 // that took a long time to complete don't pop up a notification right away. 46 // Must be immediate because useEffect runs after Ink's render cycle has 47 // already flushed; without it the timestamp stays stale and a premature 48 // notification fires if the user is idle (no subsequent renders to flush). 49 useEffect(() => { 50 updateLastInteractionTime(true) 51 }, []) 52 53 useEffect(() => { 54 let hasNotified = false 55 const timer = setInterval(() => { 56 if (shouldNotify(DEFAULT_INTERACTION_THRESHOLD_MS) && !hasNotified) { 57 hasNotified = true 58 clearInterval(timer) 59 void sendNotification({ message, notificationType }, terminal) 60 } 61 }, DEFAULT_INTERACTION_THRESHOLD_MS) 62 63 return () => clearInterval(timer) 64 }, [message, notificationType, terminal]) 65}