@mearl/client 2.0.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/README.md +119 -0
- package/dist/actionTimeouts.d.ts +2 -0
- package/dist/actionTimeouts.js +49 -0
- package/dist/browserRegistry.d.ts +38 -0
- package/dist/browserRegistry.js +80 -0
- package/dist/check.d.ts +1 -0
- package/dist/check.js +146 -0
- package/dist/cli.d.ts +14 -0
- package/dist/cli.js +324 -0
- package/dist/commands.d.ts +18 -0
- package/dist/commands.js +666 -0
- package/dist/fileRefs.d.ts +20 -0
- package/dist/fileRefs.js +52 -0
- package/dist/index.d.ts +402 -0
- package/dist/index.js +125 -0
- package/dist/socket.d.ts +35 -0
- package/dist/socket.js +306 -0
- package/package.json +44 -0
package/dist/commands.js
ADDED
|
@@ -0,0 +1,666 @@
|
|
|
1
|
+
export const COMMANDS = [
|
|
2
|
+
// ── API 调试 ──────────────────────────────────────────────────────────────
|
|
3
|
+
{
|
|
4
|
+
name: 'get_requests',
|
|
5
|
+
description: '获取最近的网络请求(mtop 或普通 xhr/fetch)',
|
|
6
|
+
params: [
|
|
7
|
+
{ name: 'tabId', type: 'number', description: '目标标签页 ID,从 tab_list 获取' },
|
|
8
|
+
{ name: 'count', type: 'number', description: '返回条数,默认 20' },
|
|
9
|
+
{
|
|
10
|
+
name: 'source',
|
|
11
|
+
type: '"mtop" | "requests"',
|
|
12
|
+
description: '强制指定来源,不填时使用 panel 当前模式',
|
|
13
|
+
},
|
|
14
|
+
{ name: 'filter', type: 'string', description: '按 URL 或 API 名称过滤,支持正则' },
|
|
15
|
+
{ name: 'includeBody', type: 'boolean', description: '是否包含请求/响应体,默认 true' },
|
|
16
|
+
],
|
|
17
|
+
examples: [
|
|
18
|
+
`get_requests --payload '{"count":5}'`,
|
|
19
|
+
`get_requests --payload '{"source":"mtop","filter":"cart"}'`,
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: 'get_logs',
|
|
24
|
+
description: '获取浏览器控制台日志',
|
|
25
|
+
params: [
|
|
26
|
+
{ name: 'limit', type: 'number', description: '返回条数,默认 20' },
|
|
27
|
+
{ name: 'level', type: 'string', description: '按日志级别过滤:log/info/warn/error' },
|
|
28
|
+
{ name: 'filter', type: 'string', description: '按内容过滤,支持正则' },
|
|
29
|
+
],
|
|
30
|
+
examples: [`get_logs --payload '{"limit":10,"level":"error"}'`],
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: 'get_events',
|
|
34
|
+
description: '获取 RUM/aplus 埋点事件',
|
|
35
|
+
params: [
|
|
36
|
+
{ name: 'source', type: '"rum" | "aplus" | "all"', description: '数据来源,默认 all' },
|
|
37
|
+
{ name: 'event_type', type: 'string', description: '按事件类型过滤,支持正则,如 CLK/PV' },
|
|
38
|
+
{ name: 'filter', type: 'string', description: '按 name 或 url 过滤,支持正则' },
|
|
39
|
+
{ name: 'since', type: 'number', description: '只返回最近 N 秒内的事件' },
|
|
40
|
+
{ name: 'limit', type: 'number', description: '返回条数,默认 20' },
|
|
41
|
+
],
|
|
42
|
+
examples: [`get_events --payload '{"source":"aplus","event_type":"CLK","limit":10}'`],
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: 'get_api_schema',
|
|
46
|
+
description: '获取 API 接口 schema(出入参定义)',
|
|
47
|
+
params: [
|
|
48
|
+
{ name: 'api', type: 'string', required: true, description: 'API 名称' },
|
|
49
|
+
{ name: 'type', type: '"schema" | "hsf" | "all"', description: '返回类型,默认 all' },
|
|
50
|
+
],
|
|
51
|
+
examples: [`get_api_schema --payload '{"api":"mtop.trade.order.detail"}'`],
|
|
52
|
+
},
|
|
53
|
+
// ── Mock & 规则 ───────────────────────────────────────────────────────────
|
|
54
|
+
{
|
|
55
|
+
name: 'set_mock',
|
|
56
|
+
description: '设置 API mock 数据',
|
|
57
|
+
params: [
|
|
58
|
+
{ name: 'apiName', type: 'string', required: true, description: 'API 名称或正则表达式' },
|
|
59
|
+
{ name: 'mockData', type: 'object', description: '完整 mock 响应数据(与 fields 二选一)' },
|
|
60
|
+
{
|
|
61
|
+
name: 'fields',
|
|
62
|
+
type: 'array',
|
|
63
|
+
description: '按字段路径修改真实响应(与 mockData 二选一)',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: 'enabled',
|
|
67
|
+
type: 'boolean',
|
|
68
|
+
description: '是否启用,默认 true。false 时恢复真实数据',
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: 'duration',
|
|
72
|
+
type: 'number',
|
|
73
|
+
description: '完整响应时长(毫秒):mock 的总耗时,绕过真实服务器精确控制',
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: 'conditions',
|
|
77
|
+
type: 'object',
|
|
78
|
+
description: '请求 query/body 字段子集匹配;$index 从 0 开始指定调用顺序',
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
examples: [
|
|
82
|
+
`set_mock --payload '{"apiName":"mtop.cart.query","mockData":{"ret":["SUCCESS::调用成功"]}}'`,
|
|
83
|
+
`set_mock --payload-file ./mock-data.json`,
|
|
84
|
+
],
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: 'get_mocks',
|
|
88
|
+
description: '查看当前生效的 mock 列表',
|
|
89
|
+
examples: ['get_mocks'],
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
name: 'set_rule',
|
|
93
|
+
description: '添加 Chrome declarativeNetRequest 规则(重定向/修改请求头/拦截请求)',
|
|
94
|
+
examples: [`set_rule --payload '{"rule":{...}}'`],
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: 'get_rules',
|
|
98
|
+
description: '查看当前存储的全部请求规则(含 Options 面板配置的)',
|
|
99
|
+
examples: ['get_rules'],
|
|
100
|
+
},
|
|
101
|
+
// ── 网络代理 ──────────────────────────────────────────────────────────────
|
|
102
|
+
{
|
|
103
|
+
name: 'send_request',
|
|
104
|
+
description: '发送 HTTP 请求,自动携带浏览器 Cookie',
|
|
105
|
+
params: [
|
|
106
|
+
{ name: 'url', type: 'string', required: true, description: '完整目标 URL' },
|
|
107
|
+
{ name: 'method', type: 'string', description: 'HTTP 方法,默认 GET' },
|
|
108
|
+
{ name: 'headers', type: 'object', description: '自定义请求头' },
|
|
109
|
+
{ name: 'params', type: 'object', description: 'URL 查询参数' },
|
|
110
|
+
{ name: 'body', type: 'any', description: '请求体(传对象时自动 JSON 序列化)' },
|
|
111
|
+
{ name: 'withCookies', type: 'boolean', description: '是否附加浏览器 Cookie,默认 true' },
|
|
112
|
+
{ name: 'cookieDomain', type: 'string', description: '指定 Cookie 域名,不填时从 url 提取' },
|
|
113
|
+
{ name: 'timeout', type: 'number', description: '超时毫秒数,默认 30000' },
|
|
114
|
+
],
|
|
115
|
+
examples: [`send_request --payload '{"url":"https://api.example.com/data","method":"GET"}'`],
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: 'send_mtop_request',
|
|
119
|
+
description: '在页面上下文中发起 mtop 请求,自动处理签名和 token',
|
|
120
|
+
params: [
|
|
121
|
+
{ name: 'api', type: 'string', required: true, description: 'mtop API 名称' },
|
|
122
|
+
{ name: 'data', type: 'object', description: '请求数据' },
|
|
123
|
+
{ name: 'version', type: 'string', description: 'API 版本,默认 1.0' },
|
|
124
|
+
{ name: 'method', type: 'string', description: 'HTTP 方法,默认 GET' },
|
|
125
|
+
{ name: 'env', type: '"online" | "pre"', description: '请求环境,默认 online' },
|
|
126
|
+
{ name: 'timeout', type: 'number', description: '超时毫秒数,默认 10000' },
|
|
127
|
+
],
|
|
128
|
+
examples: [
|
|
129
|
+
`send_mtop_request --payload '{"api":"mtop.trade.order.detail","data":{"orderId":"123"}}'`,
|
|
130
|
+
],
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: 'tdbank_account',
|
|
134
|
+
description: 'TDBank 账号操作:获取当前账号、账号列表、切换账号、快速借用并切换账号',
|
|
135
|
+
params: [
|
|
136
|
+
{
|
|
137
|
+
name: 'operation',
|
|
138
|
+
type: '"current" | "list" | "switch" | "borrow"',
|
|
139
|
+
description: '操作类型,默认 list',
|
|
140
|
+
},
|
|
141
|
+
{ name: 'refresh', type: 'boolean', description: 'list 时是否强制刷新账号列表' },
|
|
142
|
+
{ name: 'accountId', type: 'string | number', description: 'switch 时使用账号列表中的 id' },
|
|
143
|
+
{ name: 'havanaId', type: 'string | number', description: 'switch 时也可直接指定 havanaId' },
|
|
144
|
+
{ name: 'site', type: 'string | number', description: '直接指定 havanaId 时必填' },
|
|
145
|
+
{ name: 'query', type: 'string', description: 'borrow 时输入要借用的账号 loginId/关键词' },
|
|
146
|
+
],
|
|
147
|
+
examples: [
|
|
148
|
+
`tdbank_account --payload '{"operation":"current"}'`,
|
|
149
|
+
`tdbank_account --payload '{"operation":"list","refresh":true}'`,
|
|
150
|
+
`tdbank_account --payload '{"operation":"switch","accountId":12345}'`,
|
|
151
|
+
`tdbank_account --payload '{"operation":"borrow","query":"test_account"}'`,
|
|
152
|
+
],
|
|
153
|
+
},
|
|
154
|
+
// ── 浏览器 ────────────────────────────────────────────────────────────────
|
|
155
|
+
{
|
|
156
|
+
name: 'browser_list',
|
|
157
|
+
description: '列出所有浏览器及其连接状态、类型和托管实例信息',
|
|
158
|
+
examples: ['browser_list'],
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
name: 'browser_launch',
|
|
162
|
+
description: '启动独立 Chrome,可在新实例中通过 TDBank 登录指定账号',
|
|
163
|
+
params: [
|
|
164
|
+
{ name: 'name', type: 'string', required: true, description: '实例名称,最多 64 个字符' },
|
|
165
|
+
{ name: 'headless', type: 'boolean', description: '是否无头运行,默认 true' },
|
|
166
|
+
{
|
|
167
|
+
name: 'userAgentMode',
|
|
168
|
+
type: '"default" | "desktop"',
|
|
169
|
+
description: 'UA 模式:default 使用 Chrome 默认 UA,desktop 使用匹配本机版本的桌面 UA',
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
name: 'persistent',
|
|
173
|
+
type: 'boolean',
|
|
174
|
+
description: '关闭后是否保留独立 Profile,默认 false',
|
|
175
|
+
},
|
|
176
|
+
{ name: 'url', type: 'string', description: '登录完成后打开的初始页面' },
|
|
177
|
+
{ name: 'executablePath', type: 'string', description: '自定义 Chrome 可执行文件路径' },
|
|
178
|
+
{ name: 'accountId', type: 'string | number', description: '登录账号列表中的 accountId' },
|
|
179
|
+
{
|
|
180
|
+
name: 'havanaId',
|
|
181
|
+
type: 'string | number',
|
|
182
|
+
description: '直接登录 havanaId;需要同时传 site',
|
|
183
|
+
},
|
|
184
|
+
{ name: 'site', type: 'string | number', description: 'havanaId 对应的站点' },
|
|
185
|
+
{ name: 'query', type: 'string', description: '搜索、借用并登录匹配的 TDBank 账号' },
|
|
186
|
+
{
|
|
187
|
+
name: 'tabId',
|
|
188
|
+
type: 'number',
|
|
189
|
+
description: 'CDP 控制浏览器中用于读取 TDBank Cookie 的标签页',
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
name: 'copyCookieDomains',
|
|
193
|
+
type: 'string[]',
|
|
194
|
+
description: '从控制浏览器复制到新实例的 Cookie 域名列表,可与 TDBank 登录组合',
|
|
195
|
+
},
|
|
196
|
+
],
|
|
197
|
+
examples: [
|
|
198
|
+
`browser_launch --payload '{"name":"account-a","headless":true,"accountId":12345}'`,
|
|
199
|
+
`browser_launch --payload '{"name":"figma","userAgentMode":"desktop","copyCookieDomains":["figma.com"]}'`,
|
|
200
|
+
`browser_launch --payload '{"name":"account-b","query":"test_account","url":"https://www.taobao.com"}'`,
|
|
201
|
+
`browser_launch --payload '{"name":"with-cookies","copyCookieDomains":["example.com","sub.example.org"]}'`,
|
|
202
|
+
],
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
name: 'browser_close',
|
|
206
|
+
description: '关闭指定托管浏览器并按策略清理独立 Profile',
|
|
207
|
+
params: [
|
|
208
|
+
{
|
|
209
|
+
name: 'browser',
|
|
210
|
+
type: 'string',
|
|
211
|
+
required: true,
|
|
212
|
+
description: '托管浏览器的 browserId 或名称',
|
|
213
|
+
},
|
|
214
|
+
{ name: 'deleteProfile', type: 'boolean', description: '强制删除持久化 Profile,默认 false' },
|
|
215
|
+
],
|
|
216
|
+
examples: [
|
|
217
|
+
`browser_close --payload '{"browser":"managed:account-a"}'`,
|
|
218
|
+
`browser_close --payload '{"browser":"account-b","deleteProfile":true}'`,
|
|
219
|
+
],
|
|
220
|
+
},
|
|
221
|
+
// ── 标签页 ────────────────────────────────────────────────────────────────
|
|
222
|
+
{
|
|
223
|
+
name: 'tab_open',
|
|
224
|
+
description: '打开或按 URL 规则复用 Tab,并等待新页面加载完成',
|
|
225
|
+
params: [
|
|
226
|
+
{ name: 'url', type: 'string', required: true, description: '要打开的 URL' },
|
|
227
|
+
{ name: 'active', type: 'boolean', description: '是否激活新 Tab,默认 false' },
|
|
228
|
+
{
|
|
229
|
+
name: 'closeExisting',
|
|
230
|
+
type: 'boolean',
|
|
231
|
+
description: '打开前先关闭 Agent 受控的已有标签页,默认 false',
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
name: 'group',
|
|
235
|
+
type: 'string',
|
|
236
|
+
description: '把新 Tab 加入指定标题的标签页分组(同名分组存在则加入,否则新建)。仅扩展模式支持',
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
name: 'reuse',
|
|
240
|
+
type: '"never" | "prefer" | "require"',
|
|
241
|
+
description: 'never 始终新开;prefer 优先复用;require 只允许复用。默认 never',
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
name: 'match',
|
|
245
|
+
type: 'object',
|
|
246
|
+
description: '复用匹配规则:urlPattern(支持 *)、ignoreSearch、ignoreHash、onMultiple(error/first)',
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
name: 'restoreFocusOnClose',
|
|
250
|
+
type: 'boolean',
|
|
251
|
+
description: '关闭本次新开的 active Tab 后恢复原活动标签页,默认 false',
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
name: 'emulation',
|
|
255
|
+
type: 'object',
|
|
256
|
+
description: '开 tab 即进入移动端模拟态(首屏即移动态、无需 reload)。字段同 set_device_emulation 去掉 enabled,如 {"preset":"iphone-15-pro"}',
|
|
257
|
+
},
|
|
258
|
+
],
|
|
259
|
+
examples: [
|
|
260
|
+
`tab_open --payload '{"url":"https://example.com"}'`,
|
|
261
|
+
`tab_open --payload '{"url":"https://example.com/page","reuse":"prefer","match":{"ignoreSearch":true}}'`,
|
|
262
|
+
`tab_open --payload '{"url":"https://m.example.com","emulation":{"preset":"iphone-15-pro"}}'`,
|
|
263
|
+
`tab_open --payload '{"url":"https://example.com","group":"验证任务"}'`,
|
|
264
|
+
],
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
name: 'tab_close',
|
|
268
|
+
description: '关闭指定标签页',
|
|
269
|
+
params: [{ name: 'tabId', type: 'number', required: true, description: '要关闭的标签页 ID' }],
|
|
270
|
+
examples: [`tab_close --payload '{"tabId":123}'`],
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
name: 'tab_list',
|
|
274
|
+
description: '获取当前窗口所有标签页列表',
|
|
275
|
+
examples: ['tab_list'],
|
|
276
|
+
},
|
|
277
|
+
// ── 页面操作 ──────────────────────────────────────────────────────────────
|
|
278
|
+
{
|
|
279
|
+
name: 'page_click',
|
|
280
|
+
description: '点击页面元素,支持 selector / text / point 三种定位方式;默认等待异步稳定并返回页面变化信号',
|
|
281
|
+
params: [
|
|
282
|
+
{
|
|
283
|
+
name: 'selector',
|
|
284
|
+
type: 'string',
|
|
285
|
+
description: '原生 CSS 选择器,或 @eN 形式的 snapshot ref(来自 page_snapshot,必须带 @ 前缀)。不支持 :has-text/:visible 等 Playwright 私有伪类',
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
name: 'text',
|
|
289
|
+
type: 'string',
|
|
290
|
+
description: '按可见文本(accessibility name)定位。需要时配合 role/exact 消歧;多匹配会报错并列出候选',
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
name: 'point',
|
|
294
|
+
type: '{ x: number; y: number }',
|
|
295
|
+
description: '按视口坐标点击(CSS 像素)。selector/text 都不适用的兜底场景',
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
name: 'role',
|
|
299
|
+
type: 'string',
|
|
300
|
+
description: '配合 text 使用,按 AX role 过滤(如 button、link、heading)',
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
name: 'exact',
|
|
304
|
+
type: 'boolean',
|
|
305
|
+
description: '配合 text 使用,默认 true 精确匹配;false 时按子串匹配',
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
name: 'clickType',
|
|
309
|
+
type: '"js" | "cdp"',
|
|
310
|
+
description: '点击方式,默认 js(对 selector/@ref 调用 el.click());cdp 走真实 mouse/touch 事件',
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
name: 'observe',
|
|
314
|
+
type: 'object | false',
|
|
315
|
+
description: '观察选项(quietMs/firstChangeTimeoutMs/timeoutMs/navigationGraceMs/navigationTimeoutMs/networkIdleMs/contentReadyAfterMs);传 false 关闭内置观察,仅执行裸动作',
|
|
316
|
+
},
|
|
317
|
+
{ name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
|
|
318
|
+
],
|
|
319
|
+
examples: [
|
|
320
|
+
`page_click --payload '{"text":"提交"}'`,
|
|
321
|
+
`page_click --payload '{"text":"退款明细","role":"button"}'`,
|
|
322
|
+
`page_click --payload '{"selector":"@e3"}'`,
|
|
323
|
+
`page_click --payload '{"selector":".submit-btn"}'`,
|
|
324
|
+
`page_click --payload '{"point":{"x":336,"y":117}}'`,
|
|
325
|
+
],
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
name: 'page_type',
|
|
329
|
+
description: '向输入框填写文本,兼容 React 受控组件;默认观察校验提示等异步变化',
|
|
330
|
+
params: [
|
|
331
|
+
{
|
|
332
|
+
name: 'selector',
|
|
333
|
+
type: 'string',
|
|
334
|
+
required: true,
|
|
335
|
+
description: '原生 CSS 选择器或 @eN snapshot ref(必须带 @ 前缀)',
|
|
336
|
+
},
|
|
337
|
+
{ name: 'text', type: 'string', required: true, description: '要填写的文本' },
|
|
338
|
+
{ name: 'clearFirst', type: 'boolean', description: '是否先清空原有内容,默认 true' },
|
|
339
|
+
{
|
|
340
|
+
name: 'observe',
|
|
341
|
+
type: 'object | false',
|
|
342
|
+
description: '观察选项;传 false 关闭内置观察,仅执行裸动作',
|
|
343
|
+
},
|
|
344
|
+
{ name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
|
|
345
|
+
],
|
|
346
|
+
examples: [`page_type --payload '{"selector":"@e6","text":"搜索关键词"}'`],
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
name: 'page_hover',
|
|
350
|
+
description: '将鼠标悬停在元素上,默认观察下拉菜单、提示信息等 hover 后变化',
|
|
351
|
+
params: [
|
|
352
|
+
{
|
|
353
|
+
name: 'selector',
|
|
354
|
+
type: 'string',
|
|
355
|
+
required: true,
|
|
356
|
+
description: '原生 CSS 选择器或 @eN snapshot ref(必须带 @ 前缀)',
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
name: 'observe',
|
|
360
|
+
type: 'object | false',
|
|
361
|
+
description: '观察选项;传 false 关闭内置观察,仅执行裸动作',
|
|
362
|
+
},
|
|
363
|
+
{ name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
|
|
364
|
+
],
|
|
365
|
+
examples: [`page_hover --payload '{"selector":".nav-menu"}'`],
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
name: 'page_scroll',
|
|
369
|
+
description: '滚动页面,默认观察懒加载等滚动后变化',
|
|
370
|
+
params: [
|
|
371
|
+
{
|
|
372
|
+
name: 'direction',
|
|
373
|
+
type: '"up" | "down" | "top" | "bottom"',
|
|
374
|
+
required: true,
|
|
375
|
+
description: '滚动方向',
|
|
376
|
+
},
|
|
377
|
+
{ name: 'distance', type: 'number', description: '滚动距离(px),默认 300' },
|
|
378
|
+
{
|
|
379
|
+
name: 'observe',
|
|
380
|
+
type: 'object | false',
|
|
381
|
+
description: '观察选项;传 false 关闭内置观察,仅执行裸动作',
|
|
382
|
+
},
|
|
383
|
+
{ name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
|
|
384
|
+
],
|
|
385
|
+
examples: [
|
|
386
|
+
`page_scroll --payload '{"direction":"down"}'`,
|
|
387
|
+
`page_scroll --payload '{"direction":"bottom"}'`,
|
|
388
|
+
],
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
name: 'page_eval',
|
|
392
|
+
description: '在页面上下文中执行任意 JavaScript 表达式',
|
|
393
|
+
params: [
|
|
394
|
+
{ name: 'expression', type: 'string', required: true, description: '要执行的 JS 表达式' },
|
|
395
|
+
{
|
|
396
|
+
name: 'awaitPromise',
|
|
397
|
+
type: 'boolean',
|
|
398
|
+
description: '表达式返回 Promise 时等待完成,默认 true',
|
|
399
|
+
},
|
|
400
|
+
{ name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
|
|
401
|
+
],
|
|
402
|
+
examples: [`page_eval --payload '{"expression":"document.title"}'`],
|
|
403
|
+
},
|
|
404
|
+
{
|
|
405
|
+
name: 'page_press',
|
|
406
|
+
description: '在页面中按下键盘按键,默认观察提交、关闭弹窗等结果',
|
|
407
|
+
params: [
|
|
408
|
+
{
|
|
409
|
+
name: 'key',
|
|
410
|
+
type: 'string',
|
|
411
|
+
required: true,
|
|
412
|
+
description: '按键名称:Enter/Tab/Escape/Backspace 等',
|
|
413
|
+
},
|
|
414
|
+
{ name: 'modifiers', type: 'string[]', description: '修饰键数组:ctrl/alt/shift/meta/cmd' },
|
|
415
|
+
{
|
|
416
|
+
name: 'observe',
|
|
417
|
+
type: 'object | false',
|
|
418
|
+
description: '观察选项;传 false 关闭内置观察,仅执行裸动作',
|
|
419
|
+
},
|
|
420
|
+
{ name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
|
|
421
|
+
],
|
|
422
|
+
examples: [`page_press --payload '{"key":"Enter"}'`],
|
|
423
|
+
},
|
|
424
|
+
{
|
|
425
|
+
name: 'page_wait',
|
|
426
|
+
description: '等待指定时间、元素出现或页面条件成立',
|
|
427
|
+
params: [
|
|
428
|
+
{ name: 'time', type: 'number', description: '等待毫秒数(与 selector 二选一)' },
|
|
429
|
+
{
|
|
430
|
+
name: 'selector',
|
|
431
|
+
type: 'string',
|
|
432
|
+
description: '等待元素出现的 CSS 选择器(与 time/condition 三选一)',
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
name: 'condition',
|
|
436
|
+
type: 'string',
|
|
437
|
+
description: '在页面主上下文轮询的 JS 表达式,返回 truthy 时结束',
|
|
438
|
+
},
|
|
439
|
+
{ name: 'timeout', type: 'number', description: '等待超时毫秒数,默认 10000' },
|
|
440
|
+
{ name: 'interval', type: 'number', description: '轮询间隔毫秒数,默认 200' },
|
|
441
|
+
{ name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
|
|
442
|
+
],
|
|
443
|
+
examples: [
|
|
444
|
+
`page_wait --payload '{"time":1000}'`,
|
|
445
|
+
`page_wait --payload '{"selector":".loaded"}'`,
|
|
446
|
+
`page_wait --payload '{"condition":"window.appReady === true","timeout":30000}'`,
|
|
447
|
+
],
|
|
448
|
+
},
|
|
449
|
+
{
|
|
450
|
+
name: 'page_navigate',
|
|
451
|
+
description: '在当前标签页内导航到新 URL,或用 refresh 直接刷新当前页面',
|
|
452
|
+
params: [
|
|
453
|
+
{ name: 'url', type: 'string', description: '要导航到的 URL(refresh 为 true 时可省略)' },
|
|
454
|
+
{
|
|
455
|
+
name: 'refresh',
|
|
456
|
+
type: 'boolean',
|
|
457
|
+
description: '为 true 时直接重新加载当前页面(忽略 url),默认 false',
|
|
458
|
+
},
|
|
459
|
+
{ name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
|
|
460
|
+
],
|
|
461
|
+
examples: [
|
|
462
|
+
`page_navigate --payload '{"tabId":12345,"url":"https://example.com/page2"}'`,
|
|
463
|
+
`page_navigate --payload '{"tabId":12345,"refresh":true}'`,
|
|
464
|
+
],
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
name: 'page_upload',
|
|
468
|
+
description: '向 <input type="file"> 元素上传文件,默认观察上传状态变化',
|
|
469
|
+
params: [
|
|
470
|
+
{
|
|
471
|
+
name: 'selector',
|
|
472
|
+
type: 'string',
|
|
473
|
+
required: true,
|
|
474
|
+
description: '原生 CSS 选择器或 @eN snapshot ref(必须带 @ 前缀),必须指向 input[type=file]',
|
|
475
|
+
},
|
|
476
|
+
{ name: 'filePaths', type: 'string[]', required: true, description: '本地文件路径数组' },
|
|
477
|
+
{
|
|
478
|
+
name: 'observe',
|
|
479
|
+
type: 'object | false',
|
|
480
|
+
description: '观察选项;传 false 关闭内置观察,仅执行裸动作',
|
|
481
|
+
},
|
|
482
|
+
{ name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
|
|
483
|
+
],
|
|
484
|
+
examples: [
|
|
485
|
+
`page_upload --payload '{"selector":"#file-input","filePaths":["/Users/me/photo.jpg"]}'`,
|
|
486
|
+
],
|
|
487
|
+
},
|
|
488
|
+
// ── 页面感知 ──────────────────────────────────────────────────────────────
|
|
489
|
+
{
|
|
490
|
+
name: 'page_snapshot',
|
|
491
|
+
description: '获取页面无障碍树快照,支持完整、交互元素或当前视口范围(含 @ref)',
|
|
492
|
+
params: [
|
|
493
|
+
{ name: 'depth', type: 'number', description: '树深度,默认 15,复杂页面可调大' },
|
|
494
|
+
{
|
|
495
|
+
name: 'mode',
|
|
496
|
+
type: '"full" | "interactive" | "viewport"',
|
|
497
|
+
description: '输出范围,默认 full;长列表优先使用 viewport',
|
|
498
|
+
},
|
|
499
|
+
{
|
|
500
|
+
name: 'rootSelector',
|
|
501
|
+
type: 'string',
|
|
502
|
+
description: '只获取指定 CSS 元素的 AX 子树,可与 mode 组合',
|
|
503
|
+
},
|
|
504
|
+
{ name: 'maxNodes', type: 'number', description: '最多输出节点数,0 表示不限制' },
|
|
505
|
+
{
|
|
506
|
+
name: 'maxChars',
|
|
507
|
+
type: 'number',
|
|
508
|
+
description: '快照文本最大字符数,默认 60000,超出保留首尾;传 0 不限制',
|
|
509
|
+
},
|
|
510
|
+
{ name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
|
|
511
|
+
],
|
|
512
|
+
examples: [
|
|
513
|
+
'page_snapshot',
|
|
514
|
+
`page_snapshot --payload '{"tabId":1,"mode":"viewport"}'`,
|
|
515
|
+
`page_snapshot --payload '{"tabId":1,"rootSelector":"[role=dialog]"}'`,
|
|
516
|
+
],
|
|
517
|
+
},
|
|
518
|
+
{
|
|
519
|
+
name: 'page_screenshot',
|
|
520
|
+
description: '获取当前页面或指定元素截图',
|
|
521
|
+
outputFlag: true,
|
|
522
|
+
params: [
|
|
523
|
+
{ name: 'selector', type: 'string', description: 'CSS 选择器,提供后只截取该元素区域' },
|
|
524
|
+
{ name: 'format', type: '"png" | "jpeg"', description: '图片格式,默认 png' },
|
|
525
|
+
{ name: 'quality', type: 'number', description: 'JPEG 压缩质量(0-100),默认 80' },
|
|
526
|
+
{ name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
|
|
527
|
+
],
|
|
528
|
+
examples: [
|
|
529
|
+
'page_screenshot --output ./screenshot.png',
|
|
530
|
+
`page_screenshot --payload '{"selector":".product-card"}' --output ./card.png`,
|
|
531
|
+
],
|
|
532
|
+
},
|
|
533
|
+
{
|
|
534
|
+
name: 'page_selected_element',
|
|
535
|
+
description: '获取 DevTools Elements 面板当前选中元素的详细信息',
|
|
536
|
+
outputFlag: true,
|
|
537
|
+
params: [
|
|
538
|
+
{
|
|
539
|
+
name: 'includeOuterHTML',
|
|
540
|
+
type: 'boolean',
|
|
541
|
+
description: '是否返回 outerHTML(最多 3000 字符),默认 true',
|
|
542
|
+
},
|
|
543
|
+
{
|
|
544
|
+
name: 'includeScreenshot',
|
|
545
|
+
type: 'boolean',
|
|
546
|
+
description: '是否附带元素截图,默认 false;指定 --output 时自动开启',
|
|
547
|
+
},
|
|
548
|
+
{ name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
|
|
549
|
+
],
|
|
550
|
+
examples: ['page_selected_element', 'page_selected_element --output ./element.png'],
|
|
551
|
+
},
|
|
552
|
+
{
|
|
553
|
+
name: 'get_user_info',
|
|
554
|
+
description: '获取当前登录用户的信息',
|
|
555
|
+
params: [
|
|
556
|
+
{
|
|
557
|
+
name: 'detail',
|
|
558
|
+
type: 'boolean',
|
|
559
|
+
description: '是否获取完整用户信息,默认 false(只返回工号)',
|
|
560
|
+
},
|
|
561
|
+
],
|
|
562
|
+
examples: ['get_user_info', `get_user_info --payload '{"detail":true}'`],
|
|
563
|
+
},
|
|
564
|
+
// ── 录制 ──────────────────────────────────────────────────────────────────
|
|
565
|
+
{
|
|
566
|
+
name: 'record_start',
|
|
567
|
+
description: '开始录制用户操作',
|
|
568
|
+
examples: ['record_start'],
|
|
569
|
+
},
|
|
570
|
+
{
|
|
571
|
+
name: 'record_stop',
|
|
572
|
+
description: '停止录制并返回完整结果(操作 + 关联请求);未在录制时不报错,返回 wasRecording: false',
|
|
573
|
+
examples: ['record_stop'],
|
|
574
|
+
},
|
|
575
|
+
// ── 移动端模拟 ────────────────────────────────────────────────────────────
|
|
576
|
+
{
|
|
577
|
+
name: 'set_device_emulation',
|
|
578
|
+
description: '把目标 tab 切换为移动端模拟(视口/UA/触摸),等价 DevTools 设备工具栏,作用域 per-tab',
|
|
579
|
+
params: [
|
|
580
|
+
{ name: 'enabled', type: 'boolean', required: true, description: 'true=启用,false=清除' },
|
|
581
|
+
{
|
|
582
|
+
name: 'preset',
|
|
583
|
+
type: '"iphone-15-pro" | "iphone-se" | "pixel-8" | "ipad-mini" | "galaxy-s23"',
|
|
584
|
+
description: '内置设备预设,提供 width/height/DPR/UA 默认值',
|
|
585
|
+
},
|
|
586
|
+
{ name: 'width', type: 'number', description: '视口宽度(覆盖 preset)' },
|
|
587
|
+
{ name: 'height', type: 'number', description: '视口高度(覆盖 preset)' },
|
|
588
|
+
{ name: 'deviceScaleFactor', type: 'number', description: 'DPR(覆盖 preset)' },
|
|
589
|
+
{ name: 'mobile', type: 'boolean', description: '是否走移动渲染模式,默认从 preset 推断' },
|
|
590
|
+
{ name: 'userAgent', type: 'string', description: '自定义 UA(覆盖 preset)' },
|
|
591
|
+
{
|
|
592
|
+
name: 'orientation',
|
|
593
|
+
type: '"portrait" | "landscape"',
|
|
594
|
+
description: '横竖屏,默认 portrait',
|
|
595
|
+
},
|
|
596
|
+
{ name: 'touch', type: 'boolean', description: '是否启用触摸事件,默认 mobile 为真时启用' },
|
|
597
|
+
{ name: 'reload', type: 'boolean', description: '启用后是否重载页面,默认 true' },
|
|
598
|
+
{ name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
|
|
599
|
+
],
|
|
600
|
+
examples: [
|
|
601
|
+
`set_device_emulation --payload '{"enabled":true,"preset":"iphone-15-pro"}'`,
|
|
602
|
+
`set_device_emulation --payload '{"enabled":true,"preset":"pixel-8","orientation":"landscape"}'`,
|
|
603
|
+
`set_device_emulation --payload '{"enabled":false}'`,
|
|
604
|
+
],
|
|
605
|
+
},
|
|
606
|
+
{
|
|
607
|
+
name: 'set_timezone',
|
|
608
|
+
description: '覆盖目标 tab 的时区,传空字符串恢复浏览器默认时区',
|
|
609
|
+
params: [
|
|
610
|
+
{ name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
|
|
611
|
+
{
|
|
612
|
+
name: 'timezone',
|
|
613
|
+
type: 'string',
|
|
614
|
+
required: true,
|
|
615
|
+
description: 'IANA 时区标识(如 Asia/Shanghai);空字符串表示清除覆盖',
|
|
616
|
+
},
|
|
617
|
+
],
|
|
618
|
+
examples: [
|
|
619
|
+
`set_timezone --payload '{"tabId":12345,"timezone":"America/New_York"}'`,
|
|
620
|
+
`set_timezone --payload '{"tabId":12345,"timezone":""}'`,
|
|
621
|
+
],
|
|
622
|
+
},
|
|
623
|
+
// ── 其他 ──────────────────────────────────────────────────────────────────
|
|
624
|
+
{
|
|
625
|
+
name: 'page_frames',
|
|
626
|
+
description: '获取页面所有 iframe 列表',
|
|
627
|
+
params: [{ name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' }],
|
|
628
|
+
examples: [`page_frames --payload '{"tabId":12345}'`],
|
|
629
|
+
},
|
|
630
|
+
{
|
|
631
|
+
name: 'request_domain_permission',
|
|
632
|
+
description: '申请访问指定域名的权限(弹窗让用户授权)',
|
|
633
|
+
params: [
|
|
634
|
+
{
|
|
635
|
+
name: 'domain',
|
|
636
|
+
type: 'string',
|
|
637
|
+
required: true,
|
|
638
|
+
description: '需要授权的域名,如 example.com',
|
|
639
|
+
},
|
|
640
|
+
],
|
|
641
|
+
examples: [`request_domain_permission --payload '{"domain":"example.com"}'`],
|
|
642
|
+
},
|
|
643
|
+
// ── 组合调用 ────────────────────────────────────────────────────────────────
|
|
644
|
+
{
|
|
645
|
+
name: 'run_actions',
|
|
646
|
+
description: '批量顺序执行多个 action,减少往返延迟。遇错即停,返回已完成步骤结果;步骤内的页面动作不带内置观察',
|
|
647
|
+
params: [
|
|
648
|
+
{
|
|
649
|
+
name: 'actions',
|
|
650
|
+
type: 'Array<{action: string, data?: object}>',
|
|
651
|
+
required: true,
|
|
652
|
+
description: '要依次执行的 action 列表',
|
|
653
|
+
},
|
|
654
|
+
{
|
|
655
|
+
name: 'tabId',
|
|
656
|
+
type: 'number',
|
|
657
|
+
required: true,
|
|
658
|
+
description: '所有步骤共享的 tabId,步骤自身指定的优先',
|
|
659
|
+
},
|
|
660
|
+
],
|
|
661
|
+
examples: [
|
|
662
|
+
`run_actions --payload '{"actions":[{"action":"page_scroll","data":{"direction":"down"}},{"action":"page_wait","data":{"time":500}},{"action":"page_screenshot"}]}'`,
|
|
663
|
+
],
|
|
664
|
+
},
|
|
665
|
+
];
|
|
666
|
+
export const COMMAND_MAP = new Map(COMMANDS.map(c => [c.name, c]));
|