@miphamai/cli 0.24.8 → 0.24.9
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/i18n-core/locales/en-US.json +1 -1
- package/src/i18n-core/locales/zh-CN.json +1 -1
- package/src/index.tsx +1 -0
- package/src/ui/app.tsx +106 -85
- package/src/ui/input.tsx +9 -0
- package/dist/mipham +0 -0
package/package.json
CHANGED
package/src/index.tsx
CHANGED
package/src/ui/app.tsx
CHANGED
|
@@ -12,6 +12,8 @@ import { ChatPanel } from './chat'
|
|
|
12
12
|
import { InputBar } from './input'
|
|
13
13
|
import { ModelPicker } from './picker'
|
|
14
14
|
import { AgentFooter, type AgentEntry } from './agent-footer'
|
|
15
|
+
import { AgentViewDashboard } from '../agent-view/dashboard'
|
|
16
|
+
import type { AgentViewManager } from '../agent-view/agent-view-manager'
|
|
15
17
|
import { WorkflowProgress } from './workflow-progress.js'
|
|
16
18
|
import {
|
|
17
19
|
getCommand,
|
|
@@ -33,6 +35,7 @@ interface AppProps {
|
|
|
33
35
|
pluginManager?: PluginManager
|
|
34
36
|
version?: string
|
|
35
37
|
sessionId?: string
|
|
38
|
+
agentViewManager?: AgentViewManager
|
|
36
39
|
}
|
|
37
40
|
|
|
38
41
|
export interface ToolMeta {
|
|
@@ -121,6 +124,7 @@ export function App({
|
|
|
121
124
|
pluginManager,
|
|
122
125
|
version,
|
|
123
126
|
sessionId,
|
|
127
|
+
agentViewManager,
|
|
124
128
|
}: AppProps) {
|
|
125
129
|
const { t } = useI18n()
|
|
126
130
|
const PERMISSION_LABELS = useMemo<Record<PermissionMode, string>>(
|
|
@@ -139,6 +143,7 @@ export function App({
|
|
|
139
143
|
const [providerId, setProviderId] = useState(initialProvider || config.defaultProvider)
|
|
140
144
|
const [modelId, setModelId] = useState(initialModel || config.defaultModel)
|
|
141
145
|
const [pickerOpen, setPickerOpen] = useState(false)
|
|
146
|
+
const [agentViewOpen, setAgentViewOpen] = useState(false)
|
|
142
147
|
const [_sessionTitle, setSessionTitle] = useState('')
|
|
143
148
|
const [_fastMode, setFastMode] = useState(false)
|
|
144
149
|
const [_effort, setEffort] = useState('high')
|
|
@@ -580,99 +585,115 @@ export function App({
|
|
|
580
585
|
{/* Workflow progress — auto-detects active workflows, renders nothing when idle */}
|
|
581
586
|
<WorkflowProgress />
|
|
582
587
|
|
|
583
|
-
{/*
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
config={config}
|
|
590
|
-
currentProvider={providerId}
|
|
591
|
-
currentModel={modelId}
|
|
592
|
-
onSelect={(newProvider, newModel) => {
|
|
593
|
-
engine.switchProvider(newProvider, newModel)
|
|
594
|
-
setProviderId(newProvider)
|
|
595
|
-
setModelId(newModel)
|
|
596
|
-
setPickerOpen(false)
|
|
597
|
-
setMessages((prev) => [
|
|
598
|
-
...prev,
|
|
599
|
-
{ role: 'system', content: `✓ Switched to ${newProvider}/${newModel}` },
|
|
600
|
-
])
|
|
601
|
-
}}
|
|
602
|
-
onClose={() => setPickerOpen(false)}
|
|
588
|
+
{/* Agent View Dashboard — Ctrl+G overlay (replaces chat + input) */}
|
|
589
|
+
{agentViewOpen && agentViewManager ? (
|
|
590
|
+
<AgentViewDashboard
|
|
591
|
+
manager={agentViewManager}
|
|
592
|
+
onAttach={() => {}}
|
|
593
|
+
onExit={() => setAgentViewOpen(false)}
|
|
603
594
|
/>
|
|
604
595
|
) : (
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
<
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
596
|
+
<>
|
|
597
|
+
{/* Chat panel */}
|
|
598
|
+
<ChatPanel messages={messages} focusMode={focusMode} />
|
|
599
|
+
|
|
600
|
+
{/* Input with separator lines */}
|
|
601
|
+
{pickerOpen ? (
|
|
602
|
+
<ModelPicker
|
|
603
|
+
config={config}
|
|
604
|
+
currentProvider={providerId}
|
|
605
|
+
currentModel={modelId}
|
|
606
|
+
onSelect={(newProvider, newModel) => {
|
|
607
|
+
engine.switchProvider(newProvider, newModel)
|
|
608
|
+
setProviderId(newProvider)
|
|
609
|
+
setModelId(newModel)
|
|
610
|
+
setPickerOpen(false)
|
|
611
|
+
setMessages((prev) => [
|
|
612
|
+
...prev,
|
|
613
|
+
{ role: 'system', content: `✓ Switched to ${newProvider}/${newModel}` },
|
|
614
|
+
])
|
|
615
|
+
}}
|
|
616
|
+
onClose={() => setPickerOpen(false)}
|
|
617
|
+
/>
|
|
618
|
+
) : (
|
|
619
|
+
/* Input bar (hidden when picker is open) */
|
|
620
|
+
<Box flexDirection="column">
|
|
621
|
+
<Text dimColor>──────────────────────────────</Text>
|
|
622
|
+
<InputBar
|
|
623
|
+
onSubmit={handleSubmit}
|
|
624
|
+
isLoading={isLoading}
|
|
625
|
+
onTogglePicker={() => setPickerOpen((prev) => !prev)}
|
|
626
|
+
onToggleFocus={() => setFocusMode((prev) => !prev)}
|
|
627
|
+
onToggleExpand={() => {
|
|
628
|
+
setMessages((prev) => {
|
|
629
|
+
const msgs = [...prev]
|
|
630
|
+
for (let i = msgs.length - 1; i >= 0; i--) {
|
|
631
|
+
if (msgs[i]?.toolMeta) {
|
|
632
|
+
const meta = msgs[i]!.toolMeta!
|
|
633
|
+
if (meta.collapsed) {
|
|
634
|
+
msgs[i] = {
|
|
635
|
+
...msgs[i]!,
|
|
636
|
+
content: `🔧 ${meta.name}: ${meta.input}\n📋 Result: ${meta.output || '(pending)'}`,
|
|
637
|
+
toolMeta: { ...meta, collapsed: false },
|
|
638
|
+
}
|
|
639
|
+
} else {
|
|
640
|
+
const short =
|
|
641
|
+
meta.input.length > 50 ? meta.input.slice(0, 50) + '...' : meta.input
|
|
642
|
+
msgs[i] = {
|
|
643
|
+
...msgs[i]!,
|
|
644
|
+
content: `⏺ ${meta.name} · ${short} (Ctrl+O to expand)`,
|
|
645
|
+
toolMeta: { ...meta, collapsed: true },
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
break
|
|
632
649
|
}
|
|
633
650
|
}
|
|
634
|
-
|
|
651
|
+
return msgs
|
|
652
|
+
})
|
|
653
|
+
}}
|
|
654
|
+
onCyclePermission={() => {
|
|
655
|
+
setPermissionMode((prev) => {
|
|
656
|
+
const idx = PERMISSION_MODES.indexOf(prev)
|
|
657
|
+
const next = PERMISSION_MODES[(idx + 1) % PERMISSION_MODES.length]!
|
|
658
|
+
engine.getPermission().setMode(next)
|
|
659
|
+
return next
|
|
660
|
+
})
|
|
661
|
+
}}
|
|
662
|
+
onCancel={() => {
|
|
663
|
+
if (abortRef.current) {
|
|
664
|
+
abortRef.current.abort()
|
|
635
665
|
}
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
}
|
|
648
|
-
onCancel={() => {
|
|
649
|
-
if (abortRef.current) {
|
|
650
|
-
abortRef.current.abort()
|
|
651
|
-
}
|
|
652
|
-
}}
|
|
666
|
+
}}
|
|
667
|
+
onToggleAgentView={() => setAgentViewOpen((prev) => !prev)}
|
|
668
|
+
/>
|
|
669
|
+
<Text dimColor>──────────────────────────────</Text>
|
|
670
|
+
</Box>
|
|
671
|
+
)}
|
|
672
|
+
|
|
673
|
+
{/* Agent status footer — shows running background agents */}
|
|
674
|
+
<AgentFooter
|
|
675
|
+
agents={Object.values(runningAgents)}
|
|
676
|
+
gitBranch={gitBranch}
|
|
677
|
+
tick={agentTick}
|
|
653
678
|
/>
|
|
654
|
-
<Text dimColor>──────────────────────────────</Text>
|
|
655
|
-
</Box>
|
|
656
|
-
)}
|
|
657
679
|
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
<
|
|
680
|
+
{/* Status line — Claude Code style */}
|
|
681
|
+
<Box marginTop={1} flexDirection="column">
|
|
682
|
+
{goalText && (
|
|
683
|
+
<Box>
|
|
684
|
+
<Text color="green">🎯 Goal: {goalText}</Text>
|
|
685
|
+
</Box>
|
|
686
|
+
)}
|
|
687
|
+
<Box flexDirection="row">
|
|
688
|
+
<Text color={PERMISSION_COLORS[permissionMode]}>
|
|
689
|
+
⏵⏵ {PERMISSION_LABELS[permissionMode]} ({t('ui.status.shift_tab_cycle')})
|
|
690
|
+
</Text>
|
|
691
|
+
<Text dimColor> · {t('ui.status.esc_to_interrupt')}</Text>
|
|
692
|
+
<Text dimColor> · {t('ui.status.left_for_agents')}</Text>
|
|
693
|
+
</Box>
|
|
666
694
|
</Box>
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
<Text color={PERMISSION_COLORS[permissionMode]}>
|
|
670
|
-
⏵⏵ {PERMISSION_LABELS[permissionMode]} ({t('ui.status.shift_tab_cycle')})
|
|
671
|
-
</Text>
|
|
672
|
-
<Text dimColor> · {t('ui.status.esc_to_interrupt')}</Text>
|
|
673
|
-
<Text dimColor> · {t('ui.status.left_for_agents')}</Text>
|
|
674
|
-
</Box>
|
|
675
|
-
</Box>
|
|
695
|
+
</>
|
|
696
|
+
)}
|
|
676
697
|
</Box>
|
|
677
698
|
)
|
|
678
699
|
}
|
package/src/ui/input.tsx
CHANGED
|
@@ -15,6 +15,8 @@ interface InputBarProps {
|
|
|
15
15
|
onToggleFocus?: () => void
|
|
16
16
|
/** Ctrl+O → expand last tool call */
|
|
17
17
|
onToggleExpand?: () => void
|
|
18
|
+
/** Ctrl+G → toggle agent view dashboard */
|
|
19
|
+
onToggleAgentView?: () => void
|
|
18
20
|
/** Shift+Tab → cycle permission mode */
|
|
19
21
|
onCyclePermission?: () => void
|
|
20
22
|
/** Escape → cancel loading (when input is empty) */
|
|
@@ -71,6 +73,7 @@ export function InputBar({
|
|
|
71
73
|
onTogglePicker,
|
|
72
74
|
onToggleFocus,
|
|
73
75
|
onToggleExpand,
|
|
76
|
+
onToggleAgentView,
|
|
74
77
|
onCyclePermission,
|
|
75
78
|
onCancel,
|
|
76
79
|
}: InputBarProps) {
|
|
@@ -185,6 +188,12 @@ export function InputBar({
|
|
|
185
188
|
onToggleExpand?.()
|
|
186
189
|
return
|
|
187
190
|
}
|
|
191
|
+
// Ctrl+G → toggle agent view dashboard
|
|
192
|
+
if (key.ctrl && input === 'g') {
|
|
193
|
+
setValue(valueBeforeShortcut.current)
|
|
194
|
+
onToggleAgentView?.()
|
|
195
|
+
return
|
|
196
|
+
}
|
|
188
197
|
|
|
189
198
|
if (vimEngine.current.mode !== 'normal') return
|
|
190
199
|
|
package/dist/mipham
DELETED
|
Binary file
|