Skip to content

Add composer path tagging with workspace entry search#62

Merged
juliusmarminge merged 14 commits intomainfrom
codething/58603bc6
Feb 18, 2026
Merged

Add composer path tagging with workspace entry search#62
juliusmarminge merged 14 commits intomainfrom
codething/58603bc6

Conversation

@juliusmarminge
Copy link
Copy Markdown
Member

@juliusmarminge juliusmarminge commented Feb 17, 2026

Summary

  • add projects.searchEntries contracts and WebSocket API plumbing so clients can query workspace files/directories by prefix text
  • implement server-side workspace indexing/search with ignored folders, ranking, result limits, and short-lived cache
  • add composer trigger logic for @path tags and /model command completion, including cursor-aware token replacement helpers
  • update ChatView to show command palette suggestions, select path/model items from keyboard/mouse, render removable path chips, and include tagged paths in sent prompts
  • keep user-visible messages readable by showing @path tags while sending structured "Referenced paths" context to the model

Testing

  • apps/server/src/workspaceEntries.test.ts: verifies workspace scan output, ignored directories, and query filtering/ranking behavior
  • apps/server/src/wsServer.test.ts: verifies WS_METHODS.projectsSearchEntries is handled and returns expected file/directory entries
  • apps/web/src/composer-logic.test.ts: verifies trigger detection (@, /model), text replacement, prompt input building, and visible tag formatting
  • packages/contracts/src/project.test.ts: verifies search input defaults/validation and search result schema parsing
  • Not run: full repo lint/test commands in this environment

Open with Devin

Note

Medium Risk
Touches filesystem scanning and git subprocess invocation with caching/concurrency controls, which can affect performance and correctness across diverse repos; UI changes are moderate but rely on new RPC behavior.

Overview
Adds a new projects.searchEntries RPC exposed over WebSocket and consumed by the web app to query workspace files/directories by text, returning ranked results with truncation.

Implements server-side workspace indexing (workspaceEntries.ts) with short-lived caching, git-aware discovery (git ls-files) plus .gitignore filtering (including chunked git check-ignore stdin), a filesystem-walk fallback with bounded readdir concurrency, and hard caps on indexed entries.

Updates the chat composer to show a command-palette-style menu for @ path tagging and /model completion (debounced queries, keyboard navigation, cursor-aware text replacement, VS Code-style icons), and refactors branch toolbar mutations to attach error handlers per mutate call. Adds comprehensive unit/integration tests for indexing behavior, git-ignore chunking, and the new websocket method.

Written by Cursor Bugbot for commit f0bf427. This will update automatically on new commits. Configure here.

Summary by CodeRabbit

  • New Features

    • Workspace file & directory search with caching, relevance ranking, truncation flag, and remote WebSocket access (new API)
    • Interactive chat composer command palette: path, slash-command, and model entries with keyboard navigation and prompt tag insertion
    • Improved file/folder icons via VS Code icon mappings and a sync script for icon manifests; added package script to run the sync
  • Tests

    • Added unit and integration tests for workspace search, composer logic, icon resolution, and WebSocket integration

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 17, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds workspace file/directory search with server-side indexing (git-aware + fs fallback), caching and search API; WebSocket method; contracts/schemas; frontend composer trigger logic, UI and client API; VSCode icon sync/resolution and related tests.

Changes

Cohort / File(s) Summary
Server: workspace index & search
apps/server/src/workspaceEntries.ts
New module: builds git-aware or BFS filesystem index, caches indices with TTL/eviction, exposes searchWorkspaceEntries with filtering, ranking, and truncated flag.
Server tests
apps/server/src/workspaceEntries.test.ts, apps/server/src/wsServer.test.ts
Unit and integration tests for indexing, hidden/gitignore behavior, filtering/ranking, tracked-vs-ignored rules, and WebSocket projects.searchEntries flow.
WebSocket routing
apps/server/src/wsServer.ts, packages/contracts/src/ws.ts
Adds projects.searchEntries WS method and routes requests to searchWorkspaceEntries.
Contracts / IPC
packages/contracts/src/project.ts, packages/contracts/src/project.test.ts, packages/contracts/src/ipc.ts
New schemas/types/constants: input/result schemas, ProjectEntry/ProjectEntryKind, max limit constant; tests and NativeApi.projects.searchEntries signature.
Frontend composer logic
apps/web/src/composer-logic.ts, apps/web/src/composer-logic.test.ts
New trigger detection (path @, slash-command, slash-model), text replace utility, prompt builders, types and tests.
Frontend UI integration
apps/web/src/components/ChatView.tsx
Integrates composer detection, debounced path queries, floating command palette UI, keyboard navigation, prompt replacement and model/command selection wiring.
Frontend client API
apps/web/src/wsNativeApi.ts
Adds projects.searchEntries client method forwarding over WebSocket.
VSCode icons sync & resolution
scripts/sync-vscode-icons.mjs, apps/web/src/vscode-icons-manifest.json, apps/web/src/vscode-icons-language-associations.json, apps/web/src/vscode-icons.ts, apps/web/src/vscode-icons.test.ts
New sync script to fetch vscode-icons manifest and languages, generated manifest & language-associations JSON, icon resolution module, and tests; adds package script to run sync.
Package
package.json
Adds sync:vscode-icons npm script.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant ChatView
    participant ComposerLogic
    participant WSClient
    participant Server

    User->>ChatView: Type in composer textarea
    ChatView->>ComposerLogic: detectComposerTrigger(text, cursor)
    ComposerLogic-->>ChatView: ComposerTrigger { kind, query, rangeStart, rangeEnd }

    alt Path trigger
        ChatView->>WSClient: projects.searchEntries({cwd, query, limit})
        WSClient->>Server: WS: projects.searchEntries
        Server->>Server: get/build index (git or fs crawl)
        Server->>Server: filter & rank entries
        Server-->>WSClient: ProjectSearchEntriesResult { entries, truncated }
        WSClient-->>ChatView: entries, truncated
        ChatView->>ChatView: render composer menu (entries)
    end

    User->>ChatView: Select item / press Enter
    ChatView->>ComposerLogic: replaceTextRange(text, rangeStart, rangeEnd, replacement)
    ComposerLogic-->>ChatView: { text: updatedText, cursor: newCursor }
    ChatView->>ChatView: applyPromptReplacement, reset composer state
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add composer path tagging with workspace entry search' accurately describes the main changes in the PR, which adds workspace entry search functionality and composer path tagging features across the codebase.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codething/58603bc6

