@miphamai/cli 0.79.0 → 0.80.0
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 +5 -5
- package/src/shared/package-info.ts +1 -1
- package/src/ui/input.tsx +75 -33
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@miphamai/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.80.0",
|
|
4
4
|
"description": "Mipham Code — Multi-model open-core intelligent coding terminal by MiphamAI",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -43,17 +43,17 @@
|
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@larksuiteoapi/node-sdk": "^1.73.0",
|
|
45
45
|
"commander": "^13.1.0",
|
|
46
|
-
"ink": "^
|
|
46
|
+
"ink": "^7.1.1",
|
|
47
47
|
"ink-text-input": "^6.0.0",
|
|
48
|
-
"react": "^
|
|
49
|
-
"react-devtools-core": "^
|
|
48
|
+
"react": "^19.3.0",
|
|
49
|
+
"react-devtools-core": "^8.0.0",
|
|
50
50
|
"yaml": "^2.9.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@mipham/shared": "workspace:*",
|
|
54
54
|
"@types/bun": "^1.3.14",
|
|
55
55
|
"@types/node": "^22.19.19",
|
|
56
|
-
"@types/react": "^
|
|
56
|
+
"@types/react": "^19.3.0",
|
|
57
57
|
"ink-testing-library": "^4.0.0",
|
|
58
58
|
"vitest": "^4.1.7"
|
|
59
59
|
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
export const PACKAGE_NAME = '@miphamai/cli' as const
|
|
10
10
|
|
|
11
11
|
/** 当前发布版本 */
|
|
12
|
-
export const PACKAGE_VERSION = '0.
|
|
12
|
+
export const PACKAGE_VERSION = '0.80.0' as const
|
|
13
13
|
|
|
14
14
|
/** npm install 全局安装命令 */
|
|
15
15
|
export const NPM_INSTALL_COMMAND = `npm install -g ${PACKAGE_NAME}` as const
|
package/src/ui/input.tsx
CHANGED
|
@@ -130,6 +130,65 @@ export function applyEdit(state: EditState, action: EditAction): EditState {
|
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
+
/**
|
|
134
|
+
* Map an Ink key object + raw input to a cursor-editing action (null when the key
|
|
135
|
+
* isn't an edit). Extracted from the MiphamTextInput useInput handler so the macOS
|
|
136
|
+
* Backspace quirk is unit-testable.
|
|
137
|
+
*
|
|
138
|
+
* Ink 7 correctly distinguishes the physical Backspace key (terminal sends \x7f →
|
|
139
|
+
* `key.backspace`) from the forward-Delete key (\x1b[3~ → `key.delete`). Ink 5.2.1
|
|
140
|
+
* misparsed both as `key.delete`, which the old backspace fix worked around by
|
|
141
|
+
* treating `key.delete` as backward-delete.
|
|
142
|
+
*/
|
|
143
|
+
export function keyToEditAction(
|
|
144
|
+
key: { leftArrow?: boolean; rightArrow?: boolean; backspace?: boolean; delete?: boolean },
|
|
145
|
+
input: string,
|
|
146
|
+
): EditAction | null {
|
|
147
|
+
if (key.leftArrow) return { type: 'moveLeft' }
|
|
148
|
+
if (key.rightArrow) return { type: 'moveRight' }
|
|
149
|
+
if (key.backspace) return { type: 'backspace' }
|
|
150
|
+
if (key.delete) return { type: 'delete' }
|
|
151
|
+
const cleaned = normalizeInput(input)
|
|
152
|
+
if (cleaned) return { type: 'insert', text: cleaned }
|
|
153
|
+
return null
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** Browsing state for arrow-key history navigation. */
|
|
157
|
+
export interface HistoryNavState {
|
|
158
|
+
history: string[]
|
|
159
|
+
index: number // -1 = not browsing
|
|
160
|
+
savedDraft: string // draft saved on first up-arrow
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Pure history-navigation transition. Returns the value to display plus the
|
|
165
|
+
* updated browsing state, or null when the key is a no-op (empty history for up,
|
|
166
|
+
* or not browsing for down).
|
|
167
|
+
*/
|
|
168
|
+
export function navigateHistory(
|
|
169
|
+
state: HistoryNavState,
|
|
170
|
+
dir: 'up' | 'down',
|
|
171
|
+
draft: string,
|
|
172
|
+
): { index: number; savedDraft: string; value: string } | null {
|
|
173
|
+
if (dir === 'up') {
|
|
174
|
+
if (state.history.length === 0) return null
|
|
175
|
+
const savedDraft = state.index === -1 ? draft : state.savedDraft
|
|
176
|
+
const index = Math.min(state.index + 1, state.history.length - 1)
|
|
177
|
+
return { index, savedDraft, value: state.history[state.history.length - 1 - index]! }
|
|
178
|
+
}
|
|
179
|
+
// down
|
|
180
|
+
if (state.index === -1) return null
|
|
181
|
+
const index = state.index - 1
|
|
182
|
+
if (index === -1) {
|
|
183
|
+
return { index, savedDraft: '', value: state.savedDraft }
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
index,
|
|
187
|
+
savedDraft: state.savedDraft,
|
|
188
|
+
value: state.history[state.history.length - 1 - index]!,
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
133
192
|
/** True when typing a leading `/` should auto-open the slash-command picker. */
|
|
134
193
|
export function shouldAutoOpenPicker(value: string, prevValue: string, enabled: boolean): boolean {
|
|
135
194
|
return enabled && value.startsWith('/') && !prevValue.startsWith('/')
|
|
@@ -188,16 +247,10 @@ function MiphamTextInput({
|
|
|
188
247
|
}
|
|
189
248
|
|
|
190
249
|
// 把按键归一化为一次光标编辑:左/右移动,退格/删除,或光标处插入(打字/粘贴)。
|
|
250
|
+
// macOS Backspace 发 \x7f,被 Ink 映射成 key.delete(非 key.backspace),
|
|
251
|
+
// 故 keyToEditAction 里两者都按向后删处理。
|
|
191
252
|
const state: EditState = { value: valueRef.current, cursor: cursorRef.current }
|
|
192
|
-
|
|
193
|
-
if (key.leftArrow) action = { type: 'moveLeft' }
|
|
194
|
-
else if (key.rightArrow) action = { type: 'moveRight' }
|
|
195
|
-
else if (key.backspace) action = { type: 'backspace' }
|
|
196
|
-
else if (key.delete) action = { type: 'delete' }
|
|
197
|
-
else {
|
|
198
|
-
const cleaned = normalizeInput(input)
|
|
199
|
-
if (cleaned) action = { type: 'insert', text: cleaned }
|
|
200
|
-
}
|
|
253
|
+
const action = keyToEditAction(key, input)
|
|
201
254
|
if (!action) return
|
|
202
255
|
|
|
203
256
|
const next = applyEdit(state, action)
|
|
@@ -379,30 +432,19 @@ export function InputBar({
|
|
|
379
432
|
// Ignore if picker is active (command picker handles its own arrows)
|
|
380
433
|
if (value.startsWith('/')) return
|
|
381
434
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
if (historyIndexRef.current === -1) return
|
|
396
|
-
const newIndex = historyIndexRef.current - 1
|
|
397
|
-
historyIndexRef.current = newIndex
|
|
398
|
-
if (newIndex === -1) {
|
|
399
|
-
// Back to the original draft
|
|
400
|
-
setValue(savedDraftRef.current)
|
|
401
|
-
savedDraftRef.current = ''
|
|
402
|
-
} else {
|
|
403
|
-
setValue(submittedHistory[submittedHistory.length - 1 - newIndex]!)
|
|
404
|
-
}
|
|
405
|
-
return
|
|
435
|
+
const result = navigateHistory(
|
|
436
|
+
{
|
|
437
|
+
history: submittedHistory,
|
|
438
|
+
index: historyIndexRef.current,
|
|
439
|
+
savedDraft: savedDraftRef.current,
|
|
440
|
+
},
|
|
441
|
+
key.upArrow ? 'up' : 'down',
|
|
442
|
+
valueRef.current,
|
|
443
|
+
)
|
|
444
|
+
if (result) {
|
|
445
|
+
historyIndexRef.current = result.index
|
|
446
|
+
savedDraftRef.current = result.savedDraft
|
|
447
|
+
setValue(result.value)
|
|
406
448
|
}
|
|
407
449
|
}
|
|
408
450
|
})
|