@miphamai/cli 0.32.2 → 0.32.4
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 +1 -1
- package/src/ui/agent-footer.tsx +37 -10
- package/src/ui/app.tsx +46 -29
- package/src/ui/chat.tsx +9 -11
package/package.json
CHANGED
package/src/ui/agent-footer.tsx
CHANGED
|
@@ -48,11 +48,25 @@ function formatTokens(n: number): string {
|
|
|
48
48
|
/** Map tool name to Ink color for the [Tool ...] indicator. */
|
|
49
49
|
function toolIndicatorColor(name: string): string {
|
|
50
50
|
switch (name) {
|
|
51
|
-
case 'Bash':
|
|
52
|
-
case '
|
|
53
|
-
case '
|
|
54
|
-
case '
|
|
55
|
-
|
|
51
|
+
case 'Bash':
|
|
52
|
+
case 'Read':
|
|
53
|
+
case 'Glob':
|
|
54
|
+
case 'Grep':
|
|
55
|
+
return 'white'
|
|
56
|
+
case 'Write':
|
|
57
|
+
case 'Edit':
|
|
58
|
+
case 'Update':
|
|
59
|
+
return 'red'
|
|
60
|
+
case 'Agent':
|
|
61
|
+
case 'Task':
|
|
62
|
+
case 'Skill':
|
|
63
|
+
case 'Workflow':
|
|
64
|
+
return 'magenta'
|
|
65
|
+
case 'WebSearch':
|
|
66
|
+
case 'WebFetch':
|
|
67
|
+
return 'blue'
|
|
68
|
+
default:
|
|
69
|
+
return 'white'
|
|
56
70
|
}
|
|
57
71
|
}
|
|
58
72
|
|
|
@@ -64,10 +78,22 @@ function animatedDots(tick: number): string {
|
|
|
64
78
|
|
|
65
79
|
/** Gerund verbs for agent progress — rotated every 2 seconds for visual liveliness. */
|
|
66
80
|
const GERUNDS = [
|
|
67
|
-
'Pondering',
|
|
68
|
-
'
|
|
69
|
-
'
|
|
70
|
-
'
|
|
81
|
+
'Pondering',
|
|
82
|
+
'Contemplating',
|
|
83
|
+
'Cerebrating',
|
|
84
|
+
'Ruminating',
|
|
85
|
+
'Deliberating',
|
|
86
|
+
'Cogitating',
|
|
87
|
+
'Perambulating',
|
|
88
|
+
'Computing',
|
|
89
|
+
'Processing',
|
|
90
|
+
'Analyzing',
|
|
91
|
+
'Synthesizing',
|
|
92
|
+
'Orchestrating',
|
|
93
|
+
'Forging',
|
|
94
|
+
'Illuminating',
|
|
95
|
+
'Manifesting',
|
|
96
|
+
'Transmogrifying',
|
|
71
97
|
]
|
|
72
98
|
|
|
73
99
|
/** Pick a gerund that changes every 2 seconds (driven by tick). */
|
|
@@ -89,7 +115,8 @@ export function AgentFooter({ agents, tick, activeTool, agentProgress }: AgentFo
|
|
|
89
115
|
{hasTool && (
|
|
90
116
|
<Box>
|
|
91
117
|
<Text color={toolIndicatorColor(activeTool!.name)}>
|
|
92
|
-
{' '}[{activeTool!.name} {activeTool!.detail.slice(0, 60)}
|
|
118
|
+
{' '}[{activeTool!.name} {activeTool!.detail.slice(0, 60)}
|
|
119
|
+
{animatedDots(tick)}]
|
|
93
120
|
</Text>
|
|
94
121
|
</Box>
|
|
95
122
|
)}
|
package/src/ui/app.tsx
CHANGED
|
@@ -185,11 +185,17 @@ export function App({
|
|
|
185
185
|
const [agentTick, setAgentTick] = useState(0)
|
|
186
186
|
/** Active foreground tool indicator: [Bash command...], [Update file.ts...], etc. */
|
|
187
187
|
const [activeTool, setActiveTool] = useState<{ name: string; detail: string } | null>(null)
|
|
188
|
+
// Refs for immediate state (bypasses React batching so footer renders between rapid chunks)
|
|
189
|
+
const activeToolRef = useRef<{ name: string; detail: string } | null>(null)
|
|
190
|
+
const agentProgressRef = useRef<AgentProgress | null>(null)
|
|
188
191
|
|
|
189
|
-
// Tick timer for agent elapsed displays (re-renders every second while agents are running)
|
|
192
|
+
// Tick timer for agent elapsed displays (re-renders every second while agents are running).
|
|
193
|
+
// Uses refs so the timer doesn't stop between state batches.
|
|
190
194
|
useEffect(() => {
|
|
191
195
|
const hasRunning =
|
|
192
|
-
Object.values(runningAgents).some((a) => a.status === 'running') ||
|
|
196
|
+
Object.values(runningAgents).some((a) => a.status === 'running') ||
|
|
197
|
+
agentProgressRef.current !== null ||
|
|
198
|
+
activeToolRef.current !== null
|
|
193
199
|
if (!hasRunning) return
|
|
194
200
|
const i = setInterval(() => setAgentTick((t) => t + 1), 1000)
|
|
195
201
|
return () => clearInterval(i)
|
|
@@ -436,6 +442,18 @@ export function App({
|
|
|
436
442
|
setMessages((prev) => [...prev, { role: 'user', content: input }])
|
|
437
443
|
setIsLoading(true)
|
|
438
444
|
|
|
445
|
+
// Start agent progress indicator immediately for ALL processing
|
|
446
|
+
const progressStart = Date.now()
|
|
447
|
+
const progress: AgentProgress = {
|
|
448
|
+
name: '',
|
|
449
|
+
description: '',
|
|
450
|
+
startTime: progressStart,
|
|
451
|
+
tokensUsed: 0,
|
|
452
|
+
}
|
|
453
|
+
agentProgressRef.current = progress
|
|
454
|
+
setAgentProgress(progress)
|
|
455
|
+
setAgentTick((t) => t + 1)
|
|
456
|
+
|
|
439
457
|
const controller = new AbortController()
|
|
440
458
|
abortRef.current = controller
|
|
441
459
|
|
|
@@ -509,18 +527,24 @@ export function App({
|
|
|
509
527
|
const isAgent = toolName === 'Agent' || toolName === 'Task'
|
|
510
528
|
const detail = formatToolDetail(toolName, chunk.toolUse.input)
|
|
511
529
|
|
|
512
|
-
// Show [ToolName detail...] activity indicator for ALL tools
|
|
513
|
-
|
|
530
|
+
// Show [ToolName detail...] activity indicator for ALL tools (via ref for immediate render)
|
|
531
|
+
const toolEntry = { name: toolDisplayName(toolName), detail }
|
|
532
|
+
activeToolRef.current = toolEntry
|
|
533
|
+
setActiveTool(toolEntry)
|
|
534
|
+
setAgentTick((t) => t + 1)
|
|
514
535
|
|
|
515
536
|
if (isAgent) {
|
|
516
|
-
|
|
537
|
+
const ap: AgentProgress = {
|
|
517
538
|
name: detail || (chunk.toolUse.input.subagent_type as string) || 'General-purpose',
|
|
518
539
|
description:
|
|
519
540
|
(chunk.toolUse.input.description as string) ||
|
|
520
541
|
(chunk.toolUse.input.prompt as string) ||
|
|
521
542
|
'',
|
|
522
543
|
startTime: Date.now(),
|
|
523
|
-
}
|
|
544
|
+
}
|
|
545
|
+
agentProgressRef.current = ap
|
|
546
|
+
setAgentProgress(ap)
|
|
547
|
+
setAgentTick((t) => t + 1)
|
|
524
548
|
}
|
|
525
549
|
|
|
526
550
|
// Show tool call as a visible, collapsed message
|
|
@@ -544,8 +568,10 @@ export function App({
|
|
|
544
568
|
}
|
|
545
569
|
|
|
546
570
|
if (chunk.type === 'tool_result') {
|
|
547
|
-
|
|
571
|
+
// Clear tool indicator but keep agent progress (AI is still processing)
|
|
572
|
+
activeToolRef.current = null
|
|
548
573
|
setActiveTool(null)
|
|
574
|
+
setAgentTick((t) => t + 1)
|
|
549
575
|
// Sync background agents (e.g. Agent tool may have spawned them)
|
|
550
576
|
syncBgAgents()
|
|
551
577
|
const output = chunk.content ? String(chunk.content).trim() : ''
|
|
@@ -582,12 +608,14 @@ export function App({
|
|
|
582
608
|
}
|
|
583
609
|
}
|
|
584
610
|
|
|
585
|
-
if (chunk.type === 'usage'
|
|
611
|
+
if (chunk.type === 'usage') {
|
|
586
612
|
const totalTokens = (chunk.inputTokens || 0) + (chunk.outputTokens || 0)
|
|
587
|
-
if (totalTokens > 0) {
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
613
|
+
if (totalTokens > 0 && agentProgressRef.current) {
|
|
614
|
+
agentProgressRef.current = {
|
|
615
|
+
...agentProgressRef.current,
|
|
616
|
+
tokensUsed: (agentProgressRef.current.tokensUsed || 0) + totalTokens,
|
|
617
|
+
}
|
|
618
|
+
setAgentProgress({ ...agentProgressRef.current })
|
|
591
619
|
}
|
|
592
620
|
}
|
|
593
621
|
|
|
@@ -631,6 +659,12 @@ export function App({
|
|
|
631
659
|
flushStreamBuffer()
|
|
632
660
|
setIsLoading(false)
|
|
633
661
|
abortRef.current = null
|
|
662
|
+
// Clear all progress/tool indicators
|
|
663
|
+
agentProgressRef.current = null
|
|
664
|
+
setAgentProgress(null)
|
|
665
|
+
activeToolRef.current = null
|
|
666
|
+
setActiveTool(null)
|
|
667
|
+
setAgentTick((t) => t + 1)
|
|
634
668
|
// Auto-save checkpoint after each AI response
|
|
635
669
|
if (assistantContent) {
|
|
636
670
|
engine.getContext().saveCheckpoint('post-turn')
|
|
@@ -671,14 +705,6 @@ export function App({
|
|
|
671
705
|
if (apiKeyPrompt) {
|
|
672
706
|
return (
|
|
673
707
|
<Box flexDirection="column" padding={1} height="100%">
|
|
674
|
-
{/* Header */}
|
|
675
|
-
<Box flexDirection="column" marginBottom={1}>
|
|
676
|
-
<Text color="#FFD700" bold>
|
|
677
|
-
Mipham Code
|
|
678
|
-
</Text>
|
|
679
|
-
<Text dimColor>v{version || '0.0.0'}</Text>
|
|
680
|
-
</Box>
|
|
681
|
-
|
|
682
708
|
{/* Chat panel — show existing messages */}
|
|
683
709
|
<ChatPanel messages={messages} focusMode={false} />
|
|
684
710
|
|
|
@@ -718,15 +744,6 @@ export function App({
|
|
|
718
744
|
|
|
719
745
|
return (
|
|
720
746
|
<Box flexDirection="column" padding={1} height="100%">
|
|
721
|
-
{/* Header — left-aligned */}
|
|
722
|
-
<Box flexDirection="column" marginBottom={1}>
|
|
723
|
-
<Text color="#FFD700" bold>
|
|
724
|
-
Mipham Code
|
|
725
|
-
</Text>
|
|
726
|
-
<Text dimColor>v{version || '0.0.0'}</Text>
|
|
727
|
-
<Text dimColor>{modelId}</Text>
|
|
728
|
-
</Box>
|
|
729
|
-
|
|
730
747
|
{/* Workflow progress — auto-detects active workflows, renders nothing when idle */}
|
|
731
748
|
<WorkflowProgress />
|
|
732
749
|
|
package/src/ui/chat.tsx
CHANGED
|
@@ -79,17 +79,15 @@ const MessageRow = React.memo(
|
|
|
79
79
|
</Box>
|
|
80
80
|
) : (
|
|
81
81
|
<>
|
|
82
|
-
|
|
83
|
-
bold
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
:
|
|
92
|
-
</Text>
|
|
82
|
+
{msg.role === 'user' ? (
|
|
83
|
+
<Text bold color="green">
|
|
84
|
+
▸ {displayCwd()}:
|
|
85
|
+
</Text>
|
|
86
|
+
) : msg.role === 'system' ? (
|
|
87
|
+
<Text bold color="yellow">
|
|
88
|
+
⚠ {t('ui.system.role_label')}:
|
|
89
|
+
</Text>
|
|
90
|
+
) : null}
|
|
93
91
|
<Text>{msg.content}</Text>
|
|
94
92
|
</>
|
|
95
93
|
)}
|