feat(vscode): @ file mention with dropdown and file chips#397
feat(vscode): @ file mention with dropdown and file chips#397
Conversation
Add findFiles() to HttpClient, add RequestFileSearchMessage/FileSearchResultMessage message types, and handle requestFileSearch in KiloProvider.
- Detect @<query> pattern in textarea and show fuzzy file search dropdown - Keyboard navigation (arrows, Enter/Tab to select, Escape to close) - Selected files appear as removable chips below the textarea - Chips are sent as FileAttachment[] with the message on submit
…chips - Add .svg dataurl loader to esbuild for webview and agent-manager builds - Replace hardcoded SVG with FileIcon from @kilocode/kilo-ui/file-icon - Dropdown shows: [icon] filename parent/path (name bold, dir muted right-aligned) - Chips show: [icon] filename
Use a custom esbuild plugin to inject sprite.svg into document.body as a hidden element instead of using the dataurl loader. This avoids VS Code webview's cross-origin block on <use href="data:..."> references.
packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx
Outdated
Show resolved
Hide resolved
packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx
Outdated
Show resolved
Hide resolved
Code Review SummaryStatus: 1 Issue Found | Recommendation: Address before merge Overview
Issue Details (click to expand)WARNING
Files Reviewed (6 files)
|
There was a problem hiding this comment.
Pull request overview
This PR implements @ file mention functionality for the VS Code extension's chat interface, allowing users to tag and attach files to their messages through a fuzzy search dropdown.
Changes:
- Added file search API endpoint integration (
/find/file) with debounced search - Implemented keyboard-navigable dropdown with fuzzy file search triggered by @ symbol
- Added removable file chips to display attached files before sending
- Extended message handling to include
FileAttachment[]in chat messages
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
packages/kilo-vscode/webview-ui/src/types/messages.ts |
Added RequestFileSearchMessage and FileSearchResultMessage types for file search communication |
packages/kilo-vscode/webview-ui/src/styles/chat.css |
Added CSS for file mention dropdown and attached file chips with VS Code theme integration |
packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx |
Implemented @ detection, file search, dropdown with keyboard navigation, and file chip UI |
packages/kilo-vscode/src/services/cli-backend/http-client.ts |
Added findFiles method to query backend /find/file endpoint |
packages/kilo-vscode/src/KiloProvider.ts |
Added message handler for requestFileSearch to call backend and return results |
packages/kilo-vscode/esbuild.js |
Added svgSpritePlugin to inject FileIcon SVG sprite into webview DOM to avoid CSP issues |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx
Outdated
Show resolved
Hide resolved
packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx
Outdated
Show resolved
Hide resolved
packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx
Outdated
Show resolved
Hide resolved
packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx
Outdated
Show resolved
Hide resolved
packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx
Outdated
Show resolved
Hide resolved
packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx
Outdated
Show resolved
Hide resolved
packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx
Outdated
Show resolved
Hide resolved
- Add .catch() to findFiles promise, posting paths:[] on failure so the webview doesn't hang (KiloProvider.ts) - Fix AT_PATTERN to require word boundary before @ to avoid false triggers on email addresses and mid-word @ symbols - Increment fileSearchCounter before setTimeout to prevent duplicate requestIds when multiple keystrokes fire before the debounce fires
- Replace inline SVG send/stop icons with Icon name="arrow-up"/"stop" - Replace hand-rolled chip remove button with IconButton icon="close-small" - Remove .file-chip-remove CSS ruleset (no longer needed)
Move all @ mention logic into a dedicated hook: - Signals: attachedFiles, mentionQuery, mentionResults, mentionIndex - onInput(val, cursor): boolean — AT_PATTERN detection, returns true if consumed - onKeyDown(e, textarea): boolean — dropdown navigation, returns true if consumed - selectFile, removeFile, closeMention, buildFileAttachments, clearAttachedFiles PromptInput retains only text/ghostText state, autocomplete, and JSX.
- Add multiline support: regex now matches @ after newlines (m flag) - Show dropdown on bare @: trigger search with empty query to show all/recent files - Add empty state: display 'No files found' when search returns 0 results
adfd2c1 to
7f869a4
Compare
… createEffect The createEffect approach didn't work because dropdownRef is inside a <Show> block — the ref is undefined when the effect is first created and is not reactive, so the effect never runs. Move scroll logic to handleKeyDown where dropdownRef is guaranteed to exist when the dropdown is visible, using queueMicrotask to defer until after Solid updates DOM.
| import type { FileAttachment, WebviewMessage, ExtensionMessage } from "../types/messages" | ||
|
|
||
| const FILE_SEARCH_DEBOUNCE_MS = 150 | ||
| const AT_PATTERN = /(?:^|\s)@(\S*)$/m |
There was a problem hiding this comment.
[WARNING]: The m (multiline) flag on AT_PATTERN causes $ to match end-of-line, not just end-of-string
In a multiline textarea, if the user types:
hello @foo
some other text|
(cursor at |), before will be "hello @foo\nsome other text". With the m flag, $ matches the end of the first line, so the regex matches @foo on line 1 — even though the cursor is on line 2. This would incorrectly trigger the mention dropdown for a stale @ on a previous line.
Remove the m flag so $ only matches end-of-string (i.e. the cursor position):
| const AT_PATTERN = /(?:^|\s)@(\S*)$/m | |
| const AT_PATTERN = /(?:^|\s)@(\S*)$/ |
| this.postMessage({ type: "fileSearchResult", paths: [], requestId: message.requestId }) | ||
| }) | ||
| } | ||
| break |
There was a problem hiding this comment.
[WARNING]: No response sent when httpClient is null
If this.httpClient is falsy, the requestFileSearch message is silently dropped — no fileSearchResult is ever posted back. The webview's mention dropdown will remain open indefinitely, waiting for a response that never arrives.
Consider sending back an empty result when the client isn't available:
case "requestFileSearch": {
const client = this.httpClient
if (client) {
// ... existing code ...
} else {
this.postMessage({ type: "fileSearchResult", paths: [], requestId: message.requestId })
}
break
}| e.preventDefault() | ||
| const path = mentionResults()[mentionIndex()] | ||
| if (path && textarea) selectMentionFile(path, textarea, setText) | ||
| return true |
There was a problem hiding this comment.
[WARNING]: Enter key is swallowed when mention dropdown is open but results are empty
When showMention() is true (user typed @) but mentionResults() is empty (no files matched), pressing Enter calls e.preventDefault() and returns true — but selectMentionFile is never called because path is undefined. This silently swallows the Enter key, preventing the user from sending their message.
Consider also checking that there are results before intercepting Enter/Tab:
| return true | |
| if ((e.key === "Enter" || e.key === "Tab") && mentionResults().length > 0) { |
Summary
Closes #289 —
@file tagging with dropdown menu for the VS Code extension.What's new
@in the chat input to trigger a fuzzy file search dropdown×to remove)FileAttachment[]with the message on submitFileIconfrom@kilocode/kilo-ui/file-iconfor VS Code–themed file type iconsImplementation
http-client.ts:findFiles(query, dir)→GET /find/file?query=...&dirs=false&limit=10messages.ts:RequestFileSearchMessage(webview→ext) andFileSearchResultMessage(ext→webview)KiloProvider.ts: handlesrequestFileSearch, callsfindFiles, posts result backPromptInput.tsx:@detection, debounced search, dropdown with keyboard nav, file chipsesbuild.js: customsvgSpritePlugininjects the file-icon SVG sprite intodocument.bodyto avoid VS Code webview cross-origin<use href="data:...">errorschat.css: dropdown item layout[icon] filename parent/dirand chip layout[icon] filename ×