/ utils / idleTimeout.ts
idleTimeout.ts
 1  import { logForDebugging } from './debug.js'
 2  import { gracefulShutdownSync } from './gracefulShutdown.js'
 3  
 4  /**
 5   * Creates an idle timeout manager for SDK mode.
 6   * Automatically exits the process after the specified idle duration.
 7   *
 8   * @param isIdle Function that returns true if the system is currently idle
 9   * @returns Object with start/stop methods to control the idle timer
10   */
11  export function createIdleTimeoutManager(isIdle: () => boolean): {
12    start: () => void
13    stop: () => void
14  } {
15    // Parse CLAUDE_CODE_EXIT_AFTER_STOP_DELAY environment variable
16    const exitAfterStopDelay = process.env.CLAUDE_CODE_EXIT_AFTER_STOP_DELAY
17    const delayMs = exitAfterStopDelay ? parseInt(exitAfterStopDelay, 10) : null
18    const isValidDelay = delayMs && !isNaN(delayMs) && delayMs > 0
19  
20    let timer: NodeJS.Timeout | null = null
21    let lastIdleTime = 0
22  
23    return {
24      start() {
25        // Clear any existing timer
26        if (timer) {
27          clearTimeout(timer)
28          timer = null
29        }
30  
31        // Only start timer if delay is configured and valid
32        if (isValidDelay) {
33          lastIdleTime = Date.now()
34  
35          timer = setTimeout(() => {
36            // Check if we've been continuously idle for the full duration
37            const idleDuration = Date.now() - lastIdleTime
38            if (isIdle() && idleDuration >= delayMs) {
39              logForDebugging(`Exiting after ${delayMs}ms of idle time`)
40              gracefulShutdownSync()
41            }
42          }, delayMs)
43        }
44      },
45  
46      stop() {
47        if (timer) {
48          clearTimeout(timer)
49          timer = null
50        }
51      },
52    }
53  }