@mearl/client 2.19.1 → 2.19.3

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/dist/commands.js CHANGED
@@ -6,12 +6,35 @@ const PAGE_DIAGNOSTICS_PARAM = {
6
6
  name: 'diagnostics',
7
7
  type: 'object | boolean',
8
8
  description: '默认关闭;传 true 返回动作期间新增的 error logs/业务 requests,或传对象自定义通道与过滤',
9
+ details: [
10
+ 'logs: boolean | { level, limit, filter };true 默认采集 error 日志',
11
+ 'requests: boolean | { count, filter, source, includeBody, includeHeaders, maxBodySize, fields, keysOnly }',
12
+ 'events: boolean | { source, event_type, filter, limit, includeRaw };埋点需显式开启',
13
+ '各通道过滤字段同 get_logs / get_requests / get_events;observe=false 时仍返回诊断增量,但不等待 DOM/导航稳定',
14
+ ],
9
15
  };
10
16
  const PAGE_OBSERVE_PARAM = {
11
17
  name: 'observe',
12
18
  type: 'object | false',
13
19
  description: '默认开启 DOM/导航观察;传 false 关闭,不影响显式请求的 diagnostics',
20
+ details: [
21
+ 'quietMs: number,DOM 变化后的稳定窗口,默认 100ms',
22
+ 'firstChangeTimeoutMs: number,无 DOM 变化时的观察窗口,默认 500ms',
23
+ 'timeoutMs: number,DOM 观察阶段最大时间,默认 3000ms',
24
+ 'navigationGraceMs: number,低信息量点击/按键的导航宽限,默认 1000ms;相关网络活动可延长宽限',
25
+ 'navigationTimeoutMs: number,导航就绪最大等待时间,默认 15000ms',
26
+ 'networkIdleMs: number,文档完成且相关请求归零后的静默时间,默认 500ms',
27
+ 'contentReadyAfterMs: number,结构稳定兜底保护期,默认 min(5000, navigationTimeoutMs / 2),并限制在导航超时前',
28
+ ],
14
29
  };
30
+ const PAGE_ACTION_RESULT = [
31
+ '默认返回 { action, observation };action.success 只表示动作成功,业务效果需结合 observation 和目标状态判断。',
32
+ 'observe=false 且未开启 diagnostics 时返回裸动作结果(如 { clicked: true }),没有 action/observation;开启 diagnostics 时返回 { action, diagnostics }。',
33
+ '包装结果中的 action.stage=precondition 表示未派发,省略 observation/diagnostics;dispatch-uncertain 表示可能已派发,先查看 action.attempt 与可用观察或最小快照核验,避免重复提交。失败以退出码 1 结束。',
34
+ 'observation.effects 返回通知、控件和焦点增量,可直接复用 node.ref/selector;changed=true 且 effects 为空不表示失败。',
35
+ 'fullSnapshotRecommended/snapshotReasons 提示是否补充快照;openedTabs 返回可继续操作的 tabId 和 ready。navigation 模式的 ready 表示新页面就绪。',
36
+ '显式开启的诊断通道在 diagnostics 中返回动作期间增量,与 observe 独立。',
37
+ ];
15
38
  export const COMMANDS = [
16
39
  // ── API 调试 ──────────────────────────────────────────────────────────────
17
40
  {
@@ -56,6 +79,13 @@ export const COMMANDS = [
56
79
  { name: 'fields', type: 'string[]', description: '从响应体提取指定字段路径,最多 100 个' },
57
80
  { name: 'keysOnly', type: 'boolean', description: '只返回数据结构,不返回叶子值' },
58
81
  ],
82
+ notes: [
83
+ '流式请求开始后即进入缓冲区;页面及 App 桥代发的 MTop SSE 都归入 mtop。无法归属当前页面 target 的 Service Worker 请求不在采集范围内。',
84
+ ],
85
+ result: [
86
+ 'nextCursor 用于同类查询续读,hasMore 表示还有数据,gap 表示缓冲区淘汰造成缺口;checkpoint cursor 可分别用于三类查询的初始边界。',
87
+ 'isPending 标记未完成请求;SSE 的 responseBody 保存按序到达的 event/data/timestamp/duration 分片。敏感请求头返回脱敏值。',
88
+ ],
59
89
  examples: [
60
90
  `get_requests --payload '{"tabId":12345,"count":5}'`,
61
91
  `get_requests --payload '{"tabId":12345,"source":"mtop","filter":"cart"}'`,
@@ -81,6 +111,9 @@ export const COMMANDS = [
81
111
  description: '只返回指定 tab checkpoint 或同类查询 cursor 之后的日志',
82
112
  },
83
113
  ],
114
+ result: [
115
+ 'nextCursor 用于同类查询续读,hasMore 表示还有数据,gap 表示缓冲区淘汰造成缺口;checkpoint cursor 可分别用于三类查询的初始边界。',
116
+ ],
84
117
  examples: [`get_logs --payload '{"tabId":12345,"limit":10,"level":"error"}'`],
85
118
  },
86
119
  {
@@ -109,6 +142,13 @@ export const COMMANDS = [
109
142
  description: '返回完整 URL、_raw 和 _context;默认 false',
110
143
  },
111
144
  ],
145
+ notes: [
146
+ 'tab_open 新页从首屏采集;既有页面首次查询才启用采集,需要刷新或重新触发埋点。同批事件不会被 limit 拆开。',
147
+ ],
148
+ result: [
149
+ 'nextCursor 用于同类查询续读,hasMore 表示还有数据,gap 表示缓冲区淘汰造成缺口;checkpoint cursor 可分别用于三类查询的初始边界。',
150
+ 'captureStatus 为 armed/active/inactive;空结果附 hint 时按提示刷新或触发。默认去除 tracking URL query 与 _raw/_context,includeRaw=true 时保留。',
151
+ ],
112
152
  examples: [
113
153
  `get_events --payload '{"tabId":12345,"source":"aplus","event_type":"CLK","limit":10}'`,
114
154
  `get_events --payload '{"tabId":12345,"filter":"order","includeRaw":true,"limit":1}'`,
@@ -149,6 +189,11 @@ export const COMMANDS = [
149
189
  description: '请求 query/body 字段子集匹配;$index 从 0 开始指定调用顺序',
150
190
  },
151
191
  ],
192
+ notes: [
193
+ '启用时至少提供 mockData 或非空 fields;非空 fields 优先。fields 每项 { path: string, value: any },path 支持点号和数组索引。',
194
+ '相同 apiName 的多条无条件 Mock 会覆盖;conditions 子集匹配 query/body(含 data 内层),不同条件可共存;$index 从 0 起控制调用顺序,不参与字段匹配。',
195
+ '大字段可用顶层 @<绝对路径> 文件引用或 --payload-file;文件展开后仍受 Native Messaging 单条消息大小限制。',
196
+ ],
152
197
  examples: [
153
198
  `set_mock --payload '{"tabId":12345,"apiName":"mtop.cart.query","mockData":{"ret":["SUCCESS::调用成功"]}}'`,
154
199
  `set_mock --payload-file ./mock-data.json`,
@@ -170,38 +215,49 @@ export const COMMANDS = [
170
215
  },
171
216
  {
172
217
  name: 'set_rule',
173
- description: '添加 Chrome declarativeNetRequest 规则(重定向/修改请求头/拦截请求)',
218
+ description: '添加浏览器请求规则;enabled=false 且传 ruleId 时彻底删除规则',
174
219
  params: [
220
+ { name: 'ruleId', type: 'number', description: '删除时必填,从 get_rules 获取' },
221
+ { name: 'enabled', type: 'boolean', description: '省略时添加;false 时按 ruleId 删除' },
175
222
  {
176
223
  name: 'actionType',
177
224
  type: '"redirect" | "block" | "allow" | "upgradeScheme" | "modifyHeaders"',
178
- required: true,
179
- description: '规则动作',
225
+ description: '添加时必填,规则动作',
180
226
  },
181
- { name: 'filter', type: 'string', required: true, description: 'URL 过滤表达式' },
227
+ { name: 'filter', type: 'string', description: '添加时必填,URL 过滤表达式' },
182
228
  { name: 'redirectUrl', type: 'string', description: 'redirect 动作的目标 URL' },
183
229
  {
184
230
  name: 'requestHeaders',
185
231
  type: 'array',
186
232
  description: 'modifyHeaders 动作的请求头修改列表',
233
+ details: [
234
+ '每项 { header: string, operation: "set" | "append" | "remove", value?: string };set/append 需 value',
235
+ ],
187
236
  },
188
237
  {
189
238
  name: 'responseHeaders',
190
239
  type: 'array',
191
240
  description: 'modifyHeaders 动作的响应头修改列表',
241
+ details: [
242
+ '每项 { header: string, operation: "set" | "append" | "remove", value?: string };set/append 需 value',
243
+ ],
192
244
  },
193
245
  { name: 'initiatorDomains', type: 'string', description: '发起方域名过滤' },
194
246
  { name: 'resourceTypes', type: 'string[]', description: '资源类型过滤' },
195
247
  { name: 'priority', type: 'number', description: '规则优先级' },
196
248
  { name: 'description', type: 'string', description: '规则说明' },
197
249
  ],
250
+ notes: [
251
+ '扩展模式规则持久化;CDP 仅支持会话级 modifyHeaders 请求头 set,不支持响应头、initiatorDomains 或其他动作。Provider 是否支持以其能力声明为准。',
252
+ ],
198
253
  examples: [
199
254
  `set_rule --payload '{"actionType":"block","filter":"^https://example\\\\.com/ads/.*"}'`,
255
+ `set_rule --payload '{"ruleId":42,"enabled":false}'`,
200
256
  ],
201
257
  },
202
258
  {
203
259
  name: 'get_rules',
204
- description: '查看当前存储的全部请求规则(含 Options 面板配置的)',
260
+ description: '查看当前模式的请求规则;扩展模式包含 Options 面板配置的规则',
205
261
  examples: ['get_rules'],
206
262
  },
207
263
  // ── 网络代理 ──────────────────────────────────────────────────────────────
@@ -223,6 +279,11 @@ export const COMMANDS = [
223
279
  name: 'files',
224
280
  type: 'SendRequestFile[]',
225
281
  description: 'multipart 文件,最多 20 个、总计不超过 40 MiB;Base64 文件总计不超过 7 MiB。每项传 fieldName 和绝对 filePath,或传 base64 + filename',
282
+ details: [
283
+ 'fieldName: string(必填);filePath: string 与 base64: string 二选一',
284
+ 'filename: string,base64 时必填,filePath 时默认文件 basename',
285
+ 'contentType: string(可选),默认按文件名推断 MIME,否则 application/octet-stream',
286
+ ],
226
287
  },
227
288
  { name: 'withCookies', type: 'boolean', description: '是否附加浏览器 Cookie,默认 true' },
228
289
  {
@@ -232,6 +293,14 @@ export const COMMANDS = [
232
293
  },
233
294
  { name: 'timeout', type: 'number', description: '超时毫秒数,默认 30000' },
234
295
  ],
296
+ notes: [
297
+ '仅用于非 BUC 请求;BUC 接口使用 mearl buc,不手工传 Token、DPoP 或 Ticket。',
298
+ 'body 不能与 formData/files 组合;multipart 不手工设置 Content-Type,由 Mearl 生成 boundary。',
299
+ 'filePath 属于 native-host 所在机器;无法引用远端路径时用 base64。BUC 上传的路径属于插件执行宿主。',
300
+ ],
301
+ result: [
302
+ '返回 status、statusText、headers、body、bodyType、attachedCookieCount;bodyType 为 json/text/base64,二进制 body 需解码后保存。',
303
+ ],
235
304
  examples: [
236
305
  `send_request --payload '{"url":"https://api.example.com/data","method":"GET"}'`,
237
306
  `send_request --payload '{"url":"https://api.example.com/upload","method":"POST","formData":{"folder":"assets"},"files":[{"fieldName":"file","filePath":"/absolute/path/image.png"}]}'`,
@@ -249,6 +318,11 @@ export const COMMANDS = [
249
318
  { name: 'env', type: '"prod" | "pre"', description: '请求环境,默认 prod' },
250
319
  { name: 'timeout', type: 'number', description: '超时毫秒数,默认 10000' },
251
320
  ],
321
+ notes: [
322
+ '需要目标浏览器有对应登录态;Mearl 自动处理签名,不依赖页面脚本。api 以 mopen. 开头时使用 mopen 协议。',
323
+ 'env=prod 使用 h5api.m.taobao.com,pre 使用 h5api.wapa.taobao.com。',
324
+ ],
325
+ result: ['返回 success、response、requestData;业务成功需检查 response.ret。'],
252
326
  examples: [
253
327
  `send_mtop_request --payload '{"api":"mtop.trade.order.detail","data":{"orderId":"123"}}'`,
254
328
  ],
@@ -398,6 +472,15 @@ export const COMMANDS = [
398
472
  description: '与 appProfile 配合;声明式覆盖桥方法,形如 {methods:{api:{behavior|response|noop,silent?}}}',
399
473
  },
400
474
  ],
475
+ notes: [
476
+ 'emulation / appProfile 只应用到新建 Tab;复用 Tab 要切换状态时用对应设置 action。',
477
+ 'closeExisting 不能与复用或 openerTabId 组合;多匹配默认报错,match.onMultiple=first 可显式选择第一个。',
478
+ ],
479
+ result: [
480
+ '返回 tabId、url、title、opened/reused;reused=true 的既有页面应保留。',
481
+ 'active=true 时 activation 包含 tabActive、windowFocused、windowState、visibilityState;emulation 返回实际生效配置。',
482
+ 'capture.cursor 是导航前诊断边界,可分别用于 get_logs/get_requests/get_events 的 after。',
483
+ ],
401
484
  examples: [
402
485
  `tab_open --payload '{"url":"https://example.com"}'`,
403
486
  `tab_open --payload '{"url":"https://example.com/page","reuse":"prefer","match":{"ignoreSearch":true}}'`,
@@ -498,6 +581,11 @@ export const COMMANDS = [
498
581
  PAGE_DIAGNOSTICS_PARAM,
499
582
  { name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
500
583
  ],
584
+ result: PAGE_ACTION_RESULT,
585
+ notes: [
586
+ 'selector / text / point 必须且只能提供一个。隐藏页 auto 使用 DOM;只有明确依赖真实用户手势时才激活页面。',
587
+ '原生 select 可按 option 文本点击;checkbox/radio 返回 controlState.checkedBefore/checkedAfter。',
588
+ ],
501
589
  examples: [
502
590
  `page_click --payload '{"tabId":12345,"text":"提交"}'`,
503
591
  `page_click --payload '{"tabId":12345,"text":"退款明细","role":"button"}'`,
@@ -539,6 +627,10 @@ export const COMMANDS = [
539
627
  PAGE_DIAGNOSTICS_PARAM,
540
628
  { name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
541
629
  ],
630
+ result: PAGE_ACTION_RESULT,
631
+ notes: [
632
+ '起点会自动滚入视口,终点必须同时位于当前视口;否则先滚动页面。隐藏页 auto 使用 DOM,不切换活动页。',
633
+ ],
542
634
  examples: [
543
635
  `page_drag --payload '{"tabId":12345,"from":{"x":350,"y":80},"to":{"x":80,"y":80}}'`,
544
636
  `page_drag --payload '{"tabId":12345,"from":"@e3","to":"#drop-zone","dragMode":"mouse"}'`,
@@ -560,6 +652,7 @@ export const COMMANDS = [
560
652
  PAGE_DIAGNOSTICS_PARAM,
561
653
  { name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
562
654
  ],
655
+ result: PAGE_ACTION_RESULT,
563
656
  examples: [`page_type --payload '{"tabId":12345,"selector":"@e6","text":"搜索关键词"}'`],
564
657
  },
565
658
  {
@@ -576,6 +669,7 @@ export const COMMANDS = [
576
669
  PAGE_DIAGNOSTICS_PARAM,
577
670
  { name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
578
671
  ],
672
+ result: PAGE_ACTION_RESULT,
579
673
  examples: [`page_hover --payload '{"tabId":12345,"selector":".nav-menu"}'`],
580
674
  },
581
675
  {
@@ -603,6 +697,10 @@ export const COMMANDS = [
603
697
  PAGE_DIAGNOSTICS_PARAM,
604
698
  { name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
605
699
  ],
700
+ result: [
701
+ ...PAGE_ACTION_RESULT,
702
+ 'action.data 返回 moved、atTop/atBottom、scrollYBefore/After、maxScrollY、resolvedContainer 和 ancestorDistance;自动发现的内部容器提供可复用 containerSelector。',
703
+ ],
606
704
  examples: [
607
705
  `page_scroll --payload '{"tabId":12345,"direction":"down"}'`,
608
706
  `page_scroll --payload '{"tabId":12345,"direction":"bottom"}'`,
@@ -621,13 +719,22 @@ export const COMMANDS = [
621
719
  description: '表达式返回 Promise 时等待完成,默认 true',
622
720
  },
623
721
  {
624
- name: 'observe',
722
+ name: 'frameId',
723
+ type: 'string',
724
+ description: 'page_frames 返回的目标 frame ID,扩展/CDP 均支持;省略时容器/设备外壳使用当前业务 frame,普通页面使用主 frame',
725
+ },
726
+ {
727
+ ...PAGE_OBSERVE_PARAM,
625
728
  type: 'object',
626
729
  description: '仅在表达式会修改页面且需要观察结果时显式传入;不传保持轻量裸执行',
627
730
  },
628
731
  PAGE_DIAGNOSTICS_PARAM,
629
732
  { name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
630
733
  ],
734
+ notes: ['优先使用结构化 action;仅在其无法表达需求时执行最小范围脚本。'],
735
+ result: [
736
+ '默认返回 { result };observe 对象启用观察并返回 { action, observation };仅开启 diagnostics 时返回 { action, diagnostics }。diagnostics=false 不启用包装。失败阶段语义同 page_click。',
737
+ ],
631
738
  examples: [`page_eval --payload '{"tabId":12345,"expression":"document.title"}'`],
632
739
  },
633
740
  {
@@ -661,6 +768,10 @@ export const COMMANDS = [
661
768
  },
662
769
  { name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
663
770
  ],
771
+ result: [
772
+ 'matches[] 包含 boundingBox、computedStyle、hitTest、scroll 溢出量及可用的 scrollContainer。receivesPointerEvents=false 时读取 occludedBy。',
773
+ '$0 还返回 resolvedSelector、属性、XPath 和可用框架信息。',
774
+ ],
664
775
  examples: [
665
776
  `page_inspect --payload '{"tabId":12345,"selector":".form-field","styles":["display","width"]}'`,
666
777
  `page_inspect --payload '{"tabId":12345,"selector":"@e8"}'`,
@@ -689,6 +800,13 @@ export const COMMANDS = [
689
800
  PAGE_DIAGNOSTICS_PARAM,
690
801
  { name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
691
802
  ],
803
+ notes: [
804
+ '隐藏页 DOM 模式支持 Tab 焦点移动、原生控件 Enter/Space 激活和输入框 Enter 提交;编辑、选择、方向键和页面滚动等原生行为需可见页与 pressMode=keyboard。',
805
+ ],
806
+ result: [
807
+ ...PAGE_ACTION_RESULT,
808
+ 'action.data.dispatchMode / fallbackReason / defaultAction 说明实际输入路径。',
809
+ ],
692
810
  examples: [`page_press --payload '{"tabId":12345,"key":"Enter"}'`],
693
811
  },
694
812
  {
@@ -721,6 +839,9 @@ export const COMMANDS = [
721
839
  { name: 'interval', type: 'number', description: '轮询间隔毫秒数,默认 200' },
722
840
  { name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
723
841
  ],
842
+ notes: [
843
+ 'time / selector / text / condition 必须且只能提供一个;time 范围 0–60000ms。页面交互已有内置观察,仅在需要独立等待条件时使用。',
844
+ ],
724
845
  examples: [
725
846
  `page_wait --payload '{"tabId":12345,"time":1000}'`,
726
847
  `page_wait --payload '{"tabId":12345,"selector":".dialog","state":"visible"}'`,
@@ -750,6 +871,7 @@ export const COMMANDS = [
750
871
  },
751
872
  { name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
752
873
  ],
874
+ notes: ['url / refresh=true / history 必须且只能提供一个。'],
753
875
  examples: [
754
876
  `page_navigate --payload '{"tabId":12345,"url":"https://example.com/page2"}'`,
755
877
  `page_navigate --payload '{"tabId":12345,"refresh":true}'`,
@@ -771,6 +893,10 @@ export const COMMANDS = [
771
893
  PAGE_DIAGNOSTICS_PARAM,
772
894
  { name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
773
895
  ],
896
+ result: PAGE_ACTION_RESULT,
897
+ notes: [
898
+ '直接写入 input[type=file],不依赖 file chooser;隐藏的文件节点也可上传。外部 Provider 的文件中转能力查询 mearl <providerId>。',
899
+ ],
774
900
  examples: [
775
901
  `page_upload --payload '{"tabId":12345,"selector":"#file-input","filePaths":["/Users/me/photo.jpg"]}'`,
776
902
  ],
@@ -814,6 +940,14 @@ export const COMMANDS = [
814
940
  },
815
941
  { name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
816
942
  ],
943
+ notes: [
944
+ 'query.text / query.role 至少提供一个;query.exact 默认 true。每次快照刷新有效 ref 集合。',
945
+ 'interactive 无 AX 控件时回退到 viewport,不会自动改用 dom;Canvas 内容需截图。',
946
+ ],
947
+ result: [
948
+ '返回 snapshot、elementCount、outputNodeCount、mode;截断时 truncated=true。',
949
+ 'query 返回 matches 与完整 matchCount,matches 最多 100 项,裁剪时 matchesTruncated=true。容器/iframe 的视口裁剪返回 outerViewport、contentViewport 和滚动位置。',
950
+ ],
817
951
  examples: [
818
952
  `page_snapshot --payload '{"tabId":12345}'`,
819
953
  `page_snapshot --payload '{"tabId":1,"mode":"viewport"}'`,
@@ -833,6 +967,12 @@ export const COMMANDS = [
833
967
  { name: 'quality', type: 'number', description: 'JPEG 压缩质量(0-100),默认 80' },
834
968
  { name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
835
969
  ],
970
+ notes: [
971
+ '使用 --output <path> 保存图片;省略时 stdout 返回含 base64 data 的 JSON,避免直接将其加载为文本。',
972
+ ],
973
+ result: [
974
+ 'meta 包含 format、width、height、size、url、title;宽高为物理像素(CSS 尺寸 × DPR)。',
975
+ ],
836
976
  examples: [
837
977
  `page_screenshot --payload '{"tabId":12345}' --output ./screenshot.png`,
838
978
  `page_screenshot --payload '{"tabId":12345,"selector":".product-card"}' --output ./card.png`,
@@ -883,6 +1023,13 @@ export const COMMANDS = [
883
1023
  { name: 'reload', type: 'boolean', description: '启用后是否重载页面,默认 true' },
884
1024
  { name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
885
1025
  ],
1026
+ notes: [
1027
+ '无 preset 时 width/height 必须成对提供且 userAgent 必填;mobile 默认 true,touch 跟随 mobile。',
1028
+ 'deviceShell 开启/移除时必须重载;splitScreen 仅在已启用 App 档案、deviceShell=true、横屏时生效。',
1029
+ ],
1030
+ result: [
1031
+ '返回实际 viewport(width/height/deviceScaleFactor/scale)、UA、mobile、touch、orientation、deviceShell、splitScreen 和 reloaded;应以响应确认生效状态。',
1032
+ ],
886
1033
  examples: [
887
1034
  `set_device_emulation --payload '{"tabId":12345,"enabled":true,"preset":"iphone-17-pro"}'`,
888
1035
  `set_device_emulation --payload '{"tabId":12345,"enabled":true,"preset":"pixel-11","orientation":"landscape"}'`,
@@ -926,6 +1073,14 @@ export const COMMANDS = [
926
1073
  { name: 'reload', type: 'boolean', description: '应用/清除后是否重载页面,默认 true' },
927
1074
  { name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
928
1075
  ],
1076
+ notes: [
1077
+ '只有用户明确要求 App/客户端/容器/JSBridge 模拟时启用。移动视口或普通 H5 调试使用 set_device_emulation。',
1078
+ 'emulation={} 使用档案推荐设备;enabled=false 时省略 emulation 只清除 App 注入,传 {} 同时清除设备模拟。',
1079
+ 'bridgeConfig.methods 按方法声明 behavior / response / noop 三选一,可传 silent;只支持受控行为、固定 JSON 回包或成功空实现,不执行配置脚本。',
1080
+ ],
1081
+ result: [
1082
+ '返回 enabled、profile、label、userAgent、os、mtopEnv、reloaded;联动设备时额外返回实际 emulation。',
1083
+ ],
929
1084
  examples: [
930
1085
  `set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"fliggy"}'`,
931
1086
  `set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"fliggy","mtopEnv":"pre"}'`,
@@ -958,7 +1113,11 @@ export const COMMANDS = [
958
1113
  name: 'get_cookie',
959
1114
  description: '从目标浏览器读取一个指定非分区 Cookie;拒绝返回 HttpOnly Cookie',
960
1115
  params: [
961
- { name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
1116
+ {
1117
+ name: 'tabId',
1118
+ type: 'number',
1119
+ description: '可选;指定标签页的 Cookie 存储区,省略时使用浏览器默认存储区',
1120
+ },
962
1121
  {
963
1122
  name: 'name',
964
1123
  type: 'string',
@@ -968,7 +1127,7 @@ export const COMMANDS = [
968
1127
  {
969
1128
  name: 'url',
970
1129
  type: 'string',
971
- description: '可选 Cookie 查询 URL;省略时使用当前标签页 URL',
1130
+ description: 'Cookie 查询 URL;未传 tabId 时必填,省略时使用指定标签页 URL',
972
1131
  },
973
1132
  {
974
1133
  name: 'domain',
@@ -977,17 +1136,31 @@ export const COMMANDS = [
977
1136
  },
978
1137
  { name: 'path', type: 'string', description: '可选精确 path 过滤' },
979
1138
  ],
1139
+ notes: [
1140
+ '只读取指定非分区 Cookie,不列举全部、不回退分区 Cookie,拒绝 HttpOnly;禁止读取认证 Token。指定 url 不导航,指定 tabId 仅选择存储区时不启动采集。',
1141
+ ],
1142
+ result: ['找到时 found=true 并返回 value/domain/path;不存在时 found=false。'],
980
1143
  examples: [
981
1144
  `get_cookie --payload '{"tabId":12345,"name":"feature_flag"}'`,
1145
+ `get_cookie --payload '{"url":"https://www.taobao.com/","name":"tracknick"}'`,
982
1146
  `get_cookie --payload '{"tabId":12345,"name":"edith_switch_br.rx-vehicle-search_home","domain":"taobao.com"}'`,
983
1147
  `get_cookie --payload '{"tabId":12345,"name":"tracknick","url":"https://www.taobao.com/","domain":"taobao.com","path":"/"}'`,
984
1148
  ],
985
1149
  },
986
1150
  {
987
1151
  name: 'set_cookie',
988
- description: '设置当前标签页域下的一个指定非分区 session Cookie,可选刷新页面',
1152
+ description: '在目标浏览器设置一个指定非分区 session Cookie,可选刷新指定页面',
989
1153
  params: [
990
- { name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
1154
+ {
1155
+ name: 'tabId',
1156
+ type: 'number',
1157
+ description: '可选;指定标签页的 Cookie 存储区,reload=true 时必填',
1158
+ },
1159
+ {
1160
+ name: 'url',
1161
+ type: 'string',
1162
+ description: 'Cookie 目标 URL;未传 tabId 时必填,省略时使用指定标签页 URL',
1163
+ },
991
1164
  {
992
1165
  name: 'name',
993
1166
  type: 'string',
@@ -1003,13 +1176,20 @@ export const COMMANDS = [
1003
1176
  {
1004
1177
  name: 'domain',
1005
1178
  type: 'string',
1006
- description: 'Cookie 域,默认当前 host;只允许当前 host 或其父域',
1179
+ description: 'Cookie 域,默认目标 URL 的 host;只允许目标 host 或其父域',
1007
1180
  },
1008
1181
  { name: 'path', type: 'string', description: 'Cookie path,默认 /' },
1009
- { name: 'reload', type: 'boolean', description: '设置后是否刷新页面,默认 false' },
1182
+ {
1183
+ name: 'reload',
1184
+ type: 'boolean',
1185
+ description: '设置后是否刷新指定 tabId,默认 false;true 时必须传 tabId',
1186
+ },
1010
1187
  ],
1188
+ notes: ['仅写非分区 session Cookie,不支持删除。reload=true 时校验目标域与刷新页域的授权。'],
1189
+ result: ['返回 url/name/domain/path/reloaded,指定标签页时包含 tabId;不回显 Cookie 值。'],
1011
1190
  examples: [
1012
1191
  `set_cookie --payload '{"tabId":12345,"name":"feature_flag","value":"enabled"}'`,
1192
+ `set_cookie --payload '{"url":"https://www.taobao.com/","name":"feature_flag","value":"enabled"}'`,
1013
1193
  `set_cookie --payload '{"tabId":12345,"name":"edith_switch_br.rx-vehicle-search_home","value":"3.6.63","domain":"taobao.com","reload":true}'`,
1014
1194
  ],
1015
1195
  },
@@ -1018,6 +1198,9 @@ export const COMMANDS = [
1018
1198
  name: 'page_frames',
1019
1199
  description: '获取页面主 frame 与所有 iframe 列表',
1020
1200
  params: [{ name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' }],
1201
+ result: [
1202
+ 'frames[] 包含 frameId、url、name 和 isMainFrame;frameId 可用于 page_eval 等支持 frame 定位的 action。',
1203
+ ],
1021
1204
  examples: [`page_frames --payload '{"tabId":12345}'`],
1022
1205
  },
1023
1206
  {
@@ -1031,6 +1214,11 @@ export const COMMANDS = [
1031
1214
  description: '需要授权的域名,如 example.com',
1032
1215
  },
1033
1216
  ],
1217
+ notes: [
1218
+ 'domain 使用纯主机名,不传 URL。仅在非 BUC send_request 报域权限缺失时申请,BUC 不使用浏览器域权限。',
1219
+ '弹窗等待用户选择,90 秒超时或关闭按拒绝处理;granted=true 后才重试原请求。',
1220
+ ],
1221
+ result: ['返回 granted、domain,授权成功时包含 origin。'],
1034
1222
  examples: [`request_domain_permission --payload '{"domain":"example.com"}'`],
1035
1223
  },
1036
1224
  // ── 组合调用 ────────────────────────────────────────────────────────────────
@@ -1052,8 +1240,12 @@ export const COMMANDS = [
1052
1240
  description: '所有步骤共享的 tabId,步骤自身指定的优先',
1053
1241
  },
1054
1242
  ],
1243
+ notes: ['最多 50 步,不允许嵌套 run_actions;需要根据每步效果决策时逐步调用普通 action。'],
1244
+ result: [
1245
+ '返回 results、completedSteps、totalSteps;失败时包含 error/failedStep,后续步骤未执行。',
1246
+ ],
1055
1247
  examples: [
1056
- `run_actions --payload '{"tabId":12345,"actions":[{"action":"page_scroll","data":{"direction":"down"}},{"action":"page_wait","data":{"time":500}},{"action":"page_screenshot"}]}'`,
1248
+ `run_actions --payload '{"tabId":12345,"actions":[{"action":"page_hover","data":{"selector":"#menu"}},{"action":"page_click","data":{"selector":"#menu-item"}}]}'`,
1057
1249
  ],
1058
1250
  },
1059
1251
  ];
@@ -319,7 +319,8 @@ export interface BrowserAccessResult {
319
319
  sensitive: true;
320
320
  };
321
321
  }
322
- export interface SetRuleParams {
322
+ export interface AddRuleParams {
323
+ enabled?: true;
323
324
  actionType: 'redirect' | 'block' | 'allow' | 'upgradeScheme' | 'modifyHeaders';
324
325
  filter: string;
325
326
  redirectUrl?: string;
@@ -338,6 +339,11 @@ export interface SetRuleParams {
338
339
  priority?: number;
339
340
  description?: string;
340
341
  }
342
+ export interface DeleteRuleParams {
343
+ enabled: false;
344
+ ruleId: number;
345
+ }
346
+ export type SetRuleParams = AddRuleParams | DeleteRuleParams;
341
347
  export interface RulesResult {
342
348
  enabled: boolean;
343
349
  rules: Array<Record<string, unknown>>;
@@ -610,9 +616,10 @@ export interface SetTimezoneResult {
610
616
  timezone: string | null;
611
617
  }
612
618
  export interface GetCookieParams {
613
- tabId: number;
619
+ /** Select the tab's cookie store; omitted for the browser's default store. */
620
+ tabId?: number;
614
621
  name: string;
615
- /** Cookie lookup URL; defaults to the current tab URL. */
622
+ /** Cookie lookup URL; required without tabId, otherwise defaults to the tab URL. */
616
623
  url?: string;
617
624
  domain?: string;
618
625
  path?: string;
@@ -627,9 +634,12 @@ export interface GetCookieResult {
627
634
  path?: string;
628
635
  }
629
636
  export interface SetCookieParams {
630
- tabId: number;
637
+ /** Select the tab's cookie store; required when reload is true. */
638
+ tabId?: number;
631
639
  name: string;
632
640
  value: string;
641
+ /** Cookie target URL; required when tabId is omitted. */
642
+ url?: string;
633
643
  domain?: string;
634
644
  path?: string;
635
645
  reload?: boolean;
@@ -826,7 +836,7 @@ export type BrowserActionRequest<A extends BrowserAction> = BrowserActionMap[A][
826
836
  export type BrowserActionResponse<A extends BrowserAction> = BrowserActionMap[A]['response'];
827
837
  export type BrowserCommandAction = Exclude<BrowserAction, 'browser_select_browser'>;
828
838
  export type ExtensionBrowserAction = Exclude<BrowserCommandAction, 'browser_list' | 'browser_launch' | 'browser_close'>;
829
- export declare const TAB_ID_REQUIRED_ACTIONS: readonly ["tab_checkpoint", "capture_checkpoint", "get_requests", "get_logs", "get_events", "set_mock", "get_mocks", "page_screenshot", "tab_close", "page_click", "page_drag", "page_type", "page_scroll", "page_hover", "page_eval", "page_inspect", "page_snapshot", "page_press", "page_wait", "page_navigate", "page_upload", "page_frames", "set_device_emulation", "set_app_profile", "set_timezone", "get_cookie", "set_cookie", "run_actions"];
839
+ export declare const TAB_ID_REQUIRED_ACTIONS: readonly ["tab_checkpoint", "capture_checkpoint", "get_requests", "get_logs", "get_events", "set_mock", "get_mocks", "page_screenshot", "tab_close", "page_click", "page_drag", "page_type", "page_scroll", "page_hover", "page_eval", "page_inspect", "page_snapshot", "page_press", "page_wait", "page_navigate", "page_upload", "page_frames", "set_device_emulation", "set_app_profile", "set_timezone", "run_actions"];
830
840
  export type TabIdRequiredAction = (typeof TAB_ID_REQUIRED_ACTIONS)[number];
831
841
  export declare function actionRequiresTabId(action: unknown): action is TabIdRequiredAction;
832
842
  export declare function validateRequiredActionTabId(action: string, data: unknown): void;
@@ -76,8 +76,6 @@ export const TAB_ID_REQUIRED_ACTIONS = [
76
76
  'set_device_emulation',
77
77
  'set_app_profile',
78
78
  'set_timezone',
79
- 'get_cookie',
80
- 'set_cookie',
81
79
  'run_actions',
82
80
  ];
83
81
  const TAB_ID_REQUIRED_ACTION_SET = new Set(TAB_ID_REQUIRED_ACTIONS);
@@ -85,11 +83,22 @@ export function actionRequiresTabId(action) {
85
83
  return typeof action === 'string' && TAB_ID_REQUIRED_ACTION_SET.has(action);
86
84
  }
87
85
  export function validateRequiredActionTabId(action, data) {
88
- if (!actionRequiresTabId(action))
86
+ const cookieAction = action === 'get_cookie' || action === 'set_cookie';
87
+ if (!actionRequiresTabId(action) && !cookieAction)
89
88
  return;
90
- const tabId = data && typeof data === 'object' && !Array.isArray(data)
91
- ? data.tabId
89
+ const input = data && typeof data === 'object' && !Array.isArray(data)
90
+ ? data
92
91
  : undefined;
92
+ const tabId = input?.tabId;
93
+ if (cookieAction && tabId === undefined) {
94
+ if (action === 'set_cookie' && input?.reload === true) {
95
+ throw new Error('set_cookie: reload requires tabId');
96
+ }
97
+ if (typeof input?.url !== 'string' || !input.url.trim()) {
98
+ throw new Error(`${action}: specify url or tabId`);
99
+ }
100
+ return;
101
+ }
93
102
  if (typeof tabId !== 'number' || !Number.isSafeInteger(tabId) || tabId < 0) {
94
103
  throw new Error(`${action} requires a numeric tabId. Call tab_open or tab_list to obtain a tabId.`);
95
104
  }
package/dist/plugin.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { type OfficialPluginInstaller } from './officialPluginInstaller.js';
2
- import { type PluginToolboxContribution } from './pluginRegistry.js';
2
+ import { type PluginToolboxContribution, type PluginRegistration } from './pluginRegistry.js';
3
3
  import type { UnifiedInvokeOptions } from './unified.js';
4
4
  export { assertPluginName, findPluginDirectoryEntry, findPluginEntry, findPluginRegistration, listPluginNames, registerPlugin, resolvePluginEntry, unregisterPlugin, PluginError, readPluginPageBundleChunk, type PluginRegistration, type PluginRegistrationOptions, type PluginToolboxAgentConfig, type PluginPageBundleRegistration, type PluginToolboxContribution, type PluginToolboxLocale, type PluginToolboxSandboxPage, } from './pluginRegistry.js';
5
5
  export { findOfficialPlugin, listOfficialPluginNames, OFFICIAL_PLUGIN_MANAGER, OFFICIAL_PLUGINS, type OfficialPluginDefinition, type OfficialPluginName, } from './officialPluginCatalog.js';
@@ -22,11 +22,14 @@ export interface PluginExecutionContext {
22
22
  }
23
23
  export interface PluginApp {
24
24
  readonly options: Readonly<PluginOptions>;
25
- command(signature: string, handler: PluginHandler, description?: string): void;
25
+ /** Examples omit the `mearl <plugin>` prefix, which help adds when displayed. */
26
+ command(signature: string, handler: PluginHandler, description?: string, examples?: string[]): void;
26
27
  invoke(action: string, payload?: Record<string, any>, options?: UnifiedInvokeOptions): Promise<any>;
27
28
  progress(progress: PluginProgress): void;
28
29
  }
29
30
  export type PluginHandler = (input: Record<string, any>) => unknown | Promise<unknown>;
31
+ /** 工具列表仅检查入口;页面资源只在打开对应工具时检查。 */
32
+ export declare function refreshRegisteredPlugin(name: string, includePage?: boolean): Promise<PluginRegistration | undefined>;
30
33
  /** 注册和执行复用同一宿主能力边界;仅 handler 执行期间开放浏览器调用。 */
31
34
  export declare function loadPlugin(entry: string, context: Pick<PluginApp, 'invoke' | 'options' | 'progress'>, pluginName?: string): Promise<{
32
35
  name: string | undefined;