dsh-copilot-vision 1.1.0 → 1.3.1
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/README.md +58 -12
- package/package.json +2 -2
- package/src/actions.js +163 -28
- package/src/audit.js +3 -2
- package/src/auth.js +51 -82
- package/src/diff.js +2 -1
- package/src/keys.js +175 -0
- package/src/plugin.js +330 -85
- package/src/shot-index.js +26 -1
- package/src/summarize.js +131 -0
- package/src/wait.js +2 -1
package/src/keys.js
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
// 按键写法解析:把 "enter" / "ctrl+c" / "f5" 这类人类写法翻译成 robot-ts 的 Key 码与修饰键。
|
|
2
|
+
//
|
|
3
|
+
// 键码不在这里写死:直接从 robot-ts 导出的 Key 枚举反查(枚举名即官方键名),
|
|
4
|
+
// 别名表只补口语写法(esc / del / pgup / 数字键…)。这样上游改键值时我们跟着走,
|
|
5
|
+
// 不会像写死常量那样悄悄注入错键。
|
|
6
|
+
//
|
|
7
|
+
// 解析是纯函数:Key/Modifier 枚举由调用方(actions.js)从 robot-ts 取出后传入,
|
|
8
|
+
// 这样本模块既不 import native,也不依赖宿主。
|
|
9
|
+
|
|
10
|
+
// 别名 → robot-ts Key 枚举名(小写形式)
|
|
11
|
+
const KEY_ALIASES = {
|
|
12
|
+
esc: 'escape',
|
|
13
|
+
return: 'enter',
|
|
14
|
+
del: 'delete',
|
|
15
|
+
ins: 'insert',
|
|
16
|
+
pgup: 'pageup',
|
|
17
|
+
pgdn: 'pagedown',
|
|
18
|
+
pgdown: 'pagedown',
|
|
19
|
+
up: 'uparrow',
|
|
20
|
+
down: 'downarrow',
|
|
21
|
+
left: 'leftarrow',
|
|
22
|
+
right: 'rightarrow',
|
|
23
|
+
plus: 'equal',
|
|
24
|
+
1: 'digit1',
|
|
25
|
+
2: 'digit2',
|
|
26
|
+
3: 'digit3',
|
|
27
|
+
4: 'digit4',
|
|
28
|
+
5: 'digit5',
|
|
29
|
+
6: 'digit6',
|
|
30
|
+
7: 'digit7',
|
|
31
|
+
8: 'digit8',
|
|
32
|
+
9: 'digit9',
|
|
33
|
+
0: 'digit0',
|
|
34
|
+
'-': 'minus',
|
|
35
|
+
'=': 'equal',
|
|
36
|
+
'[': 'leftbracket',
|
|
37
|
+
']': 'rightbracket',
|
|
38
|
+
'\\': 'backslash',
|
|
39
|
+
';': 'semicolon',
|
|
40
|
+
"'": 'quote',
|
|
41
|
+
'`': 'grave',
|
|
42
|
+
',': 'comma',
|
|
43
|
+
'.': 'period',
|
|
44
|
+
'/': 'slash',
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// 别名 → robot-ts Modifier 枚举值
|
|
48
|
+
const MODIFIER_ALIASES = {
|
|
49
|
+
ctrl: 'Control',
|
|
50
|
+
control: 'Control',
|
|
51
|
+
shift: 'Shift',
|
|
52
|
+
alt: 'Alt',
|
|
53
|
+
option: 'Alt',
|
|
54
|
+
meta: 'Meta',
|
|
55
|
+
cmd: 'Meta',
|
|
56
|
+
win: 'Meta',
|
|
57
|
+
super: 'Meta',
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// 字符键 → 它在文本里对应的字符。
|
|
61
|
+
//
|
|
62
|
+
// 只给「无修饰键的字符键」准备:这类键改走 Unicode 直注(见 resolveUnicodeChar)。
|
|
63
|
+
// 原因是 robot-ts 的按键注入走 KEYEVENTF_SCANCODE,会经过系统输入法 ——
|
|
64
|
+
// 本机中文输入法实测会把字母键吞成拼音组合串(按下不落字,直到下一次 Enter 才吐出幽灵字符),
|
|
65
|
+
// 还会把引号改写成中文弯引号。Unicode 直注绕开输入法,字符原样落下。
|
|
66
|
+
//
|
|
67
|
+
// space 不在表里:扫描码空格实测正常,而且只有真实按键才能激活聚焦的按钮。
|
|
68
|
+
const CHARACTER_KEYS = {
|
|
69
|
+
a: 'a', b: 'b', c: 'c', d: 'd', e: 'e', f: 'f', g: 'g', h: 'h', i: 'i', j: 'j',
|
|
70
|
+
k: 'k', l: 'l', m: 'm', n: 'n', o: 'o', p: 'p', q: 'q', r: 'r', s: 's', t: 't',
|
|
71
|
+
u: 'u', v: 'v', w: 'w', x: 'x', y: 'y', z: 'z',
|
|
72
|
+
digit1: '1', digit2: '2', digit3: '3', digit4: '4', digit5: '5',
|
|
73
|
+
digit6: '6', digit7: '7', digit8: '8', digit9: '9', digit0: '0',
|
|
74
|
+
minus: '-', equal: '=', leftbracket: '[', rightbracket: ']', backslash: '\\',
|
|
75
|
+
nonushash: '#', semicolon: ';', quote: "'", grave: '`', comma: ',', period: '.', slash: '/',
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export const MODIFIER_NAMES = ['ctrl', 'shift', 'alt', 'meta']
|
|
79
|
+
|
|
80
|
+
/** Key 枚举 → 小写名到码值的索引(枚举成员名即官方键名)。 */
|
|
81
|
+
function keyIndex(keyEnum) {
|
|
82
|
+
const index = new Map()
|
|
83
|
+
for (const [name, value] of Object.entries(keyEnum)) {
|
|
84
|
+
if (typeof value === 'number') index.set(name.toLowerCase(), value)
|
|
85
|
+
}
|
|
86
|
+
return index
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* 解析按键写法。
|
|
91
|
+
* 返回 { code, keyName, modifiers, spec }:
|
|
92
|
+
* code robot-ts 的 Key 码(数字)
|
|
93
|
+
* keyName 规范化的主键名(robot-ts 枚举名)
|
|
94
|
+
* modifiers 修饰键枚举值数组,如 ['Control']
|
|
95
|
+
* spec 原样回显的写法
|
|
96
|
+
* 解析失败一律抛错,错误文案里带上可用的修饰键名。
|
|
97
|
+
*/
|
|
98
|
+
export function parseKeySpec(spec, keyEnum, modifierEnum) {
|
|
99
|
+
if (typeof spec !== 'string') {
|
|
100
|
+
throw new Error(`vp_key: key 必须是字符串,收到 ${spec === null ? 'null' : typeof spec}`)
|
|
101
|
+
}
|
|
102
|
+
const trimmed = spec.trim()
|
|
103
|
+
if (trimmed === '') {
|
|
104
|
+
throw new Error('vp_key: key 不能为空字符串')
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const parts = trimmed
|
|
108
|
+
.split('+')
|
|
109
|
+
.map((part) => part.trim())
|
|
110
|
+
.filter((part) => part !== '')
|
|
111
|
+
if (parts.length === 0) {
|
|
112
|
+
throw new Error('vp_key: key 不能为空字符串')
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const modifiers = []
|
|
116
|
+
for (const part of parts.slice(0, -1)) {
|
|
117
|
+
const modifier = MODIFIER_ALIASES[part.toLowerCase()]
|
|
118
|
+
if (modifier === undefined) {
|
|
119
|
+
throw new Error(
|
|
120
|
+
`vp_key: 不认识的修饰键 "${part}"(可用:${MODIFIER_NAMES.join(' / ')})`,
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
if (!Object.values(modifierEnum).includes(modifier)) {
|
|
124
|
+
throw new Error(`vp_key: robot-ts 不支持修饰键 "${modifier}"`)
|
|
125
|
+
}
|
|
126
|
+
modifiers.push(modifier)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const rawKey = parts[parts.length - 1]
|
|
130
|
+
const lowerKey = rawKey.toLowerCase()
|
|
131
|
+
if (MODIFIER_ALIASES[lowerKey] !== undefined) {
|
|
132
|
+
throw new Error(
|
|
133
|
+
`vp_key: "${rawKey}" 只是修饰键,必须同时给一个主键(例如 ctrl+c、shift+tab)`,
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const canonical = KEY_ALIASES[lowerKey] ?? lowerKey
|
|
138
|
+
const code = keyIndex(keyEnum).get(canonical)
|
|
139
|
+
if (code === undefined) {
|
|
140
|
+
throw new Error(
|
|
141
|
+
`vp_key: 不认识的按键 "${rawKey}"。可用示例:enter / esc / tab / space / backspace / ` +
|
|
142
|
+
'delete / up / down / left / right / f1-f12 / a-z / 0-9 / ctrl+c / shift+tab',
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
code,
|
|
148
|
+
keyName: canonical,
|
|
149
|
+
modifiers,
|
|
150
|
+
spec: trimmed,
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** 该键是否是一个字符键;是则返回它对应的字符,否则返回 null。 */
|
|
155
|
+
export function characterForKey(keyName) {
|
|
156
|
+
return CHARACTER_KEYS[String(keyName).toLowerCase()] ?? null
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* 判断这个键是否该改走 Unicode 直注,返回要注入的字符;不该改走就返回 null。
|
|
161
|
+
*
|
|
162
|
+
* 规则(依据本机实测):
|
|
163
|
+
* - 无修饰键的字符键 → 注入该字符本身
|
|
164
|
+
* - 只带 shift 的字母键 → 注入大写字母
|
|
165
|
+
* - 其余(带 ctrl/alt/meta 的组合键、控制键、space)→ null,走真实扫描码
|
|
166
|
+
*/
|
|
167
|
+
export function resolveUnicodeChar(spec) {
|
|
168
|
+
const base = characterForKey(spec.keyName)
|
|
169
|
+
if (base === null) return null
|
|
170
|
+
if (spec.modifiers.length === 0) return base
|
|
171
|
+
if (spec.modifiers.length === 1 && spec.modifiers[0] === 'Shift' && /^[a-z]$/.test(base)) {
|
|
172
|
+
return base.toUpperCase()
|
|
173
|
+
}
|
|
174
|
+
return null
|
|
175
|
+
}
|