Comment @coderabbitai help to get the list of available commands and usage tips.

@macroscopeapp
Copy link
Copy Markdown
Contributor

macroscopeapp bot commented Feb 17, 2026

Add composer path tagging and implement apps/server/src/workspaceEntries.ts searchWorkspaceEntries with Git-aware indexing, chunked git check-ignore stdin, ranking, and WebSocket WS_METHODS.projectsSearchEntries support

Introduce workspace entry search with Git-based or filesystem indexing, chunked ignore filtering, TTL-cached indexes, ranking and pagination, and expose it over WebSocket; integrate '@' path tagging in the composer with command menu and VSCode-themed icons.

📍Where to Start

Start with the searchWorkspaceEntries handler in workspaceEntries.ts, then review the WebSocket dispatch in wsServer.ts and the composer integration in ChatView.tsx.


Macroscope summarized f0bf427.

Comment thread apps/web/src/components/ChatView.tsx
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (4)
apps/web/src/components/ChatView.tsx (2)

116-120: Consider reusing basenameOf from workspaceEntries.ts or extracting to shared utility.

This function duplicates the logic in apps/server/src/workspaceEntries.ts:basenameOf. While the server function isn't directly importable in the web app, consider extracting path utilities to a shared package (e.g., @t3tools/contracts) to avoid drift.

For now, this is fine as an isolated helper.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/components/ChatView.tsx` around lines 116 - 120, This duplicates
path-basename logic in basenameOfPath; either import/reuse the existing
basenameOf from workspaceEntries.ts (by moving the shared logic into a common
package like `@t3tools/contracts`) or extract basenameOfPath into that shared
utility and switch both ChatView.tsx and server workspaceEntries.ts to use the
single shared function. Update references to the function name basenameOfPath
(or rename to basenameOf) in ChatView.tsx and ensure workspaceEntries.ts imports
the new shared util so the logic is centralized and not duplicated.

1351-1372: Cursor tracking on multiple events may cause redundant state updates.

The cursor is tracked on onChange, onKeyUp, onClick, and onSelect. While this ensures accurate cursor position, it may trigger multiple state updates for a single user action.

This is likely fine for UX responsiveness, but if performance issues arise, consider debouncing or consolidating these updates.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/components/ChatView.tsx` around lines 1351 - 1372, The cursor
position is being updated redundantly across multiple handlers (onChange calling
onPromptChange with selectionStart, plus setComposerCursor in onKeyUp, onClick,
and onSelect), causing duplicate state updates; update the component to
centralize cursor updates by removing selectionStart handling from onChange and
only calling setComposerCursor from onSelect and onKeyUp (or wrap
setComposerCursor with a lightweight debounce/requestAnimationFrame to coalesce
rapid updates), keeping onPromptChange focused solely on text updates—look for
the handlers onPromptChange and setComposerCursor in the diff to apply this
change.
apps/server/src/workspaceEntries.ts (2)

150-164: Concurrent requests for the same cwd may trigger redundant scans.

When multiple requests arrive simultaneously for an uncached cwd, each will call buildWorkspaceIndex before any result is cached. Under load this could cause redundant filesystem traversals.

Consider using a pending-promise pattern to coalesce concurrent requests:

