You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add an explicit skill browser to the composer add menu. This PR owns skill discovery and selection UI; the visual representation of an already-selected skill belongs to #422.
This PR is stacked on #422 and should be reviewed against balint/composer-skill-pill.
Scope
Add a searchable skill browser to the composer add menu
Place search at the top when the menu opens downward and at the bottom when it opens upward
Consolidate upload, connection, and skill actions in that menu
Require an explicit picker selection before text acquires skill semantics
Keep unselected /text, //text, and pasted slash text as ordinary text
Show description, provider, and resource context consistently in add-menu and slash-command results
Keep the Tab hint in normal layout without changing the skill-name column width
Use the compact-specific Phosphor icon for the built-in /compact skill
Refresh the shared skill catalog after a resource connection is successfully retained
Protect replacement catalog loads from stale failed promises
Preserve focus across add-menu Escape and connection-dialog transitions
Move composer-owned slash-command UI logic into the composer feature
Deliberately Unchanged
There is no custom rich clipboard format or pasted-skill upgrade path
Sending does not resolve or validate unselected slash text
This PR does not add new draft, attachment, resource, send, or recovery semantics
The branch was rebased after #422 was reduced to a geometry-safe visual-only change. Rich-paste validation and its asynchronous coordination remain out of scope.
Testing
52 frontend test files pass (337 tests)
Workshop frontend application and Vite TypeScript checks pass
[P1]ChatComposer.tsx:1030 always consumes Enter while the slash picker is open. For /unknown or failed/empty catalogs, no choice is selected and keyboard submission becomes impossible. Only intercept Enter when a choice can be confirmed.
[P2]ChatComposer.tsx:578 reuses a numeric caret captured when the add menu opened. Async resource or format updates can shift tokens before selection, allowing insertion at the wrong position or inside token backing text. Rebase or re-snap against the current document.
[P2]ChatComposer.tsx:1130 renders “More chat options” whenever offerFormats is true, but ComposerFormatMenuItems returns nothing while loading, on failure, or when no formats exist. Home can therefore expose an empty menu.
[P2]ComposerAddMenu.tsx:316 hides catalog failures for an empty query because upload and connection actions keep items.length nonzero. Render the skill error independently of those actions.
[P2]ComposerAddMenu.tsx:360 closes via a direct state toggle, bypassing close() and retaining the search query. Reopening can unexpectedly remain filtered and hide Upload and Add Connection.
[P2]ComposerAddMenu.tsx:133 calls close(false) before opening the hidden file input. Cancelling the native chooser can leave keyboard focus on body; restore focus for the upload path.
[P2]ComposerAddMenu.tsx:243 focuses the listbox when a skill is already selected, but provides neither aria-activedescendant nor focusable options. Arrow navigation is not reliably announced by assistive technology.
Stack reset: #423 was rebased onto the visual-only #422. The rich-paste path was dropped, and unselected /text, //text, and browser-pasted slash text now retain ordinary text semantics through send. Earlier findings tied to rich clipboard validation or asynchronous paste coordination no longer apply to the current branch.
[P1]SlashCommandPicker.tsx:247-262 removes visible provider/resource identity. Duplicate skills become indistinguishable on touch devices because identity exists only in title.
[P1]ComposerAddMenu.tsx:55-74,190-204 positions against innerHeight and ignores visualViewport. The mobile keyboard can obscure the focused skill browser entirely.
[P2]ComposerAddMenu.tsx:219-220 closes a body-end portal on Tab. Native focus navigation then wraps around the page instead of moving to adjacent composer controls.
Duplicate /name skills were already indistinguishable in the previous slash picker; provider/resource disambiguation is a separate UX improvement, not a regression in this PR.
The previous slash picker also positioned from window.innerWidth/innerHeight without visualViewport, so the mobile-keyboard behavior is preexisting.
The Tab focus wrap is new to the add-menu portal and is fixed by making Tab activate the highlighted item, matching the slash picker.
[P2]ComposerAddMenu.tsx:145-165 retains actionable skills from the previous getOverseer while the replacement catalog loads or fails. Clear/source-tag the catalog or disable stale rows during reload.
[P2]ComposerAddMenu.tsx:304 only constrains skill-name width at sm; long names overflow mobile rows and obscure description/provider identity. Apply the width cap at the base breakpoint.
[P2] ComposerAddMenu.tsx:214 Escape also reaches CapsuleOverlay’s document listener, dismissing the active URL overlay and preventing it from reopening at the unchanged caret. Stop propagation when closing the add menu.
[P2] ComposerAddMenu.tsx:135 Opening “Add a new connection” first unmounts the focused option, leaving GatekeeperModal without a valid return-focus target. Canceling the dialog can strand keyboard focus on body. Focus the persistent add trigger before opening the modal.
The reason will be displayed to describe this comment to others. Learn more.
Looks great! We should distinguish /compact from skill invocation here too:
The only interaction that feels odd is the search bar moving vertically after you start typing here:
I would expect it to stay in the same place. The search box being at the very bottom is also a bit odd. Maybe we need to reorder this panel depending on whether it's above or below the composer?
[P2]ChatComposer.tsx:448 invalidates only the composer creating a connection. In sidebar mode, the other mounted composer’s slash picker keeps its local catalog and never discovers new skills until remount.
[P2]ComposerAddMenu.tsx:275,362 moves an unkeyed search input when placement flips. Resize or scroll remounts it, dropping focus and interrupting keyboard input.
[P2]SlashCommandPicker.tsx:235-276 prioritizes stale choices over replacement-load errors. After invalidation fails, users see permanently disabled old commands instead of the failure message.
[P2] ComposerAddMenu.tsx:198-213 Layout updates only on window resize or scroll. If the prompt card itself resizes, such as when “Pending changes” appears, an upward-opening menu remains fixed and overlaps the composer. Observe the anchor with ResizeObserver and recompute placement.
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
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
Add an explicit skill browser to the composer add menu. This PR owns skill discovery and selection UI; the visual representation of an already-selected skill belongs to #422.
This PR is stacked on #422 and should be reviewed against
balint/composer-skill-pill.Scope
/text,//text, and pasted slash text as ordinary text/compactskillDeliberately Unchanged
The branch was rebased after #422 was reduced to a geometry-safe visual-only change. Rich-paste validation and its asynchronous coordination remain out of scope.
Testing
Dependency