@miphamai/cli 0.16.4 β†’ 0.16.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miphamai/cli",
3
- "version": "0.16.4",
3
+ "version": "0.16.5",
4
4
  "description": "Mipham Code β€” Multi-model open-core intelligent coding terminal by MiphamAI",
5
5
  "keywords": [
6
6
  "ai",
package/src/ui/app.tsx CHANGED
@@ -353,18 +353,10 @@ export function App({
353
353
 
354
354
  try {
355
355
  for await (const chunk of engine.process(input, controller.signal)) {
356
- // Show thinking indicator when model is reasoning (DeepSeek V4 thinking mode)
357
- if (chunk.reasoning_content && turnContent === '') {
358
- setMessages((prev) => {
359
- const updated = [...prev]
360
- const last = updated[updated.length - 1]
361
- if (last?.role === 'assistant' && last.content === '') {
362
- last.content = 'πŸ’­ 思考中…'
363
- } else if (!last || last.role !== 'assistant' || last.content !== 'πŸ’­ 思考中…') {
364
- updated.push({ role: 'assistant', content: 'πŸ’­ 思考中…' })
365
- }
366
- return updated
367
- })
356
+ // Reasoning content (DeepSeek V4 thinking mode) β€” silently consumed,
357
+ // not shown to user to avoid noise.
358
+ if (chunk.reasoning_content) {
359
+ continue
368
360
  }
369
361
 
370
362
  if (chunk.type === 'text' && chunk.content) {
@@ -372,17 +364,10 @@ export function App({
372
364
  if (isNewTurn) {
373
365
  turnContent = chunk.content
374
366
  isNewTurn = false
375
- setMessages((prev) => {
376
- const updated = [...prev]
377
- const last = updated[updated.length - 1]
378
- // Replace "thinking" placeholder with real content
379
- if (last?.role === 'assistant' && last.content === 'πŸ’­ 思考中…') {
380
- last.content = turnContent
381
- } else {
382
- updated.push({ role: 'assistant', content: turnContent })
383
- }
384
- return updated
385
- })
367
+ setMessages((prev) => [
368
+ ...prev,
369
+ { role: 'assistant', content: turnContent },
370
+ ])
386
371
  } else {
387
372
  turnContent += chunk.content
388
373
  setMessages((prev) => {
@@ -430,9 +415,10 @@ export function App({
430
415
  setAgentProgress(null)
431
416
  // Sync background agents (e.g. Agent tool may have spawned them)
432
417
  syncBgAgents()
433
- // Show tool result as a compact indented line
418
+ // Only show tool results with meaningful content.
419
+ // Skip empty results, "(no matches)", and other noise.
434
420
  const output = chunk.content ? String(chunk.content).trim() : ''
435
- if (output) {
421
+ if (output && output !== '(no matches)' && output.length > 20) {
436
422
  const firstLine = output.split('\n')[0]!.slice(0, 200)
437
423
  const preview = firstLine.length < output.length ? `${firstLine}...` : firstLine
438
424
  setMessages((prev) => [
package/src/ui/chat.tsx CHANGED
@@ -93,8 +93,11 @@ const MessageRow = React.memo(
93
93
  )
94
94
 
95
95
  export function ChatPanel({ messages, focusMode }: ChatPanelProps) {
96
- // In focus mode, compact tool activity into summary lines
97
- const displayMessages = focusMode ? compactForFocus(messages) : messages
96
+ // Group consecutive tool calls into compact summaries to reduce visual noise.
97
+ // In focus mode, use the more aggressive compactForFocus.
98
+ const displayMessages = focusMode
99
+ ? compactForFocus(messages)
100
+ : compactToolGroups(messages)
98
101
 
99
102
  return (
100
103
  <Box flexDirection="column" marginY={1} flexGrow={1}>
@@ -141,6 +144,56 @@ export function ChatPanel({ messages, focusMode }: ChatPanelProps) {
141
144
  )
142
145
  }
143
146
 
147
+ /**
148
+ * Group consecutive tool calls into compact one-liners for the normal view.
149
+ * Single tools show normally; 2+ consecutive tools get folded:
150
+ * ⏺ Read · Glob · Bash (3 tools)
151
+ */
152
+ function compactToolGroups(messages: ChatMessage[]): ChatMessage[] {
153
+ const result: ChatMessage[] = []
154
+ let toolGroup: ChatMessage[] = []
155
+
156
+ const flush = () => {
157
+ if (toolGroup.length === 0) return
158
+ if (toolGroup.length === 1) {
159
+ result.push(toolGroup[0]!)
160
+ } else {
161
+ const names = toolGroup
162
+ .filter((t) => t.toolMeta?.name && !t.toolMeta.name.startsWith('tools ('))
163
+ .map((t) => t.toolMeta!.name)
164
+ const uniqueNames = [...new Set(names)]
165
+ result.push({
166
+ role: 'system',
167
+ content: `⏺ ${uniqueNames.join(' · ')} (${names.length} tools)`,
168
+ toolMeta: {
169
+ name: `tools (${names.length})`,
170
+ input: uniqueNames.join(', '),
171
+ collapsed: true,
172
+ },
173
+ })
174
+ }
175
+ toolGroup = []
176
+ }
177
+
178
+ for (const msg of messages) {
179
+ // Tool results (no name, has output) get folded into the preceding tool group
180
+ if (msg.toolMeta && !msg.toolMeta.name && msg.toolMeta.output) {
181
+ toolGroup.push(msg)
182
+ continue
183
+ }
184
+ // Tool calls with a name
185
+ if (msg.toolMeta?.name && !msg.toolMeta.name.startsWith('tools (')) {
186
+ toolGroup.push(msg)
187
+ continue
188
+ }
189
+ // Already-grouped or non-tool message
190
+ flush()
191
+ result.push(msg)
192
+ }
193
+ flush()
194
+ return result
195
+ }
196
+
144
197
  /**
145
198
  * Compact messages for focus view:
146
199
  * - Groups consecutive tool calls into [β–Ά N tools] ↳ name1 ↳ name2 summary lines