Skip to content

Commit ccd687c

Browse files
7418claude
andcommitted
fix: don't cache "not found" binary result, use ref lock for pagination
- platform.ts: only cache positive findClaudeBinary results so a fresh CLI install is detected immediately on next check - ChatView.tsx: use useRef as atomic lock to prevent double-fetch from rapid clicks on "Load earlier messages" Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 9b166be commit ccd687c

File tree

2 files changed

+17
-6
lines changed

2 files changed

+17
-6
lines changed

src/components/chat/ChatView.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export function ChatView({ sessionId, initialMessages = [], initialHasMore = fal
3131
const [messages, setMessages] = useState<Message[]>(initialMessages);
3232
const [hasMore, setHasMore] = useState(initialHasMore);
3333
const [loadingMore, setLoadingMore] = useState(false);
34+
const loadingMoreRef = useRef(false);
3435
const [streamingContent, setStreamingContent] = useState('');
3536
const [isStreaming, setIsStreaming] = useState(false);
3637
const [toolUses, setToolUses] = useState<ToolUseInfo[]>([]);
@@ -113,7 +114,9 @@ export function ChatView({ sessionId, initialMessages = [], initialHasMore = fal
113114
}, [initialHasMore]);
114115

115116
const loadEarlierMessages = useCallback(async () => {
116-
if (loadingMore || !hasMore || messages.length === 0) return;
117+
// Use ref as atomic lock to prevent double-fetch from rapid clicks
118+
if (loadingMoreRef.current || !hasMore || messages.length === 0) return;
119+
loadingMoreRef.current = true;
117120
setLoadingMore(true);
118121
try {
119122
// Use _rowid of the earliest message as cursor
@@ -128,9 +131,10 @@ export function ChatView({ sessionId, initialMessages = [], initialHasMore = fal
128131
setMessages(prev => [...data.messages, ...prev]);
129132
}
130133
} finally {
134+
loadingMoreRef.current = false;
131135
setLoadingMore(false);
132136
}
133-
}, [sessionId, messages, hasMore, loadingMore]);
137+
}, [sessionId, messages, hasMore]);
134138

135139
const stopStreaming = useCallback(() => {
136140
abortControllerRef.current?.abort();

src/lib/platform.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,16 @@ export function getExpandedPath(): string {
9595
return parts.join(path.delimiter);
9696
}
9797

98-
// TTL cache for findClaudeBinary to avoid repeated filesystem probes
98+
// TTL cache for findClaudeBinary to avoid repeated filesystem probes.
99+
// Only caches "found" results; "not found" is never cached so a fresh
100+
// install is detected immediately on the next check.
99101
let _cachedBinaryPath: string | undefined | null = null; // null = not cached
100102
let _cachedBinaryTimestamp = 0;
101103
const BINARY_CACHE_TTL = 60_000; // 60 seconds
102104

103105
/**
104106
* Find and validate the Claude CLI binary.
105-
* Results are cached for 60s to avoid redundant filesystem probes on every poll.
107+
* Positive results are cached for 60s; negative results are never cached.
106108
*/
107109
export function findClaudeBinary(): string | undefined {
108110
const now = Date.now();
@@ -111,8 +113,13 @@ export function findClaudeBinary(): string | undefined {
111113
}
112114

113115
const found = _findClaudeBinaryUncached();
114-
_cachedBinaryPath = found;
115-
_cachedBinaryTimestamp = now;
116+
if (found) {
117+
_cachedBinaryPath = found;
118+
_cachedBinaryTimestamp = now;
119+
} else {
120+
// Don't cache "not found" — user may install CLI any moment
121+
_cachedBinaryPath = null;
122+
}
116123
return found;
117124
}
118125

0 commit comments

Comments
 (0)