@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 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miphamai/cli",
3
- "version": "0.24.9",
3
+ "version": "0.24.11",
4
4
  "description": "Mipham Code — Multi-model open-core intelligent coding terminal by MiphamAI",
5
5
  "keywords": [
6
6
  "ai",
@@ -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+S — toggle group by (status ↔ directory)
100
- if (input === '\x13') {
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) return
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) return
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) return
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+S group · Ctrl+R rename · Esc back
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 &quot;run this in background&quot; 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
  }