mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-16 13:03:31 +08:00
fix: keep agent slash selection editable before send (#653)
Selecting a concrete /agent entry from the composer suggestions should prepare the command and leave focus in the editor so the user can type the required prompt. The Enter send shortcut still applies after the suggestion menu is closed, and exact non-agent slash commands keep their existing direct execution path when they remain highlighted. Constraint: The desktop composer supports configurable Enter vs Ctrl/Cmd+Enter sending. Rejected: Special-case only /agent entries | the highlighted suggestion should consistently win while the menu is open. Confidence: high Scope-risk: narrow Directive: Keep ChatInput and EmptySession slash-key handling aligned with shared send shortcut behavior. Tested: cd desktop && bun run test -- --run src/components/chat/composerUtils.test.ts src/components/chat/ChatInput.test.tsx src/pages/EmptySession.test.tsx Tested: bun run check:desktop Not-tested: Live backend agent-list integration beyond mocked desktop composer coverage.
This commit is contained in:
parent
3f1312d40d
commit
959e177cdf
@ -1101,4 +1101,54 @@ describe('ChatInput file mentions', () => {
|
||||
|
||||
expect(input).toHaveValue('/agent debugger ')
|
||||
})
|
||||
|
||||
it('selects a highlighted agent entry from /agent without sending until the configured send shortcut is used', async () => {
|
||||
useSettingsStore.setState({
|
||||
chatSendBehavior: 'modifierEnter',
|
||||
})
|
||||
mocks.listAgents.mockResolvedValue({
|
||||
activeAgents: [
|
||||
{
|
||||
agentType: 'debugger',
|
||||
description: 'Debug failures',
|
||||
modelDisplay: 'OPUS',
|
||||
source: 'userSettings',
|
||||
isActive: true,
|
||||
},
|
||||
],
|
||||
allAgents: [],
|
||||
})
|
||||
|
||||
render(<ChatInput />)
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mocks.listAgents).toHaveBeenCalledWith('/repo')
|
||||
})
|
||||
|
||||
const input = screen.getByRole('textbox') as HTMLTextAreaElement
|
||||
fireEvent.change(input, {
|
||||
target: { value: '/agent', selectionStart: 6 },
|
||||
})
|
||||
|
||||
await screen.findByText('/agent debugger')
|
||||
fireEvent.keyDown(input, { key: 'ArrowDown' })
|
||||
fireEvent.keyDown(input, { key: 'Enter' })
|
||||
|
||||
expect(input).toHaveValue('/agent debugger ')
|
||||
expect(mocks.wsSend).not.toHaveBeenCalled()
|
||||
|
||||
const prompt = '/agent debugger investigate this failure'
|
||||
fireEvent.change(input, {
|
||||
target: { value: prompt, selectionStart: prompt.length },
|
||||
})
|
||||
fireEvent.keyDown(input, { key: 'Enter' })
|
||||
expect(mocks.wsSend).not.toHaveBeenCalled()
|
||||
|
||||
fireEvent.keyDown(input, { key: 'Enter', ctrlKey: true })
|
||||
expect(mocks.wsSend).toHaveBeenCalledWith(sessionId, {
|
||||
type: 'user_message',
|
||||
content: prompt,
|
||||
attachments: [],
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -737,8 +737,10 @@ export function ChatInput({ variant = 'default', compact = false }: ChatInputPro
|
||||
return
|
||||
}
|
||||
if (event.key === 'Enter') {
|
||||
const selected = filteredCommands[slashSelectedIndex]
|
||||
if (
|
||||
exactSlashCommand &&
|
||||
selected?.name.toLowerCase() === exactSlashCommand.name.toLowerCase() &&
|
||||
slashFilter.trim().toLowerCase() === exactSlashCommand.name.toLowerCase() &&
|
||||
shouldSubmitOnEnter(event, chatSendBehavior)
|
||||
) {
|
||||
@ -747,7 +749,6 @@ export function ChatInput({ variant = 'default', compact = false }: ChatInputPro
|
||||
return
|
||||
}
|
||||
event.preventDefault()
|
||||
const selected = filteredCommands[slashSelectedIndex]
|
||||
if (selected) selectSlashCommand(selected.name)
|
||||
return
|
||||
}
|
||||
|
||||
@ -353,6 +353,43 @@ describe('EmptySession', () => {
|
||||
expect(input).toHaveValue('/agent debugger ')
|
||||
})
|
||||
|
||||
it('selects a highlighted agent entry from /agent without creating a session', async () => {
|
||||
useSettingsStore.setState({
|
||||
chatSendBehavior: 'enter',
|
||||
})
|
||||
mocks.listAgents.mockResolvedValue({
|
||||
activeAgents: [
|
||||
{
|
||||
agentType: 'debugger',
|
||||
description: 'Debug failures',
|
||||
modelDisplay: 'OPUS',
|
||||
source: 'userSettings',
|
||||
isActive: true,
|
||||
},
|
||||
],
|
||||
allAgents: [],
|
||||
})
|
||||
|
||||
render(<EmptySession />)
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mocks.listAgents).toHaveBeenCalledWith(undefined)
|
||||
})
|
||||
|
||||
const input = screen.getByRole('textbox') as HTMLTextAreaElement
|
||||
fireEvent.change(input, {
|
||||
target: { value: '/agent', selectionStart: 6 },
|
||||
})
|
||||
|
||||
await screen.findByText('/agent debugger')
|
||||
fireEvent.keyDown(input, { key: 'ArrowDown' })
|
||||
fireEvent.keyDown(input, { key: 'Enter' })
|
||||
|
||||
expect(input).toHaveValue('/agent debugger ')
|
||||
expect(mocks.createSession).not.toHaveBeenCalled()
|
||||
expect(mocks.wsSend).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('integrates repository launch controls into the desktop composer panel', async () => {
|
||||
render(<EmptySession />)
|
||||
|
||||
|
||||
@ -415,9 +415,11 @@ export function EmptySession() {
|
||||
return
|
||||
}
|
||||
if (event.key === 'Enter' || event.key === 'Tab') {
|
||||
const selected = filteredCommands[slashSelectedIndex]
|
||||
if (
|
||||
event.key === 'Enter' &&
|
||||
exactSlashCommand &&
|
||||
selected?.name.toLowerCase() === exactSlashCommand.name.toLowerCase() &&
|
||||
slashFilter.trim().toLowerCase() === exactSlashCommand.name.toLowerCase() &&
|
||||
shouldSubmitOnEnter(event, chatSendBehavior)
|
||||
) {
|
||||
@ -426,7 +428,6 @@ export function EmptySession() {
|
||||
return
|
||||
}
|
||||
event.preventDefault()
|
||||
const selected = filteredCommands[slashSelectedIndex]
|
||||
if (selected) selectSlashCommand(selected.name)
|
||||
return
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user