import { useEffect, useRef, useState } from "react"; function fmt(ms: number): string { const total = Math.max(0, Math.floor(ms / 1000)); return `${Math.floor(total / 60)}m ${total % 60}s`; } /** * Processing-time indicator: accumulates ONLY the time the harness/model is * actively working (`running`), pausing while a gate waits on the reviewer and * freezing when the session ends. The parent keys this component on the session id, * so it remounts (and restarts at zero) per session. In-memory: a page reload * restarts the count. */ export function ElapsedTimer({ running }: { running: boolean }) { const [accumMs, setAccumMs] = useState(0); const runStartRef = useRef(null); const [, tick] = useState(0); useEffect(() => { if (!running) return; runStartRef.current = Date.now(); const t = setInterval(() => tick((n) => n + 1), 1000); return () => { // Fold the just-finished run into the accumulator (setState re-renders so the // frozen total shows), then stop ticking. if (runStartRef.current != null) { const started = runStartRef.current; runStartRef.current = null; setAccumMs((ms) => ms + (Date.now() - started)); } clearInterval(t); }; }, [running]); const live = running && runStartRef.current != null ? Date.now() - runStartRef.current : 0; return ( {fmt(accumMs + live)} ); }