Files
cline/proto
Mikołaj Kondratek 418a8a6325 perf(file-search): route @-mention picker through host index when available (#10592)
* perf(file-search): route @-mention picker through host index when available

Adds a new SearchWorkspaceItems RPC on WorkspaceService that lets
hosts serve the @-mention file search from their own native index
(JetBrains FilenameIndex, eventually anything similar). When the
host returns results, core skips ripgrep entirely; when the host
throws, core falls back to ripgrep as today.

Why: on slow filesystems (the CLINE-2092 reporter is on a
2000-mile SSHFS mount) ripgrep's stat fan-out blows up to 15s+
per keystroke as it walks the workspace. JetBrains already has
the answer in memory.

Contract:
- searchWorkspaceItems thrown error  -> host can't answer, use ripgrep.
- searchWorkspaceItems returns items -> authoritative, including [].
This split lets a host that says "zero matches" short-circuit the
ripgrep fallback, which is the entire point of the change for slow
filesystems.

Implementation notes:
- VS Code / CLI / ACP host adapters throw "not implemented". Core
  swallows the throw silently in the @-mention path because on
  these hosts the throw is steady state, not an error worth
  logging on every keystroke.
- Telemetry: captureMentionSearchResults now records a search_source
  property (host_index | ripgrep) so we can see how often the host
  index actually picks up the load per fs_class.
- Multiroot aggregation reports source=host_index only when *every*
  contributing root used the host index; any root falling back to
  ripgrep marks the aggregate as ripgrep so the metric isn't misleading.
- Telemetry calls in searchFiles.ts are now fire-and-forget; the
  webview shouldn't block on a metrics flush.

CLINE-2092

* fix(file-search): scope host-index per workspace root in multiroot

In multi-root projects searchWorkspaceFilesMultiroot calls
searchWorkspaceFiles once per root. Each call hit the host index
without telling it which root, so a JetBrains host returned
project-wide results; the caller then path.join'd those against the
wrong base, lstat silently swallowed the ENOENT, and the user saw
fabricated paths.

Add an optional workspace_path field to SearchWorkspaceItemsRequest
and forward the workspacePath argument into executeHostIndexForFiles.
Hosts that can't honor the field ignore it; this preserves
project-wide behavior for older plugins paired with newer core.

Surfaced in code review on CLINE-2092.

* file-search: distinguish unimplemented host index from real failures

Previously the catch in executeHostIndexForFiles returned null on every
exception with no client-side trace. That's the right behavior on
VS Code/CLI/ACP where the RPC stub throws every keystroke, but it also
hides real degradation on JetBrains (UNAVAILABLE during indexing,
INTERNAL, transport errors) — operators have no way to tell whether a
ripgrep fallback was expected or a slow-path regression.

Split: gRPC code 12 / messages matching /not implemented/i log at debug
(steady state, stays quiet); everything else logs at warn with the code
and message so degraded sessions are visible. Fallback policy unchanged
— still returns null and lets the caller use ripgrep — and core has no
useful action on the error type, so we don't propagate further.

Surfaced in code review on CLINE-2092.

* fix(file-search): dedup host folders against parent-walk inferred dirs

When the host index returns a folder explicitly (e.g. 'src') *and* a file
underneath it (e.g. 'src/main.ts') for the same query, the parent-walk that
seeds the inferred directory set was re-adding 'src' as an inferred parent,
producing two identical entries in the picker.

Pre-pass the host items to record which directory paths were returned as
explicit folders, then skip those during the parent-walk so we don't double
list them. Transitive ancestors above an explicit folder are still added
because the loop keeps walking up.

Adds a regression test that reproduces the duplicate and fails without the
fix.
2026-05-11 12:00:16 +02:00
..