♻️ Optional: Coalesce concurrent index builds
+const pendingIndexBuilds = new Map<string, Promise<WorkspaceIndex>>();
+
 async function getWorkspaceIndex(cwd: string): Promise<WorkspaceIndex> {
   const cached = workspaceIndexCache.get(cwd);
   if (cached && Date.now() - cached.scannedAt < WORKSPACE_CACHE_TTL_MS) {
     return cached;
   }
 
+  const pending = pendingIndexBuilds.get(cwd);
+  if (pending) {
+    return pending;
+  }
+
-  const next = await buildWorkspaceIndex(cwd);
+  const buildPromise = buildWorkspaceIndex(cwd);
+  pendingIndexBuilds.set(cwd, buildPromise);
+  let next: WorkspaceIndex;
+  try {
+    next = await buildPromise;
+  } finally {
+    pendingIndexBuilds.delete(cwd);
+  }
   workspaceIndexCache.set(cwd, next);
   // ... rest unchanged

Based on coding guidelines: "Maintain predictable behavior under load and during failures (session restarts, reconnects, partial streams)".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/server/src/workspaceEntries.ts` around lines 150 - 164, Concurrent calls
to getWorkspaceIndex for the same cwd can trigger duplicate buildWorkspaceIndex
runs; implement a pending-promise coalescing pattern: create a module-scoped map
(e.g., pendingIndexBuilds) keyed by cwd, have getWorkspaceIndex check
pendingIndexBuilds before calling buildWorkspaceIndex, store the Promise there
while the build is in-flight, await that single Promise for all callers, on
success insert the resolved WorkspaceIndex into workspaceIndexCache and delete
the pending entry, and on failure delete the pending entry and rethrow so
subsequent calls can retry; reference getWorkspaceIndex, workspaceIndexCache,
buildWorkspaceIndex, and ensure pending promises are cleaned up on both resolve
and reject.

73-148: Consider adding hidden file filtering.

The scan ignores specific directory names (.git, node_modules, etc.) but doesn't filter other hidden files/directories starting with . (e.g., .env, .vscode). Depending on the intended UX, you may want to either:

  • Exclude all dot-prefixed entries for a cleaner list.
  • Keep them visible (current behavior) if users need to reference config files.

Current behavior is reasonable if referencing dotfiles is a valid use case.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/server/src/workspaceEntries.ts` around lines 73 - 148, The scan
currently includes dot-prefixed files/dirs; update buildWorkspaceIndex to skip
hidden entries by adding a check in the dirents loop (inside function
buildWorkspaceIndex) to continue when dirent.name startsWith('.') (after the
existing "."/".." check) or implement a small whitelist for allowed dotfiles
(e.g., ALLOWED_DOTFILES) and only include dot entries if they are explicitly
allowed; update IGNORED_DIRECTORY_NAMES handling or add a new HIDE_DOTFILES
constant to control this behavior so the scanner excludes hidden entries unless
opted-in.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/server/src/workspaceEntries.ts`:
- Around line 150-164: Concurrent calls to getWorkspaceIndex for the same cwd
can trigger duplicate buildWorkspaceIndex runs; implement a pending-promise
coalescing pattern: create a module-scoped map (e.g., pendingIndexBuilds) keyed
by cwd, have getWorkspaceIndex check pendingIndexBuilds before calling
buildWorkspaceIndex, store the Promise there while the build is in-flight, await
that single Promise for all callers, on success insert the resolved
WorkspaceIndex into workspaceIndexCache and delete the pending entry, and on
failure delete the pending entry and rethrow so subsequent calls can retry;
reference getWorkspaceIndex, workspaceIndexCache, buildWorkspaceIndex, and
ensure pending promises are cleaned up on both resolve and reject.
- Around line 73-148: The scan currently includes dot-prefixed files/dirs;
update buildWorkspaceIndex to skip hidden entries by adding a check in the
dirents loop (inside function buildWorkspaceIndex) to continue when dirent.name
startsWith('.') (after the existing "."/".." check) or implement a small
whitelist for allowed dotfiles (e.g., ALLOWED_DOTFILES) and only include dot
entries if they are explicitly allowed; update IGNORED_DIRECTORY_NAMES handling
or add a new HIDE_DOTFILES constant to control this behavior so the scanner
excludes hidden entries unless opted-in.

In `@apps/web/src/components/ChatView.tsx`:
- Around line 116-120: This duplicates path-basename logic in basenameOfPath;
either import/reuse the existing basenameOf from workspaceEntries.ts (by moving
the shared logic into a common package like `@t3tools/contracts`) or extract
basenameOfPath into that shared utility and switch both ChatView.tsx and server
workspaceEntries.ts to use the single shared function. Update references to the
function name basenameOfPath (or rename to basenameOf) in ChatView.tsx and
ensure workspaceEntries.ts imports the new shared util so the logic is
centralized and not duplicated.
- Around line 1351-1372: The cursor position is being updated redundantly across
multiple handlers (onChange calling onPromptChange with selectionStart, plus
setComposerCursor in onKeyUp, onClick, and onSelect), causing duplicate state
updates; update the component to centralize cursor updates by removing
selectionStart handling from onChange and only calling setComposerCursor from
onSelect and onKeyUp (or wrap setComposerCursor with a lightweight
debounce/requestAnimationFrame to coalesce rapid updates), keeping
onPromptChange focused solely on text updates—look for the handlers
onPromptChange and setComposerCursor in the diff to apply this change.

@cursor

This comment has been minimized.

Comment thread apps/server/src/workspaceEntries.ts Outdated
@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Feb 17, 2026

Greptile Summary

Adds workspace file/directory search with @path tagging in the composer. Server-side implementation indexes workspace entries via git ls-files (with fallback to bounded-concurrency FS walking), filters .gitignore matches in chunks, caches results for 15s, and deduplicates concurrent builds. Client implements cursor-aware trigger detection for @path and /model commands, debounces queries (120ms), displays command palette with VSCode-style icons and keyboard navigation, and replaces tokens on selection.

Key changes:

  • workspaceEntries.ts: workspace indexing with git/fs strategies, chunked ignore filtering (256KB stdin limit), ranking by exact/prefix/contains matches, 25k entry limit, LRU cache (4 keys, 15s TTL), in-flight deduplication
  • ChatView.tsx: composer command palette UI, debounced workspace search query hook, keyboard navigation (ArrowUp/Down/Tab/Enter), path chip rendering
  • composer-logic.ts: trigger detection (detectComposerTrigger), text replacement (replaceTextRange), prompt formatting helpers (buildPromptInput, buildUserVisiblePrompt)
  • WebSocket plumbing: new WS_METHODS.projectsSearchEntries handler routes to searchWorkspaceEntries
  • VSCode icons: manifest sync script, extension/filename-to-icon mapping

Issues found:

  • Empty query debounce causes 120ms delay showing initial results (line apps/web/src/components/ChatView.tsx:449)
  • git check-ignore --no-index doesn't respect .gitignore as expected (line apps/server/src/workspaceEntries.ts:161)
  • Tagged @path tokens aren't extracted into structured context for the model (line apps/web/src/components/ChatView.tsx:1023)

Confidence Score: 3/5

  • Safe to merge with medium risk - functional feature with edge cases
  • Three logic issues found: empty query debounce delay, git check-ignore flag mismatch, and missing path context extraction. The deduplication and debouncing improvements from previous threads are well-implemented. Comprehensive test coverage exists but doesn't catch the semantic issues.
  • Pay attention to apps/web/src/components/ChatView.tsx for the path context extraction and debounce issues, and apps/server/src/workspaceEntries.ts for the git check-ignore flag

Important Files Changed

Filename Overview
apps/server/src/workspaceEntries.ts Adds workspace indexing with git and fs fallback; implements deduplication, caching (15s TTL), ignore filtering, ranking, and truncation at 25k entries
apps/web/src/composer-logic.ts New file with cursor-aware trigger detection for @path and /model commands, text replacement helpers, and prompt formatting utilities
apps/web/src/components/ChatView.tsx Adds command palette UI with debounced workspace search (120ms), keyboard navigation, and path tagging support; integrates with composer trigger logic
apps/server/src/wsServer.ts Adds single-line WebSocket handler for projectsSearchEntries that routes to searchWorkspaceEntries
packages/contracts/src/project.ts Adds Zod schemas for workspace search input (cwd, query, limit) and result (entries array, truncated flag)

Sequence Diagram

sequenceDiagram
    participant User
    participant ChatView
    participant ReactQuery
    participant WebSocket
    participant wsServer
    participant workspaceEntries

    User->>ChatView: types "@src/comp"
    ChatView->>ChatView: detectComposerTrigger(text, cursor)
    ChatView->>ChatView: debounce query (120ms)
    ChatView->>ReactQuery: projectSearchEntriesQuery
    ReactQuery->>WebSocket: WS_METHODS.projectsSearchEntries
    WebSocket->>wsServer: { cwd, query, limit }
    wsServer->>workspaceEntries: searchWorkspaceEntries(params)
    
    alt cache hit (< 15s old)
        workspaceEntries->>workspaceEntries: return cached index
    else cache miss or expired
        alt in-flight build exists
            workspaceEntries->>workspaceEntries: await pending promise
        else new build needed
            workspaceEntries->>workspaceEntries: buildWorkspaceIndex(cwd)
            Note over workspaceEntries: tries git ls-files,<br/>falls back to fs walk
            workspaceEntries->>workspaceEntries: filterGitIgnoredPaths (chunked)
            workspaceEntries->>workspaceEntries: cache result (15s TTL)
        end
    end
    
    workspaceEntries->>workspaceEntries: filter by query
    workspaceEntries->>workspaceEntries: rank by score
    workspaceEntries->>workspaceEntries: slice to limit
    workspaceEntries-->>wsServer: { entries, truncated }
    wsServer-->>WebSocket: response
    WebSocket-->>ReactQuery: data
    ReactQuery-->>ChatView: workspaceEntries
    ChatView->>ChatView: render ComposerCommandMenu
    User->>ChatView: press Tab/Enter
    ChatView->>ChatView: replaceTextRange("@src/components/Button.tsx ")
    ChatView->>ChatView: update prompt state
Loading

Last reviewed commit: 2136fee

Copy link
Copy Markdown

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

12 files reviewed, 4 comments

Edit Code Review Agent Settings | Greptile

Comment thread apps/server/src/workspaceEntries.ts
Comment thread apps/web/src/components/ChatView.tsx Outdated
Comment thread apps/server/src/workspaceEntries.ts Outdated
@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Feb 17, 2026

Additional Comments (1)

apps/web/src/components/ChatView.tsx
Enter with open menu and zero items sends the message

When the command palette is open but has no matching items (e.g., @nonexistent), the guard composerMenuOpen && composerMenuItems.length > 0 is false, so pressing Enter falls through to the send handler. This sends the raw @nonexistent text as the prompt, which is likely unintentional from the user's perspective — they may expect the palette to close or do nothing.

Consider handling Enter when the menu is open but empty to prevent accidental sends:

  const onKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {
    if (composerMenuOpen && composerMenuItems.length > 0) {
      if (e.key === "ArrowDown") {
        e.preventDefault();
        setComposerMenuIndex((existing) => Math.min(existing + 1, composerMenuItems.length - 1));
        return;
      }
      if (e.key === "ArrowUp") {
        e.preventDefault();
        setComposerMenuIndex((existing) => Math.max(existing - 1, 0));
        return;
      }
      if (e.key === "Tab" || e.key === "Enter") {
        const selectedItem = activeComposerMenuItem ?? composerMenuItems[0];
        if (selectedItem) {
          e.preventDefault();
          onSelectComposerItem(selectedItem);
          return;
        }
      }
    }
    if (composerMenuOpen && e.key === "Escape") {
      e.preventDefault();
      setPrompt((existing) => {
        if (!composerTrigger) return existing;
        return replaceTextRange(existing, composerTrigger.rangeStart, composerTrigger.rangeEnd, "").text;
      });
      return;
    }

    if (e.key === "Enter" && !e.shiftKey) {
      e.preventDefault();
      void onSend(e as unknown as FormEvent);
    }
  };

Comment thread apps/server/src/workspaceEntries.ts
Comment thread apps/server/src/workspaceEntries.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
apps/server/src/workspaceEntries.ts (1)

175-194: Consider limiting parallel readdir calls.
Promise.all over large directory batches can create hundreds/thousands of concurrent file handles in big workspaces. A small concurrency cap (e.g., p-limit) would make load more predictable.

As per coding guidelines "Maintain predictable behavior under load and during failures (session restarts, reconnects, partial streams)".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/server/src/workspaceEntries.ts` around lines 175 - 194, The current use
of Promise.all over currentDirectories in the scan loop (pendingDirectories →
currentDirectories → directoryEntries) can spawn unbounded concurrent fs.readdir
calls; limit concurrency by replacing Promise.all with a bounded task runner
(e.g., p-limit or a simple semaphore) that caps concurrent calls to fs.readdir
(use an adjustable constant like MAX_CONCURRENCY), and run the mapping through
that limiter so directoryEntries is built with controlled parallelism while
preserving the existing error handling and returned shape.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/server/src/workspaceEntries.ts`:
- Around line 250-264: The getWorkspaceIndex implementation currently triggers
duplicate scans when multiple callers race after cache expiry; change it to
memoize the in‑flight Promise per cwd so concurrent callers share one
buildWorkspaceIndex call: when cache miss, immediately place a placeholder
Promise for buildWorkspaceIndex(cwd) into workspaceIndexCache (instead of
waiting for await), have callers await that Promise, and when it resolves
replace the cached Promise with the resolved WorkspaceIndex (including
scannedAt); also ensure that if the Promise rejects you remove the cache entry
so future calls can retry. Update references around getWorkspaceIndex,
workspaceIndexCache, buildWorkspaceIndex, WORKSPACE_CACHE_TTL_MS and the
existing workspaceIndexCache.set/delete logic to implement this behavior.

In `@apps/web/src/components/ChatView.tsx`:
- Around line 1293-1299: The empty-state string for model selection is
incorrect: in the JSX that renders when composerMenuItems.length === 0 (using
workspaceEntriesQuery and composerTrigger), update the conditional that
currently returns "No matching command." when composerTrigger?.kind !== "path"
so it returns "No matching model." specifically when composerTrigger?.kind ===
"model" (keep existing "No matching command." for other non-path kinds),
ensuring the ternary/conditional in the ChatView component that checks
composerTrigger?.kind is adjusted accordingly.

---

Nitpick comments:
In `@apps/server/src/workspaceEntries.ts`:
- Around line 175-194: The current use of Promise.all over currentDirectories in
the scan loop (pendingDirectories → currentDirectories → directoryEntries) can
spawn unbounded concurrent fs.readdir calls; limit concurrency by replacing
Promise.all with a bounded task runner (e.g., p-limit or a simple semaphore)
that caps concurrent calls to fs.readdir (use an adjustable constant like
MAX_CONCURRENCY), and run the mapping through that limiter so directoryEntries
is built with controlled parallelism while preserving the existing error
handling and returned shape.

Comment thread apps/server/src/workspaceEntries.ts
Comment thread apps/web/src/components/ChatView.tsx Outdated
Comment thread apps/web/src/components/ChatView.tsx Outdated
Comment thread apps/web/src/composer-logic.ts Outdated
@cursor

This comment has been minimized.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
apps/web/src/vscode-icons.ts (1)

4-5: Version hardcoded in two places - potential drift risk.

VSCODE_ICONS_VERSION is v12.17.0 here, while the sync script defaults to 12.17.0. Consider importing the version from the generated JSON manifest metadata to ensure consistency.

♻️ Use version from manifest
 import vscodeIconsManifest from "./vscode-icons-manifest.json";
 import languageAssociationsData from "./vscode-icons-language-associations.json";

-const VSCODE_ICONS_VERSION = "v12.17.0";
+const VSCODE_ICONS_VERSION = `v${languageAssociationsData.version}`;
 const VSCODE_ICONS_BASE_URL = `https://cdn.jsdelivr.net/gh/vscode-icons/vscode-icons@${VSCODE_ICONS_VERSION}/icons`;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/vscode-icons.ts` around lines 4 - 5, VSCODE_ICONS_VERSION is
hardcoded separately from the sync script; change the code to read the version
from the generated manifest JSON instead of hardcoding it so they can't drift:
replace uses of VSCODE_ICONS_VERSION (and construction of VSCODE_ICONS_BASE_URL)
with a runtime import/read of the generated icons manifest (e.g., read
manifest.version or manifest.metadata.version) and derive the base URL from that
value; update any module-level constants VSCODE_ICONS_VERSION and
VSCODE_ICONS_BASE_URL to be computed from the manifest value (e.g.,
manifest.version) so the version is single-sourced.
apps/web/src/components/ChatView.tsx (1)

113-117: basenameOfPath is duplicated.

This helper function is identical to the one in apps/web/src/vscode-icons.ts. Consider extracting it to a shared utility module to avoid duplication.

♻️ Extract to shared utility

Create in apps/web/src/lib/path-utils.ts:

export function basenameOfPath(pathValue: string): string {
  const slashIndex = pathValue.lastIndexOf("/");
  if (slashIndex === -1) return pathValue;
  return pathValue.slice(slashIndex + 1);
}

Then import in both files.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/components/ChatView.tsx` around lines 113 - 117, The duplicate
helper basenameOfPath should be extracted into a single shared utility module:
create and export a basenameOfPath(pathValue: string): string function in a new
shared file and replace the local implementations in ChatView.tsx and the other
file by importing this exported function; ensure the function signature and
behavior match the existing implementation and update imports in the places that
used the duplicated code (e.g., references to basenameOfPath in ChatView and
vscode-icons) so both modules use the single shared export.
scripts/sync-vscode-icons.mjs (1)

49-59: The script assumes unzip is available on the system.

This script uses the unzip command-line tool which may not be available on all systems (e.g., Windows without WSL). Consider documenting this dependency or adding a check.

💡 Optional: Add availability check
+async function checkUnzipAvailable() {
+  try {
+    await execFileAsync("unzip", ["-v"]);
+  } catch {
+    throw new Error("'unzip' command not found. Please install it to run this script.");
+  }
+}
+
 async function extractManifestFromVsix(vsixPath) {

Then call await checkUnzipAvailable(); at the start of main().

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/sync-vscode-icons.mjs` around lines 49 - 59, The script assumes the
external "unzip" binary is present when extractManifestFromVsix calls
execFileAsync("unzip", ...); add a short availability check function (e.g.,
checkUnzipAvailable) that verifies "unzip" exists (using a lightweight
spawn/exec of "which unzip" or "unzip -v") and throws a clear error or logs
instructions if missing, then call await checkUnzipAvailable(); at the start of
main() before extractManifestFromVsix is used; alternatively add a comment near
extractManifestFromVsix and main() documenting "unzip" as a required dependency
for users on platforms like Windows.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@apps/server/src/workspaceEntries.ts`:
- Around line 312-326: getWorkspaceIndex currently allows multiple concurrent
cache misses to call buildWorkspaceIndex concurrently; create a per-cwd
in-flight Promise map (e.g., inFlightIndexPromises) and memoize the Promise for
a given cwd when starting buildWorkspaceIndex so concurrent callers await the
same Promise; on success set workspaceIndexCache with the returned
WorkspaceIndex and remove the entry from inFlightIndexPromises, and on failure
remove the in-flight entry and rethrow so callers see the error (do not populate
workspaceIndexCache on failure). Ensure you still check the existing
workspaceIndexCache TTL at the top of getWorkspaceIndex and reference
getWorkspaceIndex, buildWorkspaceIndex, workspaceIndexCache, and the new
inFlightIndexPromises map in your changes.

In `@apps/web/src/components/ChatView.tsx`:
- Around line 1344-1351: The empty-state text incorrectly shows "No matching
command." when composerTrigger?.kind is "slash-model"; update the conditional in
ChatView.tsx (the JSX rendering that checks composerMenuItems.length and
composerTrigger?.kind) to return "No matching model." when composerTrigger?.kind
=== "slash-model" (preserving existing cases for "path" and the default command
case) so the message accurately reflects model searches.

---

Nitpick comments:
In `@apps/web/src/components/ChatView.tsx`:
- Around line 113-117: The duplicate helper basenameOfPath should be extracted
into a single shared utility module: create and export a
basenameOfPath(pathValue: string): string function in a new shared file and
replace the local implementations in ChatView.tsx and the other file by
importing this exported function; ensure the function signature and behavior
match the existing implementation and update imports in the places that used the
duplicated code (e.g., references to basenameOfPath in ChatView and
vscode-icons) so both modules use the single shared export.

In `@apps/web/src/vscode-icons.ts`:
- Around line 4-5: VSCODE_ICONS_VERSION is hardcoded separately from the sync
script; change the code to read the version from the generated manifest JSON
instead of hardcoding it so they can't drift: replace uses of
VSCODE_ICONS_VERSION (and construction of VSCODE_ICONS_BASE_URL) with a runtime
import/read of the generated icons manifest (e.g., read manifest.version or
manifest.metadata.version) and derive the base URL from that value; update any
module-level constants VSCODE_ICONS_VERSION and VSCODE_ICONS_BASE_URL to be
computed from the manifest value (e.g., manifest.version) so the version is
single-sourced.

In `@scripts/sync-vscode-icons.mjs`:
- Around line 49-59: The script assumes the external "unzip" binary is present
when extractManifestFromVsix calls execFileAsync("unzip", ...); add a short
availability check function (e.g., checkUnzipAvailable) that verifies "unzip"
exists (using a lightweight spawn/exec of "which unzip" or "unzip -v") and
throws a clear error or logs instructions if missing, then call await
checkUnzipAvailable(); at the start of main() before extractManifestFromVsix is
used; alternatively add a comment near extractManifestFromVsix and main()
documenting "unzip" as a required dependency for users on platforms like
Windows.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
apps/web/src/components/ChatView.tsx (1)

1259-1274: Scheduling side effects inside setState callback is an anti-pattern.

The requestAnimationFrame call within the setPrompt updater function is problematic because React may invoke the updater multiple times (e.g., in StrictMode), leading to redundant RAF schedules. Although the duplicate focus/cursor operations are idempotent here, consider refactoring to schedule the RAF after the state update completes.

♻️ Suggested refactor
 const applyPromptReplacement = useCallback(
   (rangeStart: number, rangeEnd: number, replacement: string) => {
+    const next = replaceTextRange(prompt, rangeStart, rangeEnd, replacement);
+    setPrompt(next.text);
+    window.requestAnimationFrame(() => {
+      const textarea = textareaRef.current;
+      if (!textarea) return;
+      textarea.focus();
+      textarea.setSelectionRange(next.cursor, next.cursor);
+      setComposerCursor(next.cursor);
+    });
-    setPrompt((existing) => {
-      const next = replaceTextRange(existing, rangeStart, rangeEnd, replacement);
-      window.requestAnimationFrame(() => {
-        const textarea = textareaRef.current;
-        if (!textarea) return;
-        textarea.focus();
-        textarea.setSelectionRange(next.cursor, next.cursor);
-        setComposerCursor(next.cursor);
-      });
-      return next.text;
-    });
   },
-  [],
+  [prompt],
 );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/components/ChatView.tsx` around lines 1259 - 1274, The updater
in applyPromptReplacement schedules a requestAnimationFrame inside setPrompt's
functional updater; move the side-effect (focus + setSelectionRange +
setComposerCursor) out of the setPrompt callback: compute the replacement result
with replaceTextRange before/alongside calling setPrompt (use the current prompt
state or a promptRef to get the existing value), call setPrompt(next.text) (no
RAF or DOM ops inside), then call window.requestAnimationFrame(() => { const
textarea = textareaRef.current; if (!textarea) return; textarea.focus();
textarea.setSelectionRange(next.cursor, next.cursor);
setComposerCursor(next.cursor); }); This keeps applyPromptReplacement,
setPrompt, textareaRef, and setComposerCursor intact but ensures DOM
side-effects run after state is scheduled, avoiding RAF inside the updater.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@apps/web/src/components/ChatView.tsx`:
- Around line 306-313: The empty-state message uses props.triggerKind but
doesn't handle the "slash-model" case, causing a misleading "No matching
command." text; update the JSX in ChatView (where props.items, props.isLoading,
and props.triggerKind are used) to add a branch for props.triggerKind ===
"slash-model" (e.g., props.triggerKind === "path" ? "No matching files or
folders." : props.triggerKind === "slash-model" ? "No matching model." : "No
matching command.") so the message accurately reflects model selection triggers.

---

Nitpick comments:
In `@apps/web/src/components/ChatView.tsx`:
- Around line 1259-1274: The updater in applyPromptReplacement schedules a
requestAnimationFrame inside setPrompt's functional updater; move the
side-effect (focus + setSelectionRange + setComposerCursor) out of the setPrompt
callback: compute the replacement result with replaceTextRange before/alongside
calling setPrompt (use the current prompt state or a promptRef to get the
existing value), call setPrompt(next.text) (no RAF or DOM ops inside), then call
window.requestAnimationFrame(() => { const textarea = textareaRef.current; if
(!textarea) return; textarea.focus(); textarea.setSelectionRange(next.cursor,
next.cursor); setComposerCursor(next.cursor); }); This keeps
applyPromptReplacement, setPrompt, textareaRef, and setComposerCursor intact but
ensures DOM side-effects run after state is scheduled, avoiding RAF inside the
updater.

Comment thread apps/web/src/components/ChatView.tsx Outdated
@cursor

This comment has been minimized.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
apps/web/src/components/ChatView.tsx (1)

126-130: Consider extracting basenameOfPath to a shared utility.

This function is duplicated in vscode-icons.ts. For consistency and DRY, consider moving it to a shared utilities module.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/components/ChatView.tsx` around lines 126 - 130, The function
basenameOfPath is duplicated (here in ChatView.tsx and in vscode-icons.ts);
extract it into a shared utility module (e.g., utils/path.ts or similar) and
replace the local implementations by importing basenameOfPath from that module
in both ChatView.tsx and vscode-icons.ts; ensure the exported function signature
(basenameOfPath(pathValue: string): string) and behavior remain identical and
update imports where the local definitions were removed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@apps/web/src/components/ChatView.tsx`:
- Around line 307-314: The empty-state message in ChatView.tsx uses
props.triggerKind to decide text but wrongly shows "No matching command." for
model selection; update the conditional that renders the fallback string (within
the JSX that checks props.items.length === 0) so that when props.triggerKind ===
"model" it returns "No matching model." instead of "No matching command.",
preserving the existing branches for "path" and loading state.

---

Nitpick comments:
In `@apps/web/src/components/ChatView.tsx`:
- Around line 126-130: The function basenameOfPath is duplicated (here in
ChatView.tsx and in vscode-icons.ts); extract it into a shared utility module
(e.g., utils/path.ts or similar) and replace the local implementations by
importing basenameOfPath from that module in both ChatView.tsx and
vscode-icons.ts; ensure the exported function signature
(basenameOfPath(pathValue: string): string) and behavior remain identical and
update imports where the local definitions were removed.

Comment thread apps/server/src/workspaceEntries.ts
@cursor

This comment has been minimized.

Comment thread apps/web/src/components/ChatView.tsx Outdated
setPrompt("");
setComposerImages([]);
setComposerCursor(0);
setComposerMenuIndex(0);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Path tag helpers never wired into send flow

High Severity

buildPromptInput and buildUserVisiblePrompt are implemented, exported, and tested in composer-logic.ts, but never actually called in the onSend flow in ChatView.tsx. The raw trimmed prompt (containing literal @path tokens) is sent directly to both the message store and the model provider. This means the PR's stated goal of "sending structured 'Referenced paths' context to the model" while "showing @path tags" to the user doesn't actually happen — the model just receives raw @src/file.tsx text with no structured path context.

Additional Locations (1)

Fix in Cursor Fix in Web

@cursor

This comment has been minimized.

Comment thread apps/web/src/lib/projectReactQuery.ts Outdated
Comment thread apps/server/src/workspaceEntries.ts
- add `projects.searchEntries` API, contracts, and server-side indexed workspace search
- add composer trigger logic for `@` path suggestions and `/model` command completion
- include tagged paths in sent prompt/user-visible text and cover behavior with server/web tests
- Build workspace index from `git ls-files` when in a Git repo, excluding ignored paths
- Skip configured ignored top-level directories during filesystem fallback indexing
- Update chat composer to insert `@path` directly in prompt and remove separate tagged-path chips
- Keep command menu navigation visible by scrolling the active/next item into view
- render theme-aware VS Code icons for path suggestions in chat composer
- exclude `.convex` and gitignored paths more reliably in workspace indexing
- add tests plus a sync script and icon manifest/association data
- Extract composer menu into memoized components for cleaner ChatView rendering
- Debounce path trigger queries and keep previous results while fetching
- Precompute searchable model fields to reduce repeated lowercase work
- Replace slash-command menu glyph in ChatView with `BotIcon`
- Map `yml`/`yaml` to base YAML language id to avoid overly specific icons
- Add test coverage for GitHub workflow YAML icon selection
- add `@tanstack/react-pacer` and switch composer path debounce to `useDebouncedValue`
- extract reusable `projectSearchEntriesQueryOptions` for workspace entry lookup
- add `serverKeybindingsQueryOptions` and update consumers in chat/sidebar
- keep branch toolbar mutation error handling at call sites
- Reuse in-flight workspace index builds per cwd and cap `readdir` scan concurrency at 32
- Add server tests for build deduplication and directory read concurrency limits
- Track composer text in a ref so prompt replacements use current text after send/reset
- Introduce a new test file to validate chunking behavior of git check-ignore to prevent oversized input strings.
- Adjust workspaceEntries.ts to implement chunking logic for git check-ignore, improving performance with large ignored path lists.
- Set a maximum byte limit for stdin in git check-ignore to enhance stability and prevent errors during processing.
const source = rawSource
.replace(/^import[^;]+;\s*/gm, "")
.replace(/export const languages(?:\s*:\s*[^=]+)?\s*=/, "const languages =")
.replace(/\}\s*satisfies\s*Record<[^;]+>;/, "};");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Low

scripts/sync-vscode-icons.mjs:70 The regex doesn't strip as const assertions, which would cause a SyntaxError in vm.runInContext. Consider adding a replacement like .replace(/\}\s*as\s+const\s*;/, '};') alongside the satisfies handling.

Suggested change
.replace(/\}\s*satisfies\s*Record<[^;]+>;/, "};");
.replace(/\}\s*satisfies\s*Record<[^;]+;/, "};")
.replace(/\}\s*as\s+const\s*;/, "};");

🚀 Want me to fix this? Reply ex: "fix it for me".

🤖 Prompt for AI
In file scripts/sync-vscode-icons.mjs around line 70:

The regex doesn't strip `as const` assertions, which would cause a `SyntaxError` in `vm.runInContext`. Consider adding a replacement like `.replace(/\}\s*as\s+const\s*;/, '};')` alongside the `satisfies` handling.

Evidence trail:
Viewed `scripts/sync-vscode-icons.mjs` lines ~60–74 at commit `be9b9e3` showing the `.replace(...satisfies...)` cleanup and absence of any `as const` replacement.

Co-authored-by: codex <codex@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is ON. A Cloud Agent has been kicked off to fix the reported issue.

});
},
[],
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deferred cursor state causes stale trigger flash after selection

Medium Severity

setComposerCursor(next.cursor) is called inside requestAnimationFrame, but setPrompt(next.text) is called synchronously. This causes a render cycle where composerTrigger is computed with the new prompt text but the old stale cursor position. detectComposerTrigger will find an @-token in the middle of the replaced text, briefly reopening the command menu with incorrect results before the rAF fires and updates the cursor. Moving setComposerCursor outside the rAF (alongside setPrompt) would fix the stale intermediate state.

Fix in Cursor Fix in Web

@cursor
Copy link
Copy Markdown
Contributor

cursor bot commented Feb 18, 2026

Bugbot Autofix prepared fixes for 1 of the 1 bugs found in the latest run.

  • ✅ Fixed: Deferred cursor state causes stale trigger flash after selection
    • Moved setComposerCursor(next.cursor) out of the requestAnimationFrame callback to execute synchronously alongside setPrompt(next.text), ensuring both states update in the same render cycle and preventing stale composerTrigger computation.

Create PR

Or push these changes by commenting:

@cursor push 583765b883
Preview (583765b883)
diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx
--- a/apps/web/src/components/ChatView.tsx
+++ b/apps/web/src/components/ChatView.tsx
@@ -1246,12 +1246,12 @@
       const next = replaceTextRange(promptRef.current, rangeStart, rangeEnd, replacement);
       promptRef.current = next.text;
       setPrompt(next.text);
+      setComposerCursor(next.cursor);
       window.requestAnimationFrame(() => {
         const textarea = textareaRef.current;
         if (!textarea) return;
         textarea.focus();
         textarea.setSelectionRange(next.cursor, next.cursor);
-        setComposerCursor(next.cursor);
       });
     },
     [],

},
enabled: (input.enabled ?? true) && Boolean(input.api && input.cwd),
staleTime: input.staleTime ?? DEFAULT_SEARCH_ENTRIES_STALE_TIME,
placeholderData: (previous) => previous ?? EMPTY_SEARCH_ENTRIES_RESULT,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Low

lib/projectReactQuery.ts:40 placeholderData persists stale entries when cwd becomes null and the query is disabled. Consider returning undefined (or the empty result) when input.cwd is falsy to avoid showing files from a previous project.

Suggested change
placeholderData: (previous) => previous ?? EMPTY_SEARCH_ENTRIES_RESULT,
placeholderData: (previous) => (input.cwd ? previous : undefined) ?? EMPTY_SEARCH_ENTRIES_RESULT,

🚀 Want me to fix this? Reply ex: "fix it for me".

🤖 Prompt for AI
In file apps/web/src/lib/projectReactQuery.ts around line 40:

`placeholderData` persists stale entries when `cwd` becomes `null` and the query is disabled. Consider returning `undefined` (or the empty result) when `input.cwd` is falsy to avoid showing files from a previous project.

Evidence trail:
Viewed `apps/web/src/lib/projectReactQuery.ts:26-41` at commit `b73b2c9c` (shows `enabled` condition and `placeholderData` returning previous data).

- Switch composer menu arrow-key navigation to `Command`'s internal highlight handling
- Track highlighted item by id instead of manual index/keyboard state
- Remove custom hover/highlight plumbing and hidden-scroll sync logic
@juliusmarminge
Copy link
Copy Markdown
Member Author

@greptileai review

Copy link
Copy Markdown

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

23 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

{ wait: COMPOSER_PATH_QUERY_DEBOUNCE_MS },
(debouncerState) => ({ isPending: debouncerState.isPending }),
);
const effectivePathQuery = pathTriggerQuery.length > 0 ? debouncedPathQuery : "";
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

empty query should skip debouncing to show results immediately

Suggested change
const effectivePathQuery = pathTriggerQuery.length > 0 ? debouncedPathQuery : "";
const effectivePathQuery = pathTriggerQuery.length > 0 ? debouncedPathQuery : pathTriggerQuery;

Comment thread apps/server/src/workspaceEntries.ts
@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Feb 18, 2026

Additional Comments (1)

apps/web/src/components/ChatView.tsx
tagged paths from @path tokens aren't extracted and sent to the model - they stay in the text but there's no structured "Referenced paths" context like buildPromptInput creates

@juliusmarminge juliusmarminge merged commit 9e877f5 into main Feb 18, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant