Something went wrong. Try again.
source dump of claude code forked from oppi.li/claude-code
Something went wrong. Try again.
3.2 kB · 106 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107import { useEffect, useRef, useState } from 'react'import { getLastInteractionTime } from '../bootstrap/state.js'import { fetchPrStatus, type PrReviewState } from '../utils/ghPrStatus.js'
const POLL_INTERVAL_MS = 60_000const SLOW_GH_THRESHOLD_MS = 4_000const IDLE_STOP_MS = 60 * 60_000 // stop polling after 60 min idle
export type PrStatusState = { number: number | null url: string | null reviewState: PrReviewState | null lastUpdated: number}
const INITIAL_STATE: PrStatusState = { number: null, url: null, reviewState: null, lastUpdated: 0,}
/** * Polls PR review status every 60s while the session is active. * When no interaction is detected for 60 minutes, the loop stops — no * timers remain. React re-runs the effect when isLoading changes * (turn starts/ends), restarting the loop. Effect setup schedules * the next poll relative to the last fetch time so turn boundaries * don't spawn `gh` more than once per interval. Disables permanently * if a fetch exceeds 4s. * * Pass `enabled: false` to skip polling entirely (hook still must be * called unconditionally to satisfy the rules of hooks). */export function usePrStatus(isLoading: boolean, enabled = true): PrStatusState { const [prStatus, setPrStatus] = useState<PrStatusState>(INITIAL_STATE) const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null) const disabledRef = useRef(false) const lastFetchRef = useRef(0)
useEffect(() => { if (!enabled) return if (disabledRef.current) return
let cancelled = false let lastSeenInteractionTime = -1 let lastActivityTimestamp = Date.now()
async function poll() { if (cancelled) return
const currentInteractionTime = getLastInteractionTime() if (lastSeenInteractionTime !== currentInteractionTime) { lastSeenInteractionTime = currentInteractionTime lastActivityTimestamp = Date.now() } else if (Date.now() - lastActivityTimestamp >= IDLE_STOP_MS) { return }
const start = Date.now() const result = await fetchPrStatus() if (cancelled) return lastFetchRef.current = start
setPrStatus(prev => { const newNumber = result?.number ?? null const newReviewState = result?.reviewState ?? null if (prev.number === newNumber && prev.reviewState === newReviewState) { return prev } return { number: newNumber, url: result?.url ?? null, reviewState: newReviewState, lastUpdated: Date.now(), } })
if (Date.now() - start > SLOW_GH_THRESHOLD_MS) { disabledRef.current = true return }
if (!cancelled) { timeoutRef.current = setTimeout(poll, POLL_INTERVAL_MS) } }
const elapsed = Date.now() - lastFetchRef.current if (elapsed >= POLL_INTERVAL_MS) { void poll() } else { timeoutRef.current = setTimeout(poll, POLL_INTERVAL_MS - elapsed) }
return () => { cancelled = true if (timeoutRef.current) { clearTimeout(timeoutRef.current) timeoutRef.current = null } } }, [isLoading, enabled])
return prStatus}