mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-17 13:13:35 +08:00
This folds together the desktop-side fixes needed before broader rollout. Session resume no longer deadlocks waiting on init, Mermaid and inline image output render inside chat, task and sub-agent state stay visible during execution, local build/release paths are safer, and Feishu/Telegram now expose lightweight mobile commands (/help, /status, /clear) without adding a new adapter-specific protocol. Constraint: Desktop releases must publish updater artifacts from non-draft GitHub releases Constraint: IM commands need short, phone-friendly responses and low operational complexity Rejected: Add a dedicated IM command API surface | re-used existing slash commands and session/task REST endpoints to keep adapters thin Rejected: Wait for task_update push events in WebUI | added low-risk polling because the current frontend ignores that event path Confidence: medium Scope-risk: broad Reversibility: clean Directive: Keep IM command replies terse and mobile-first, and merge local fallback slash commands when server-provided lists are partial Tested: cd desktop && bun x vitest run src/components/chat/MermaidRenderer.test.tsx src/components/markdown/MarkdownRenderer.test.tsx Tested: cd desktop && bun x vitest run src/components/chat/composerUtils.test.ts src/pages/ActiveSession.test.tsx src/stores/chatStore.test.ts Tested: cd desktop && bun run lint Tested: bun test src/server/__tests__/conversations.test.ts --test-name-pattern "SDK init arrives only after the first user turn" --timeout 60000 Tested: cd adapters && bun test common/ feishu/ telegram/ Tested: cd adapters && bunx tsc --noEmit Not-tested: Full GitHub Actions release run on all three desktop platforms Not-tested: Local DMG packaging end-to-end on Apple Silicon Not-tested: Real Feishu/Telegram device sessions against a live adapter process
56 lines
1.7 KiB
TypeScript
56 lines
1.7 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import {
|
|
findSlashToken,
|
|
insertSlashTrigger,
|
|
mergeSlashCommands,
|
|
replaceSlashCommand,
|
|
} from './composerUtils'
|
|
|
|
describe('composerUtils', () => {
|
|
it('finds slash token without trailing space', () => {
|
|
expect(findSlashToken('/rev', 4)).toEqual({ start: 0, filter: 'rev' })
|
|
expect(findSlashToken('hello /rev', 10)).toEqual({ start: 6, filter: 'rev' })
|
|
})
|
|
|
|
it('does not treat slash followed by a space as an active token', () => {
|
|
expect(findSlashToken('/ review', 8)).toBeNull()
|
|
})
|
|
|
|
it('inserts a slash trigger without appending a trailing space', () => {
|
|
expect(insertSlashTrigger('', 0)).toEqual({ value: '/', cursorPos: 1 })
|
|
expect(insertSlashTrigger('hello', 5)).toEqual({ value: 'hello /', cursorPos: 7 })
|
|
})
|
|
|
|
it('replaces the current slash token with a command and one trailing separator', () => {
|
|
expect(replaceSlashCommand('/rev', 4, 'review')).toEqual({
|
|
value: '/review ',
|
|
cursorPos: 8,
|
|
})
|
|
})
|
|
|
|
it('merges fallback commands so built-in entries like /clear remain visible', () => {
|
|
expect(
|
|
mergeSlashCommands([
|
|
{ name: 'help', description: '' },
|
|
]),
|
|
).toEqual(
|
|
expect.arrayContaining([
|
|
{ name: 'help', description: 'Show available commands' },
|
|
{ name: 'clear', description: 'Clear conversation history' },
|
|
]),
|
|
)
|
|
})
|
|
|
|
it('keeps server-provided descriptions when they exist', () => {
|
|
expect(
|
|
mergeSlashCommands([
|
|
{ name: 'clear', description: 'Server description' },
|
|
]),
|
|
).toEqual(
|
|
expect.arrayContaining([
|
|
{ name: 'clear', description: 'Server description' },
|
|
]),
|
|
)
|
|
})
|
|
})
|