diff --git a/apps/buddy/src/modules/prompt-input/model/chatComposerInput.ts b/apps/buddy/src/modules/prompt-input/model/chatComposerInput.ts index 624cec2f..690edcd0 100644 --- a/apps/buddy/src/modules/prompt-input/model/chatComposerInput.ts +++ b/apps/buddy/src/modules/prompt-input/model/chatComposerInput.ts @@ -78,7 +78,10 @@ export function serializeChatComposerContent(content: JSONContent): ChatComposer } export function findChatComposerTrigger(textBeforeCursor: string): ChatComposerTrigger | null { - const candidateSlashIndex = findTriggerStart(textBeforeCursor, '/') + const candidateSlashIndex = Math.max( + findTriggerStart(textBeforeCursor, '/'), + findTriggerStart(textBeforeCursor, '、'), + ) const slashIndex = candidateSlashIndex >= 0 && textBeforeCursor.slice(0, candidateSlashIndex).trim().length === 0 ? candidateSlashIndex @@ -103,7 +106,7 @@ export function findChatComposerTrigger(textBeforeCursor: string): ChatComposerT if (/\s/u.test(query)) return null return { - kind: trigger === '/' ? 'slash' : trigger === '$' ? 'skill' : 'mention', + kind: trigger === '/' || trigger === '、' ? 'slash' : trigger === '$' ? 'skill' : 'mention', query, } } @@ -148,7 +151,7 @@ export function shouldSubmitChatComposerKey( && !event.metaKey } -function findTriggerStart(value: string, trigger: '/' | '$' | '@'): number { +function findTriggerStart(value: string, trigger: '/' | '、' | '$' | '@'): number { const index = value.lastIndexOf(trigger) if (index < 0 || (index > 0 && !TRIGGER_BOUNDARY_PATTERN.test(value[index - 1] ?? ''))) return -1 diff --git a/apps/buddy/src/modules/tasks/widgets/composer/__tests__/chatComposerEditing.spec.ts b/apps/buddy/src/modules/tasks/widgets/composer/__tests__/chatComposerEditing.spec.ts index 176de542..898ecbe6 100644 --- a/apps/buddy/src/modules/tasks/widgets/composer/__tests__/chatComposerEditing.spec.ts +++ b/apps/buddy/src/modules/tasks/widgets/composer/__tests__/chatComposerEditing.spec.ts @@ -128,6 +128,21 @@ async function mountComposer(options: { } describe('chat composer editing', () => { + it('opens slash command suggestions with the Chinese ideographic comma and replaces the trigger on selection', async () => { + const flow = await mountComposer() + flow.editor.view.dom.focus() + flow.editor.commands.insertContent('、rev') + + await expect.poll(() => flow.composer.activeTrigger.value).toEqual({ kind: 'slash', query: 'rev' }) + const review = flow.composer.suggestions.value.find(({ option }) => option.value === '/review')?.option + expect(review).toBeDefined() + flow.composer.selectSuggestion(review) + + const content = chatComposerDocumentToUserContent(flow.editor.getJSON()) + expect(content.body[0]?.content[0]).toMatchObject({ type: 'prompt_directive', directive: 'slash_command', commandMode: 'prompt', value: '/review' }) + expect(JSON.stringify(content)).not.toContain('、') + }) + it.each(['select', 'submit'] as const)('submits a run action with its arguments through %s', async (source) => { const flow = await mountComposer() const prefix = source === 'select' ? '/com' : '/compact'