fix(desktop): surface an exactly-typed command alias in slash completions
Typing /reset to completion showed an empty "no matches" popover while Enter still executed the command, because aliases are hidden while browsing. An exact typed query now unlocks its own alias, gated on isDesktopSlashCommand so aliases with no desktop surface stay hidden. Fixes #57641
This commit is contained in:
@@ -12,7 +12,7 @@ import {
|
||||
type DesktopThemeCommandOption,
|
||||
filterDesktopCommandsCatalog,
|
||||
isDesktopSlashExtensionCommand,
|
||||
isDesktopSlashSuggestion,
|
||||
isDesktopSlashSuggestionWithOptions,
|
||||
rankSkillCommands,
|
||||
slashCompletionGroup
|
||||
} from '@/lib/desktop-slash-commands'
|
||||
@@ -221,6 +221,12 @@ export function useSlashCompletions(options: {
|
||||
const isArgCompletion = replaceFrom > 1
|
||||
const prefix = isArgCompletion ? text.slice(0, replaceFrom) : ''
|
||||
|
||||
// An alias the user typed to completion (`/reset`) must surface even
|
||||
// though aliases are hidden while browsing — otherwise the popover
|
||||
// says "no matches" for a command Enter happily executes (#57641).
|
||||
// Only an EXACT match unlocks it; a partial prefix keeps hiding.
|
||||
const exactAliasQuery = isArgCompletion ? undefined : commandText(query).toLowerCase()
|
||||
|
||||
const decorated = (result.items ?? [])
|
||||
.map(item => {
|
||||
if (!isArgCompletion) {
|
||||
@@ -231,7 +237,10 @@ export function useSlashCompletions(options: {
|
||||
|
||||
return { ...item, text: `${prefix}${argText}` }
|
||||
})
|
||||
.filter(item => isArgCompletion || isDesktopSlashSuggestion(item.text))
|
||||
.filter(
|
||||
item =>
|
||||
isArgCompletion || isDesktopSlashSuggestionWithOptions(item.text, { exactAlias: exactAliasQuery })
|
||||
)
|
||||
.map(item => ({
|
||||
...item,
|
||||
// Arg suggestions (e.g. `/handoff <platform>`) live under one
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
isDesktopSlashCommand,
|
||||
isDesktopSlashExtensionCommand,
|
||||
isDesktopSlashSuggestion,
|
||||
isDesktopSlashSuggestionWithOptions,
|
||||
isModelPickerCommand,
|
||||
isPickerCommand,
|
||||
rankSkillCommands,
|
||||
@@ -149,6 +150,22 @@ describe('desktop slash command curation', () => {
|
||||
expect(isDesktopSlashCommand('/reset')).toBe(true)
|
||||
})
|
||||
|
||||
it('surfaces an alias the user typed exactly, gated on desktop availability (#57641)', () => {
|
||||
// Browsing (no exact query): aliases stay hidden — popover stays lean.
|
||||
expect(isDesktopSlashSuggestionWithOptions('/reset')).toBe(false)
|
||||
// Exact typed query: the alias must appear, not "no matches".
|
||||
expect(isDesktopSlashSuggestionWithOptions('/reset', { exactAlias: '/reset' })).toBe(true)
|
||||
expect(isDesktopSlashSuggestionWithOptions('/reset', { exactAlias: 'reset' })).toBe(true)
|
||||
// Partial prefixes and other queries keep aliases hidden.
|
||||
expect(isDesktopSlashSuggestionWithOptions('/reset', { exactAlias: 're' })).toBe(false)
|
||||
expect(isDesktopSlashSuggestionWithOptions('/reset', { exactAlias: '/new' })).toBe(false)
|
||||
// A different alias never rides along with this query.
|
||||
expect(isDesktopSlashSuggestionWithOptions('/fork', { exactAlias: '/reset' })).toBe(false)
|
||||
// Aliases whose canonical has no desktop surface stay hidden even on an
|
||||
// exact match (isDesktopSlashCommand gate).
|
||||
expect(isDesktopSlashSuggestionWithOptions('/reload_mcp', { exactAlias: '/reload_mcp' })).toBe(false)
|
||||
})
|
||||
|
||||
it('filters built-in catalog noise but keeps skill / quick-command extensions', () => {
|
||||
const filtered = filterDesktopCommandsCatalog({
|
||||
categories: [
|
||||
|
||||
@@ -556,10 +556,28 @@ export function isDesktopSlashCommand(command: string): boolean {
|
||||
|
||||
/** Gates discovery in the popover/completions. */
|
||||
export function isDesktopSlashSuggestion(command: string): boolean {
|
||||
return isDesktopSlashSuggestionWithOptions(command, {})
|
||||
}
|
||||
|
||||
/**
|
||||
* Same gate, with the one escape hatch the composer needs: an alias the user
|
||||
* typed EXACTLY (`/reset`, not a browsing prefix) must surface, or the empty
|
||||
* "no matches" popover reads as "this command doesn't exist" while Enter still
|
||||
* executes it (#57641). Gated on `isDesktopSlashCommand` so aliases whose
|
||||
* canonical has no desktop surface (e.g. `/reload_mcp`) stay hidden.
|
||||
*/
|
||||
export function isDesktopSlashSuggestionWithOptions(
|
||||
command: string,
|
||||
options: { exactAlias?: string } = {}
|
||||
): boolean {
|
||||
const normalized = normalizeCommand(command)
|
||||
|
||||
// Aliases stay hidden so the popover isn't cluttered with duplicates.
|
||||
if (isAliasCommand(normalized)) {
|
||||
if (options.exactAlias != null) {
|
||||
return normalizeCommand(options.exactAlias) === normalized && isDesktopSlashCommand(normalized)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user