Feat/vscode context mentions - #842
Conversation
Typing `@` in the chat input opens a floating dropdown of workspace files, folders, and open editors. Selecting one attaches it as a context chip. Reuses the existing attachment pipeline rather than adding a parallel one: completions push into the same `attachedPaths` state the attach button already feeds, so chip rendering, `@[file]` serialization and host-side expansion are untouched. - Search runs on the extension host via workspace.findFiles, which honours files.exclude/search.exclude; open editor tabs resolve with no disk I/O - Requests carry an id so out-of-order postMessage responses are dropped - `@` triggers only at line start or after whitespace, so emails and decorators do not open the dropdown - Cap attached file reads at 100 KB and skip binaries, since `@` makes attaching cheap enough to exhaust the context window by accident
CI runs ava with FORCE_COLOR=1, so Ink emits the themed indicator wrapped in escape sequences and the frame line starts with \x1b[34m rather than `>`. The anchored regexes could therefore never match, while locally the colours are stripped and the tests passed. Strip the frame with strip-ansi before splitting, matching the existing convention in app-container.spec.tsx. Verified under both CI=true FORCE_COLOR=1 and a plain local run.
The "reports and restores submitted drafts with attachments" test flaked in CI. Instrumenting it showed the frame rendered the typed text but onSubmit was called zero times, so the poll for the submitted value ran out its budget with nothing pending - the Enter had been swallowed, not delayed. Ink's useInput unsubscribes from stdin and resubscribes across a re-render, so an Enter written while React is still flushing the typed characters is lost. Raising the deadline cannot help when no submit is in flight. Route every Enter through a helper that first waits for the frame to stop changing, which keeps the keystroke clear of that window. Resending Enter was rejected as an alternative: handleSubmit has no empty-input guard, so a duplicate would submit '' and clobber the captured value. Verified with the full file under CI=true FORCE_COLOR=1: six consecutive clean runs, against a one-in-three failure rate beforehand.
The first pass spread this feature across four new modules plus three spec files, and picked up changes unrelated to Nano-Collective#747. Reviewing it meant reading 1.4k added lines for what is a dropdown over a workspace search. Everything now lives in the files the feature already had to touch: - mention-search.ts collapses into a single _searchMentions method on ChatWebviewProvider. Ranking and matching are unchanged; the injectable MentionSearchDeps seam and the hand-rolled posix path helpers are gone, since path.relative/basename/dirname already handle both separators. - mention-utils.js collapses into chat-panel.js. findMentionQuery moves in as-is; removeMentionToken was three lines at its only call site, so it is inlined there. That drops the extra <script> tag, its CSP-nonce wiring and the globalThis handoff. - MentionItem moves to webview-protocol.ts next to the two messages that carry it, and its source enum narrows to an isEditor flag. Reverted as out of scope for this issue: - context-attachment.ts and the 100 KB cap / binary sniff it added to _expandContextAttachments. Worth doing, but it is not @ autocomplete and the attach button has always had the same exposure - separate PR. - The user-input and styled-select-input spec fixes, which are already their own branches. - chat-panel.css, a Tailwind rebuild whose only delta was an unrelated .container rule; every class the dropdown uses was already compiled. The three spec files go with their modules. AVA only globs source/**, so plugins/vscode specs never ran in CI and none of them were executing. No behaviour change: same trigger rules, same ranking, same keyboard handling, same postMessage protocol.
9230511 to
7dc000d
Compare
|
Hey @addyCooks - thanks for this, the design is solid - host-side search, the request-id staleness guard, mousedown over click, and folding the keys into the existing A few things before merge: The description doesn't match the diff. The body describes The 100 KB read cap isn't in the diff either. Escape while streaming kills the agent turn. The mention Escape branch calls
Stale Smaller stuff: accepting mid-token leaves the suffix behind ( |
Reverses the structural half of "fold @ mention support into the existing files" and addresses the defects found in review of Nano-Collective#842. The fold's argument for dropping the specs was that AVA only globs source/**, so none of them executed. That is fixed rather than worked around: ava.files now includes plugins/**, so the three spec files run in `pnpm test:ava` and in CI. acp-client and acp-process-manager are excluded explicitly — they transitively require('vscode'), which does not resolve outside the extension host. They stay in the state they are in today. Restored: - mention-search.ts, carrying the fold's improvements forward: MentionItem comes from webview-protocol.ts and the source enum stays collapsed to an isEditor flag. The injectable MentionSearchDeps seam is back, since testability without an extension host is the whole point. - mention-utils.js and context-attachment.ts, with their specs. Fixed: - files.exclude was not honoured. An explicit exclude *replaces* VS Code's defaults rather than merging, so .env and anything else hidden by the user showed up in the dropdown. _mentionExcludeGlob now folds files.exclude and search.exclude into the always-on list, scoped to the workspace folder being searched, skipping `when`-clause entries. - mentionToken was assigned after the dedupe guard in requestMentions. With `@foo @foo`, moving the caret between the two short-circuited the guard and left start pointing at the wrong mention, so accepting added the chip but stripped the other one. Assigned in syncMentionState now. - Accepting mid-token sliced only up to the caret, stranding the tail: `@src/foo` accepted from after `src` left `/foo` behind. removeMentionToken takes the whole token. - The dedupe key folded case unconditionally, so on a case-sensitive filesystem `Foo.ts` and `foo.ts` collapsed and one silently vanished. Folding is now conditional on the filesystem, injectable for tests. - `@**` widened to a match-everything glob, scanned the workspace, then filtered every result away against the raw `**` needle. Queries with no literal characters no longer touch disk, and result filtering uses the metacharacter-stripped query so `*app*` still finds app.ts. - The listbox had role=option rows but nothing tied them to the textarea. Added aria-activedescendant, plus role=combobox / aria-expanded / aria-controls and stable row ids. - The mention Escape branch called preventDefault without stopPropagation. No handler above it cancels on Escape today, so this is not reachable, but the branch should not depend on that. - The fold had swapped the hand-rolled posix path helpers for node's `path`. `path` binds to the host separator, so the Windows-path tests passed locally and meant nothing on Linux. Helpers are hand-rolled against the posix form again. Also restores the 100 KB read cap and binary sniff on attached files, scoped out of the fold as a separate concern — @ makes attaching a lockfile one keystroke, so it belongs with this change. The styled-select-input spec fix is dropped from this branch; it is byte-identical to fix/styled-select-input-ansi-assertions.
Per review feedback, these ANSI stripping changes are unrelated to the @ mention feature and should be in a separate PR.
7dc000d to
ac5abf5
Compare
|
Hey @will-lamerton, The PR description has been updated to accurately reflect the current implementation. |
Closes #747.
Summary
Implements @ mention autocomplete in the VS Code extension's chat composer, allowing users to explicitly attach workspace files, folders, and open editors as context. Typing
@displays a dropdown with fuzzy-matched suggestions; selecting an item attaches it as a chip that's expanded into the AI's context on submit.Files Changed
New Modules
mention-search.tsmention-search.spec.tsmention-utils.jsmention-utils.spec.tscontext-attachment.tscontext-attachment.spec.tsModified Files
webview-protocol.tschat-webview-provider.tschat-panel.jschat-panel.html.changeset/vscode-context-mentions.mdType of Change
Changeset
pnpm changeset) describing this change for the changelogTesting
Automated Tests
.spec.ts/tsxfilespnpm test:allcompletes successfully)Manual Testing
###Checklist