import { describe, expect, it } from 'vitest' import { summarizeClaudeStreamLine } from './claudeProgress' function assistantLine(content: unknown[]): string { return JSON.stringify({ type: 'assistant', message: { role: 'assistant', content } }) } describe('summarizeClaudeStreamLine', () => { it('工具 Bash 有 description 时优先用 description', () => { const line = assistantLine([ { type: 'tool_use', name: 'Bash', input: { command: 'pnpm test', description: '跑全量测试' } }, ]) expect(summarizeClaudeStreamLine(line)).toEqual(['执行命令:跑全量测试']) }) it('工具 Bash 没 description 时回退到 command,超长截断', () => { const command = 'x'.repeat(80) const line = assistantLine([{ type: 'tool_use', name: 'Bash', input: { command } }]) expect(summarizeClaudeStreamLine(line)).toEqual([`执行命令:${'x'.repeat(60)}…`]) }) it('工具 Read 只显示文件名', () => { const line = assistantLine([{ type: 'tool_use', name: 'Read', input: { file_path: '/abs/dir/x.py' } }]) expect(summarizeClaudeStreamLine(line)).toEqual(['读取 x.py']) }) it('工具 Edit / Write / MultiEdit 显示为修改', () => { for (const name of ['Edit', 'Write', 'MultiEdit']) { const line = assistantLine([{ type: 'tool_use', name, input: { file_path: '/a/b/c.ts' } }]) expect(summarizeClaudeStreamLine(line)).toEqual(['修改 c.ts']) } }) it('工具 Grep / Glob 显示搜索模式', () => { const line = assistantLine([{ type: 'tool_use', name: 'Grep', input: { pattern: 'foo.*bar' } }]) expect(summarizeClaudeStreamLine(line)).toEqual(['搜索 foo.*bar']) }) it('未知工具显示调用 + 工具名', () => { const line = assistantLine([{ type: 'tool_use', name: 'TodoWrite', input: {} }]) expect(summarizeClaudeStreamLine(line)).toEqual(['调用 TodoWrite']) }) it('text 块取第一行并截断', () => { const line = assistantLine([{ type: 'text', text: `${'好'.repeat(70)}\n第二行` }]) expect(summarizeClaudeStreamLine(line)).toEqual([`${'好'.repeat(60)}…`]) }) it('空白 text 块忽略', () => { const line = assistantLine([{ type: 'text', text: ' \n\n' }]) expect(summarizeClaudeStreamLine(line)).toEqual([]) }) it('thinking 块忽略', () => { const line = assistantLine([{ type: 'thinking', thinking: '让我想想' }]) expect(summarizeClaudeStreamLine(line)).toEqual([]) }) it('system / user / result 行忽略', () => { expect(summarizeClaudeStreamLine(JSON.stringify({ type: 'system', subtype: 'init' }))).toEqual([]) expect(summarizeClaudeStreamLine(JSON.stringify({ type: 'user', message: { content: [{ type: 'tool_result', content: 'ok' }] }, }))).toEqual([]) expect(summarizeClaudeStreamLine(JSON.stringify({ type: 'result', result: 'done', session_id: 's' }))).toEqual([]) }) it('坏 JSON 返回空数组', () => { expect(summarizeClaudeStreamLine('{not json')).toEqual([]) expect(summarizeClaudeStreamLine('')).toEqual([]) expect(summarizeClaudeStreamLine('null')).toEqual([]) }) it('多个 block 按顺序输出', () => { const line = assistantLine([ { type: 'thinking', thinking: '...' }, { type: 'text', text: '先看看代码' }, { type: 'tool_use', name: 'Read', input: { file_path: '/p/a.ts' } }, { type: 'tool_use', name: 'Bash', input: { command: 'git status' } }, ]) expect(summarizeClaudeStreamLine(line)).toEqual(['先看看代码', '读取 a.ts', '执行命令:git status']) }) })