@miphamai/cli 0.55.0 → 0.57.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/bin/mipham.ts +21 -2
- package/package.json +1 -1
- package/src/commands/project.ts +9 -6
- package/src/core/engine.ts +7 -1
- package/src/i18n-core/locales/en-US.json +2 -3
- package/src/i18n-core/locales/zh-CN.json +2 -3
- package/src/index.tsx +1 -1
- package/src/plugin/claude-plugin.ts +174 -0
- package/src/plugin/plugin-loader.ts +25 -0
- package/src/plugin/plugin-manager.ts +46 -17
- package/src/plugin/plugin-validator.ts +58 -11
- package/src/security/gate.ts +3 -2
- package/src/shared/deleted-cwd.ts +26 -0
- package/src/shared/graft-savings.ts +34 -0
- package/src/shared/graft-stats.ts +53 -0
- package/src/shared/package-info.ts +1 -1
- package/src/skills/loader.ts +11 -33
- package/src/skills/seam.ts +1 -1
- package/src/tools/agent/memory.ts +20 -2
- package/src/tools/exec/bash.ts +4 -4
- package/src/ui/app.tsx +16 -3
- package/src/ui/graft-status.tsx +63 -0
- package/src/ui/input.tsx +45 -156
- package/src/ui/vim-motions.ts +0 -113
package/src/ui/vim-motions.ts
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
export type VimMode = 'insert' | 'normal'
|
|
2
|
-
|
|
3
|
-
export class VimMotionEngine {
|
|
4
|
-
mode: VimMode = 'insert'
|
|
5
|
-
private clipboard = ''
|
|
6
|
-
private undoStack: string[] = []
|
|
7
|
-
|
|
8
|
-
/** Handle a keypress in normal mode. Returns new cursor position delta and any text mutation. */
|
|
9
|
-
handleNormal(key: string, text: string, cursor: number): VimAction | null {
|
|
10
|
-
switch (key) {
|
|
11
|
-
case 'h':
|
|
12
|
-
return { cursor: cursor - 1 }
|
|
13
|
-
case 'j':
|
|
14
|
-
return { cursor: text.length } // end of line (like $)
|
|
15
|
-
case 'k':
|
|
16
|
-
return { cursor: 0 } // start of line (like 0)
|
|
17
|
-
case 'l':
|
|
18
|
-
return { cursor: cursor + 1 }
|
|
19
|
-
case '0':
|
|
20
|
-
return { cursor: 0 }
|
|
21
|
-
case '$':
|
|
22
|
-
return { cursor: text.length }
|
|
23
|
-
case 'w':
|
|
24
|
-
return { cursor: this.nextWord(text, cursor) }
|
|
25
|
-
case 'b':
|
|
26
|
-
return { cursor: this.prevWord(text, cursor) }
|
|
27
|
-
case 'd':
|
|
28
|
-
return { pending: 'd' }
|
|
29
|
-
case 'y':
|
|
30
|
-
return { pending: 'y' }
|
|
31
|
-
default:
|
|
32
|
-
return null
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/** Handle dd — delete entire line */
|
|
37
|
-
handleDD(text: string): VimAction {
|
|
38
|
-
this.clipboard = text
|
|
39
|
-
this.pushUndo(text)
|
|
40
|
-
return { text: '', cursor: 0 }
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/** Handle yy — yank entire line */
|
|
44
|
-
handleYY(text: string): VimAction {
|
|
45
|
-
this.clipboard = text
|
|
46
|
-
return { cursor: 0 } // no change
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/** Handle p — paste after cursor */
|
|
50
|
-
handlePaste(text: string, cursor: number): VimAction {
|
|
51
|
-
const newText = text.slice(0, cursor) + this.clipboard + text.slice(cursor)
|
|
52
|
-
this.pushUndo(text)
|
|
53
|
-
return { text: newText, cursor: cursor + this.clipboard.length }
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** Handle u — undo */
|
|
57
|
-
handleUndo(text: string): VimAction {
|
|
58
|
-
const prev = this.undoStack.pop()
|
|
59
|
-
if (prev !== undefined) {
|
|
60
|
-
return { text: prev, cursor: prev.length }
|
|
61
|
-
}
|
|
62
|
-
return { cursor: text.length }
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/** Handle /search */
|
|
66
|
-
handleSearch(text: string, query: string): VimAction {
|
|
67
|
-
const idx = text.indexOf(query)
|
|
68
|
-
return idx >= 0 ? { cursor: idx } : { cursor: 0 }
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
private nextWord(text: string, cursor: number): number {
|
|
72
|
-
// Skip word characters, then skip whitespace
|
|
73
|
-
let i = cursor
|
|
74
|
-
while (i < text.length && text[i] !== ' ') i++
|
|
75
|
-
while (i < text.length && text[i] === ' ') i++
|
|
76
|
-
return i
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
private prevWord(text: string, cursor: number): number {
|
|
80
|
-
let i = cursor - 1
|
|
81
|
-
while (i > 0 && text[i] === ' ') i--
|
|
82
|
-
while (i > 0 && text[i] !== ' ') i--
|
|
83
|
-
return i > 0 ? i + 1 : 0
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
private pushUndo(text: string): void {
|
|
87
|
-
this.undoStack.push(text)
|
|
88
|
-
if (this.undoStack.length > 50) this.undoStack.shift()
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export interface VimAction {
|
|
93
|
-
text?: string
|
|
94
|
-
cursor?: number
|
|
95
|
-
pending?: string
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export interface SearchBackspaceResult {
|
|
99
|
-
query: string
|
|
100
|
-
/** true → the `/` prefix should be removed by exiting search mode */
|
|
101
|
-
exit: boolean
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Backspace while in `/` search mode.
|
|
106
|
-
* Trims the query; when the query is already empty, signals that search mode
|
|
107
|
-
* should exit so the `/` placeholder disappears (the user can "delete" the
|
|
108
|
-
* slash instead of being trapped).
|
|
109
|
-
*/
|
|
110
|
-
export function handleSearchBackspace(query: string): SearchBackspaceResult {
|
|
111
|
-
if (query.length === 0) return { query: '', exit: true }
|
|
112
|
-
return { query: query.slice(0, -1), exit: false }
|
|
113
|
-
}
|