mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-29 18:46:59 +00:00
fix(desktop): keep slash completion alive after a leading command
Typing a second slash command in the composer went dead whenever the message started with one. `/work /cle` offered nothing, while `do /work then /cle` completed fine — which read as an intermittent glitch rather than a rule. Two regexes detect a slash, and the `^`-anchored command shape was tried first. Its argument tail (`(?:\s+\S*)*`) swallows the rest of the line, so a later `/skill` parsed as an argument to the first command; a command that takes no options then suppresses the popover outright, and every slash after the first was unreachable. Only the first slash can be an invocation, so detect the inline shape first. It requires a whitespace-preceded slash sitting at the caret, so it can't take over ordinary argument completion (`/personality alic` has no second slash) — it fires only where completion was already dead.
This commit is contained in:
parent
84858d76ba
commit
eb851d619e
2 changed files with 37 additions and 7 deletions
|
|
@ -120,6 +120,29 @@ describe('useComposerTrigger — slash anywhere in the prompt', () => {
|
|||
|
||||
expect(hook.result.current.trigger).toBeNull()
|
||||
})
|
||||
|
||||
it('opens the list for a second slash after a leading command', () => {
|
||||
// `/work /cle`: the command regex's argument tail would otherwise swallow
|
||||
// `/cle` as an argument to `/work`, and a no-arg command suppresses the
|
||||
// popover — so every slash after the first went dead.
|
||||
const editor = mountEditor('/work /cle')
|
||||
const { hook } = mountTrigger(editor, [item('/clean')])
|
||||
|
||||
act(() => hook.result.current.refreshTrigger())
|
||||
|
||||
expect(hook.result.current.trigger).toMatchObject({ kind: '/', inline: true, query: 'cle' })
|
||||
expect(hook.result.current.triggerItems).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('inserts the second command without disturbing the first', () => {
|
||||
const editor = mountEditor('/work rewrite the composer /cle')
|
||||
const { hook } = mountTrigger(editor, [item('/clean')])
|
||||
|
||||
act(() => hook.result.current.refreshTrigger())
|
||||
act(() => hook.result.current.replaceTriggerWithChip(item('/clean')))
|
||||
|
||||
expect(composerPlainText(editor)).toBe('/work rewrite the composer /clean ')
|
||||
})
|
||||
})
|
||||
|
||||
describe('useComposerTrigger — free-text slash arguments', () => {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,11 @@ export interface TriggerState {
|
|||
// there are no args to complete — the trigger is a single token that ends at
|
||||
// the next space, exactly like `@`.
|
||||
//
|
||||
// Only the FIRST slash can be an invocation, so the inline shape is tested
|
||||
// first: the command regex's argument tail (`(?:\s+\S*)*`) happily swallows a
|
||||
// later `/skill` as if it were an argument, which killed completion for every
|
||||
// slash after a leading command (`/work /cle` → nothing).
|
||||
//
|
||||
// The inline shape is what makes skills reachable anywhere in a prompt. Both
|
||||
// shapes need the trailing `$`: detection runs against the text BEFORE the
|
||||
// caret, so the match must end where the user is typing.
|
||||
|
|
@ -124,14 +129,10 @@ export function textBeforeCaret(editor: HTMLDivElement): string | null {
|
|||
}
|
||||
|
||||
export function detectTrigger(textBefore: string): TriggerState | null {
|
||||
const command = SLASH_COMMAND_TRIGGER_RE.exec(textBefore)
|
||||
|
||||
if (command) {
|
||||
return { kind: '/', query: command[2], tokenLength: 1 + command[2].length }
|
||||
}
|
||||
|
||||
// An inline `/skill` is a reference dropped into prose, so it carries no args
|
||||
// and the whole match is the token the chip replaces.
|
||||
// and the whole match is the token the chip replaces. Checked before the
|
||||
// anchored command shape so a second slash isn't mistaken for the first
|
||||
// command's argument.
|
||||
const inline = SLASH_INLINE_TRIGGER_RE.exec(textBefore)
|
||||
|
||||
if (inline) {
|
||||
|
|
@ -140,6 +141,12 @@ export function detectTrigger(textBefore: string): TriggerState | null {
|
|||
return { inline: true, kind: '/', query, tokenLength: 1 + query.length }
|
||||
}
|
||||
|
||||
const command = SLASH_COMMAND_TRIGGER_RE.exec(textBefore)
|
||||
|
||||
if (command) {
|
||||
return { kind: '/', query: command[2], tokenLength: 1 + command[2].length }
|
||||
}
|
||||
|
||||
const at = AT_TRIGGER_RE.exec(textBefore)
|
||||
|
||||
if (at) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue