diff --git a/packages/app/src/hooks/use-agent-autocomplete.ts b/packages/app/src/hooks/use-agent-autocomplete.ts index 4657f1ca0..5c27c966f 100644 --- a/packages/app/src/hooks/use-agent-autocomplete.ts +++ b/packages/app/src/hooks/use-agent-autocomplete.ts @@ -1,4 +1,4 @@ -import { useCallback, useMemo } from "react"; +import { useCallback, useEffect, useMemo, useState } from "react"; import { keepPreviousData, useQuery } from "@tanstack/react-query"; import type { AutocompleteOption } from "@/components/ui/autocomplete"; import { useAgentCommandsQuery, type DraftCommandConfig } from "./use-agent-commands-query"; @@ -185,6 +185,12 @@ export function useAgentAutocomplete(input: UseAgentAutocompleteInput): AgentAut ); const showFileAutocomplete = activeFileMention !== null; const fileFilterQuery = activeFileMention?.query ?? ""; + const [debouncedFileFilterQuery, setDebouncedFileFilterQuery] = useState(fileFilterQuery); + + useEffect(() => { + const timer = setTimeout(() => setDebouncedFileFilterQuery(fileFilterQuery), 180); + return () => clearTimeout(timer); + }, [fileFilterQuery]); const normalizedDraftConfig = useMemo( () => normalizeDraftCommandConfig(draftConfig), @@ -229,14 +235,21 @@ export function useAgentAutocomplete(input: UseAgentAutocompleteInput): AgentAut }); const fileSuggestionsQuery = useQuery({ - queryKey: ["directorySuggestions", serverId, autocompleteCwd, fileFilterQuery, true, true], + queryKey: [ + "directorySuggestions", + serverId, + autocompleteCwd, + debouncedFileFilterQuery, + true, + true, + ], queryFn: async (): Promise => { if (!client) { throw new Error("Daemon client unavailable"); } const response = await client.getDirectorySuggestions({ cwd: autocompleteCwd, - query: fileFilterQuery, + query: debouncedFileFilterQuery, limit: 50, includeFiles: true, includeDirectories: true, diff --git a/packages/server/src/utils/directory-suggestions.test.ts b/packages/server/src/utils/directory-suggestions.test.ts index 9eb01e864..88c05a388 100644 --- a/packages/server/src/utils/directory-suggestions.test.ts +++ b/packages/server/src/utils/directory-suggestions.test.ts @@ -265,4 +265,34 @@ describe("searchWorkspaceEntries", () => { }); expect(results.some((entry) => entry.path.startsWith("node_modules/"))).toBe(false); }); + + it("ignores common build/cache directories so large generated trees do not exhaust scan budget", async () => { + mkdirSync(path.join(workspaceDir, "packages", "app", "src"), { recursive: true }); + writeFileSync(path.join(workspaceDir, "packages", "app", "src", "needle.ts"), ""); + + const heavyDirs = ["dist", "build", "target", "out", "coverage", "vendor", "__pycache__"]; + for (const heavyDir of heavyDirs) { + for (let index = 0; index < 30; index += 1) { + mkdirSync(path.join(workspaceDir, heavyDir, `bundle-${index}`), { recursive: true }); + writeFileSync(path.join(workspaceDir, heavyDir, `bundle-${index}`, "needle.ts"), ""); + } + } + + const results = await searchWorkspaceEntries({ + cwd: workspaceDir, + query: "needle.ts", + limit: 20, + includeFiles: true, + includeDirectories: true, + maxEntriesScanned: 80, + }); + + expect(results).toContainEqual({ + path: "packages/app/src/needle.ts", + kind: "file", + }); + for (const heavyDir of heavyDirs) { + expect(results.some((entry) => entry.path.startsWith(`${heavyDir}/`))).toBe(false); + } + }); }); diff --git a/packages/server/src/utils/directory-suggestions.ts b/packages/server/src/utils/directory-suggestions.ts index 17c8d3aae..08b180fa3 100644 --- a/packages/server/src/utils/directory-suggestions.ts +++ b/packages/server/src/utils/directory-suggestions.ts @@ -73,7 +73,16 @@ const directoryListCache = new Map(); const workspaceEntryListCache = new Map(); const NO_SEGMENT_INDEX = Number.MAX_SAFE_INTEGER; const NO_MATCH_OFFSET = Number.MAX_SAFE_INTEGER; -const WORKSPACE_IGNORED_DIRECTORY_NAMES = new Set(["node_modules"]); +const WORKSPACE_IGNORED_DIRECTORY_NAMES = new Set([ + "node_modules", + "dist", + "build", + "target", + "out", + "coverage", + "vendor", + "__pycache__", +]); export async function searchHomeDirectories( options: SearchHomeDirectoriesOptions,