feat: sync CLI status (verb, elapsed, tokens) to StreamingIndicator

- Store statusVerb from server 'status' WebSocket messages
- StreamingIndicator now shows the real CLI verb (Canoodling, Thinking, etc.)
  plus elapsed time and output token count
- Only show StreamingIndicator during tool_executing (not during thinking,
  where ThinkingBlock already provides feedback)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
程序员阿江(Relakkes) 2026-04-06 22:49:33 +08:00
parent 905d4216a5
commit 83559ce7be
2 changed files with 26 additions and 8 deletions

View File

@ -1,18 +1,32 @@
import { useChatStore } from '../../stores/chatStore'
export function StreamingIndicator() {
const { chatState } = useChatStore()
function formatElapsed(seconds: number): string {
if (seconds < 60) return `${seconds}s`
const m = Math.floor(seconds / 60)
const s = seconds % 60
return `${m}m ${s}s`
}
const verb = chatState === 'thinking'
? 'Thinking'
: chatState === 'tool_executing'
? 'Running'
: 'Working'
export function StreamingIndicator() {
const { chatState, statusVerb, elapsedSeconds, tokenUsage } = useChatStore()
const verb = statusVerb
|| (chatState === 'thinking' ? 'Thinking' : chatState === 'tool_executing' ? 'Running' : 'Working')
return (
<div className="mb-2 ml-10 flex w-fit items-center gap-2 rounded-full border border-[var(--color-border)]/40 bg-[var(--color-surface-container-low)] px-3 py-1">
<span className="text-[var(--color-brand)] animate-shimmer text-xs"></span>
<span className="text-xs font-medium text-[var(--color-text-secondary)]">{verb}...</span>
{elapsedSeconds > 0 && (
<span className="text-[10px] text-[var(--color-text-tertiary)]">
{formatElapsed(elapsedSeconds)}
</span>
)}
{tokenUsage.output_tokens > 0 && (
<span className="text-[10px] text-[var(--color-text-tertiary)]">
· {tokenUsage.output_tokens}
</span>
)}
</div>
)
}

View File

@ -25,6 +25,7 @@ type ChatStore = {
} | null
tokenUsage: TokenUsage
elapsedSeconds: number
statusVerb: string
connectedSessionId: string | null
slashCommands: Array<{ name: string; description: string }>
@ -56,6 +57,7 @@ export const useChatStore = create<ChatStore>((set, get) => ({
pendingPermission: null,
tokenUsage: { input_tokens: 0, output_tokens: 0 },
elapsedSeconds: 0,
statusVerb: '',
connectedSessionId: null,
slashCommands: [],
@ -190,7 +192,9 @@ export const useChatStore = create<ChatStore>((set, get) => ({
case 'status':
set({
chatState: msg.state,
...(msg.state === 'idle' ? { activeThinkingId: null } : {}),
...(msg.verb ? { statusVerb: msg.verb } : {}),
...(msg.tokens ? { tokenUsage: { ...get().tokenUsage, output_tokens: msg.tokens } } : {}),
...(msg.state === 'idle' ? { activeThinkingId: null, statusVerb: '' } : {}),
})
if (msg.state === 'idle' && elapsedTimer) {
clearInterval(elapsedTimer)