Build App / compute-version (push) Successful in 7s
Secret Scan / scan (push) Successful in 8s
Build App / build-macos (push) Successful in 2m53s
Build App / build-linux (push) Successful in 5m12s
Build App / build-windows (push) Successful in 5m15s
Build App / create-tag (push) Successful in 3s
Build App / sync-to-github (push) Successful in 1m5s
Clicking a file path in Claude's terminal output now opens the file in its own window with a CodeMirror 6 editor. The editor highlights the target line, live-reloads while the file changes, and saves explicitly with hash-based conflict detection. The viewer commands are gated by window label. Every app command is now ACL-gated per window through a Tauri AppManifest. build.rs checks the handler list against the capability files and fails the build on any mismatch. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
34 lines
1.2 KiB
TypeScript
34 lines
1.2 KiB
TypeScript
import { useEffect, useRef } from "react";
|
|
|
|
/** A visibility-gated interval that never overlaps its own ticks (spec §5). */
|
|
export function useViewerPolling(intervalMs: number, tick: () => Promise<void>, enabled: boolean): void {
|
|
const tickRef = useRef(tick);
|
|
tickRef.current = tick;
|
|
|
|
useEffect(() => {
|
|
if (!enabled) return;
|
|
let disposed = false;
|
|
let inFlight = false;
|
|
let timer: ReturnType<typeof setInterval> | null = null;
|
|
|
|
const run = async () => {
|
|
if (disposed || inFlight || document.visibilityState !== "visible") return;
|
|
inFlight = true;
|
|
try { await tickRef.current(); } finally { inFlight = false; }
|
|
};
|
|
const start = () => { if (timer === null) timer = setInterval(run, intervalMs); };
|
|
const stop = () => { if (timer !== null) { clearInterval(timer); timer = null; } };
|
|
const onVisibility = () => {
|
|
if (document.visibilityState === "visible") { void run(); start(); } else { stop(); }
|
|
};
|
|
|
|
document.addEventListener("visibilitychange", onVisibility);
|
|
onVisibility();
|
|
return () => {
|
|
disposed = true;
|
|
stop();
|
|
document.removeEventListener("visibilitychange", onVisibility);
|
|
};
|
|
}, [intervalMs, enabled]);
|
|
}
|