From 85322c59682b21164e36c293b388cc4e5bd0fe79 Mon Sep 17 00:00:00 2001 From: jms830 Date: Fri, 26 Jun 2026 09:11:05 -0400 Subject: [PATCH] fix(client): raise project-open & directory-suggestion timeouts for large repos (#1620) openProject 10s->60s and getDirectorySuggestions 10s->30s + debounce the project-picker query 250ms. On large local repos the daemon's path-resolve and home-tree scan take several seconds; firing per-keystroke against a 10s timeout raced the suggestion list to empty (e.g. ~/gi found a hit but ~/gith blanked) and surfaced a spurious 'Timeout waiting for message (10000ms)' on add. Co-authored-by: jms830 --- .../app/src/components/project-picker-modal.tsx | 13 +++++++++++-- packages/client/src/daemon-client.ts | 8 ++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/packages/app/src/components/project-picker-modal.tsx b/packages/app/src/components/project-picker-modal.tsx index b400d73da..367436200 100644 --- a/packages/app/src/components/project-picker-modal.tsx +++ b/packages/app/src/components/project-picker-modal.tsx @@ -82,17 +82,18 @@ export function ProjectPickerModal() { const inputRef = useRef(null); const [query, setQuery] = useState(""); + const [debouncedQuery, setDebouncedQuery] = useState(""); const [activeIndex, setActiveIndex] = useState(0); const [isSubmitting, setIsSubmitting] = useState(false); const [openErrorReason, setOpenErrorReason] = useState(null); const openProject = useOpenProject(serverId); const directorySuggestionsQuery = useQuery({ - queryKey: ["project-picker-directory-suggestions", serverId, query], + queryKey: ["project-picker-directory-suggestions", serverId, debouncedQuery], queryFn: async () => { if (!client) return []; const result = await client.getDirectorySuggestions({ - query, + query: debouncedQuery, includeDirectories: true, includeFiles: false, limit: 30, @@ -165,6 +166,7 @@ export function ProjectPickerModal() { useEffect(() => { if (open) { setQuery(""); + setDebouncedQuery(""); setActiveIndex(0); setOpenErrorReason(null); const id = setTimeout(() => inputRef.current?.focus(), 0); @@ -172,6 +174,13 @@ export function ProjectPickerModal() { } }, [open]); + // Debounce the query that drives the (potentially multi-second) directory + // suggestions RPC so fast typing doesn't fire a filesystem scan per keystroke. + useEffect(() => { + const id = setTimeout(() => setDebouncedQuery(query), 250); + return () => clearTimeout(id); + }, [query]); + useEffect(() => { if (!open) return; if (activeIndex >= options.length) { diff --git a/packages/client/src/daemon-client.ts b/packages/client/src/daemon-client.ts index 8857b0418..005cfd2e3 100644 --- a/packages/client/src/daemon-client.ts +++ b/packages/client/src/daemon-client.ts @@ -1886,7 +1886,9 @@ export class DaemonClient { cwd, }, responseType: "open_project_response", - timeout: 10000, + // Large local repos (e.g. a big monorepo/brain checkout) need >10s for the + // daemon to resolve the path, detect git, and materialize the workspace. + timeout: 60000, }); } @@ -3512,7 +3514,9 @@ export class DaemonClient { limit: options.limit, }, responseType: "directory_suggestions_response", - timeout: 10000, + // Home-tree scans on large home dirs can take several seconds; don't cut + // the suggestion request off early (it would surface as an empty list). + timeout: 30000, }); }