fix(chat-sidebar): refresh @-mention picker when workspace files change#251
Merged
mbektas merged 2 commits intoMay 16, 2026
Merged
Conversation
Before this fix, the workspace file picker scanned once on first open and cached the result for the lifetime of the chat-sidebar component. `workspaceFilesLoaded` was set true after the initial scan and never reset, with no `ContentsManager.fileChanged` subscription and no manual refresh affordance. A user who created a notebook in the file browser, ran `touch foo.py` in a terminal, or had Claude generate files would not see them in the @-mention picker until a full lab reload. The fix subscribes to `ContentsManager.fileChanged` and either rescans (if the picker is open) or invalidates the cache (if it's closed). Three design decisions: 1. **300ms debounce.** Bulk file ops (folder drag-drop, agent-driven notebook creation) fire many signals back-to-back. Without coalescing, one drop of N items would schedule N rescans. 300ms is the knee: drag-drops settle inside it, single user-initiated creates feel responsive. 2. **In-flight gate, not force-cancel.** Earlier drafts force-canceled the previous scan on every signal. Worst-case (open picker, agent creating files at 2/s, scans taking ~1s) that produced a never- completing scan storm. `runWorkspaceFileScan` instead sets `pendingRescanRef` while a scan is in flight and the running scan drains the flag at completion, bounding the storm to "at most one running + one queued." 3. **Stable subscription deps.** The first effect attempt used `[props]`. ReactWidget rebuilds `props` on every Lumino update, so the effect connected/disconnected the signal on every parent render and cleared the in-flight debounce timer mid-coalesce — defeating the whole point. The contents manager is a singleton, captured once via `appRef`, and the effect now uses `[]` deps. A manual refresh button is added to the picker header (`VscRefresh`) as the escape hatch for the gap below. Known limitation: `ContentsManager.fileChanged` fires only on operations that round-trip through the Contents API. Some NBI agent tools (`built_in_toolsets.py`) write to disk directly via `open()` and bypass the API; those changes don't auto-refresh. The manual refresh button is the mitigation. Tracked as a follow-up to route agent writes through the Contents API. Drive-by a11y fix on the picker's close button: it was a bare `<div onClick>`. Now mirrors the refresh button's affordances — role, tabIndex, aria-label, Enter/Space keyboard handler. A `:focus-visible` style is added to `.mode-tools-popover-button` so keyboard users can see focus on either button. No new tests. The testable surface is a one-line predicate (`change.type !== 'save'`); the React-component-level behavior (signal subscription, debounce, gate) lacks component-test infrastructure in the codebase. Manual verification: created files via file browser, terminal, and an agent tool — picker auto-refreshes in the first two cases and refreshes on manual button in the third.
cb083e3 to
5682150
Compare
…ball The TestArchiveSizeCap cases were patching notebook_intelligence.skill_github_import._get_github_token, which doesn't exist (the module imports resolve_github_token from notebook_intelligence.util). mock.patch raised AttributeError at context-manager enter, breaking the suite on every fresh clone. Patch the imported reference in the skill_github_import namespace (resolve_github_token) so the mock takes effect inside _fetch_tarball's call site.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The chat-sidebar `@`-mention workspace file picker scanned once on first open and cached the result for the lifetime of the chat sidebar — `workspaceFilesLoaded` was set true after the initial scan and never reset, with no `ContentsManager.fileChanged` subscription and no manual refresh affordance. Users creating a notebook in the file browser, running `touch foo.py` in a terminal, or letting Claude generate files would not see them in the picker until a full lab reload.
Solution
Subscribe to `ContentsManager.fileChanged`. When the picker is open the new file shows up after a 300ms debounce; when it's closed the cache is marked stale so the next open re-scans. A manual refresh icon button (`VscRefresh`) is added to the picker header as the escape hatch for the limitation below.
Three load-bearing decisions, all flagged by reviewers and addressed before push:
Plus two small a11y fixes the reviewer flagged in the same surface:
Testing
Risks / follow-ups