@miphamai/cli 0.24.9 → 0.24.11
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/bin/mipham.ts +21 -0
- package/package.json +1 -1
- package/src/agent-view/dashboard.tsx +48 -6
package/bin/mipham.ts
CHANGED
|
@@ -308,6 +308,27 @@ async function runUpdate(): Promise<boolean> {
|
|
|
308
308
|
}
|
|
309
309
|
|
|
310
310
|
async function main() {
|
|
311
|
+
// ── Disable terminal software flow control (XON/XOFF) ──────────────────
|
|
312
|
+
// Ctrl+S and Ctrl+Q are intercepted by the terminal for flow control by default.
|
|
313
|
+
// Disabling it lets our app receive these key combinations (e.g. Agent Dashboard).
|
|
314
|
+
const { execSync } = await import('node:child_process')
|
|
315
|
+
try {
|
|
316
|
+
execSync('stty -ixon 2>/dev/null || true', { stdio: 'ignore' })
|
|
317
|
+
} catch {
|
|
318
|
+
// Non-POSIX platform (Windows) — no flow control to disable
|
|
319
|
+
}
|
|
320
|
+
// Restore flow control on exit
|
|
321
|
+
const restoreFlowControl = () => {
|
|
322
|
+
try {
|
|
323
|
+
execSync('stty ixon 2>/dev/null || true', { stdio: 'ignore' })
|
|
324
|
+
} catch {
|
|
325
|
+
/* ignore */
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
process.on('exit', restoreFlowControl)
|
|
329
|
+
process.on('SIGINT', restoreFlowControl)
|
|
330
|
+
process.on('SIGTERM', restoreFlowControl)
|
|
331
|
+
|
|
311
332
|
// ── Read version fresh from package.json at startup (bypasses Bun module cache) ──
|
|
312
333
|
const { readFileSync } = await import('node:fs')
|
|
313
334
|
const { join } = await import('node:path')
|
package/package.json
CHANGED
|
@@ -31,6 +31,13 @@ export function AgentViewDashboard({ manager, onAttach, onExit }: DashboardProps
|
|
|
31
31
|
const [selectedIndex, setSelectedIndex] = useState(0)
|
|
32
32
|
const [peekingSessionId, setPeekingSessionId] = useState<string | null>(null)
|
|
33
33
|
const [_groupBy, setGroupBy] = useState<'status' | 'directory'>('status')
|
|
34
|
+
const [feedback, setFeedback] = useState<string | null>(null)
|
|
35
|
+
|
|
36
|
+
// Flash a brief feedback message that auto-clears
|
|
37
|
+
const showFeedback = useCallback((msg: string) => {
|
|
38
|
+
setFeedback(msg)
|
|
39
|
+
setTimeout(() => setFeedback(null), 1800)
|
|
40
|
+
}, [])
|
|
34
41
|
|
|
35
42
|
// Build a flat list of sessions in group order, with group headers
|
|
36
43
|
const flatList = useMemo(() => {
|
|
@@ -96,29 +103,42 @@ export function AgentViewDashboard({ manager, onAttach, onExit }: DashboardProps
|
|
|
96
103
|
return
|
|
97
104
|
}
|
|
98
105
|
|
|
99
|
-
// Ctrl+
|
|
100
|
-
if (input === '\
|
|
106
|
+
// Ctrl+T — toggle group by (status ↔ directory)
|
|
107
|
+
if (input === '\x14') {
|
|
101
108
|
setGroupBy((prev) => (prev === 'status' ? 'directory' : 'status'))
|
|
109
|
+
showFeedback(`Grouped by ${_groupBy === 'status' ? 'directory' : 'status'}`)
|
|
102
110
|
return
|
|
103
111
|
}
|
|
104
112
|
|
|
105
113
|
// Ctrl+R — rename selected session
|
|
106
114
|
if (input === '\x12') {
|
|
107
|
-
if (sessionsOnly.length === 0)
|
|
115
|
+
if (sessionsOnly.length === 0) {
|
|
116
|
+
showFeedback('No sessions to rename')
|
|
117
|
+
return
|
|
118
|
+
}
|
|
108
119
|
const current = sessionsOnly[selectedIndex]
|
|
109
120
|
if (!current) return
|
|
110
121
|
const newTitle = `session-${Date.now().toString(36)}`
|
|
111
122
|
manager.rename(current.session.id, newTitle)
|
|
123
|
+
showFeedback(`Renamed to ${newTitle}`)
|
|
112
124
|
return
|
|
113
125
|
}
|
|
114
126
|
|
|
115
127
|
if (input === 'j') {
|
|
128
|
+
if (sessionsOnly.length === 0) {
|
|
129
|
+
showFeedback('No sessions to navigate — spawn a background agent first')
|
|
130
|
+
return
|
|
131
|
+
}
|
|
116
132
|
setSelectedIndex((prev) => Math.min(prev + 1, sessionsOnly.length - 1))
|
|
117
133
|
setPeekingSessionId(null)
|
|
118
134
|
return
|
|
119
135
|
}
|
|
120
136
|
|
|
121
137
|
if (input === 'k') {
|
|
138
|
+
if (sessionsOnly.length === 0) {
|
|
139
|
+
showFeedback('No sessions to navigate — spawn a background agent first')
|
|
140
|
+
return
|
|
141
|
+
}
|
|
122
142
|
setSelectedIndex((prev) => Math.max(prev - 1, 0))
|
|
123
143
|
setPeekingSessionId(null)
|
|
124
144
|
return
|
|
@@ -126,7 +146,10 @@ export function AgentViewDashboard({ manager, onAttach, onExit }: DashboardProps
|
|
|
126
146
|
|
|
127
147
|
// Space — toggle peek
|
|
128
148
|
if (input === ' ') {
|
|
129
|
-
if (sessionsOnly.length === 0)
|
|
149
|
+
if (sessionsOnly.length === 0) {
|
|
150
|
+
showFeedback('No sessions to peek')
|
|
151
|
+
return
|
|
152
|
+
}
|
|
130
153
|
const current = sessionsOnly[selectedIndex]
|
|
131
154
|
if (!current) return
|
|
132
155
|
setPeekingSessionId(peekingSessionId === current.session.id ? null : current.session.id)
|
|
@@ -135,7 +158,10 @@ export function AgentViewDashboard({ manager, onAttach, onExit }: DashboardProps
|
|
|
135
158
|
|
|
136
159
|
// Enter — attach to selected session
|
|
137
160
|
if (key.return) {
|
|
138
|
-
if (sessionsOnly.length === 0)
|
|
161
|
+
if (sessionsOnly.length === 0) {
|
|
162
|
+
showFeedback('No sessions to attach — spawn a background agent first')
|
|
163
|
+
return
|
|
164
|
+
}
|
|
139
165
|
const current = sessionsOnly[selectedIndex]
|
|
140
166
|
if (!current) return
|
|
141
167
|
if (peekingSessionId) {
|
|
@@ -181,7 +207,7 @@ export function AgentViewDashboard({ manager, onAttach, onExit }: DashboardProps
|
|
|
181
207
|
</Box>
|
|
182
208
|
<Box>
|
|
183
209
|
<Text dimColor>
|
|
184
|
-
j/k navigate · Space peek · Enter attach · Ctrl+
|
|
210
|
+
j/k navigate · Space peek · Enter attach · Ctrl+T group · Ctrl+R rename · Esc back
|
|
185
211
|
</Text>
|
|
186
212
|
</Box>
|
|
187
213
|
</Box>
|
|
@@ -198,6 +224,13 @@ export function AgentViewDashboard({ manager, onAttach, onExit }: DashboardProps
|
|
|
198
224
|
<Text dimColor>
|
|
199
225
|
Use the Agent tool or type "run this in background" to spawn one.
|
|
200
226
|
</Text>
|
|
227
|
+
{feedback && (
|
|
228
|
+
<Box marginTop={1}>
|
|
229
|
+
<Text color="yellow" dimColor>
|
|
230
|
+
⚡ {feedback}
|
|
231
|
+
</Text>
|
|
232
|
+
</Box>
|
|
233
|
+
)}
|
|
201
234
|
</Box>
|
|
202
235
|
) : (
|
|
203
236
|
<Box flexDirection="column">
|
|
@@ -232,6 +265,15 @@ export function AgentViewDashboard({ manager, onAttach, onExit }: DashboardProps
|
|
|
232
265
|
{peekData && (
|
|
233
266
|
<SessionPeek session={peekData.session} recentMessages={peekData.recentMessages} />
|
|
234
267
|
)}
|
|
268
|
+
|
|
269
|
+
{/* Feedback toast — flashes briefly on action */}
|
|
270
|
+
{feedback && (
|
|
271
|
+
<Box marginTop={1}>
|
|
272
|
+
<Text color="yellow" dimColor>
|
|
273
|
+
⚡ {feedback}
|
|
274
|
+
</Text>
|
|
275
|
+
</Box>
|
|
276
|
+
)}
|
|
235
277
|
</Box>
|
|
236
278
|
)
|
|
237
279
|
}
|