@mearl/client 2.0.1 → 2.0.2

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 CHANGED
@@ -72,23 +72,25 @@ mearl browser_list
72
72
 
73
73
  ## 支持的操作
74
74
 
75
- | 分类 | Actions |
76
- | ----------- | -------------------------------------------------------------------------------------------------------------------- |
77
- | API 调试 | `get_requests` `get_logs` `get_events` `get_api_schema` |
78
- | Mock & 规则 | `set_mock` `get_mocks` `set_rule` `get_rules` |
79
- | 网络代理 | `send_request` `send_mtop_request` |
80
- | 标签页 | `tab_open` `tab_close` `tab_list` |
81
- | 页面操作 | `page_click` `page_type` `page_scroll` `page_eval` `page_press` `page_wait` `page_navigate` `page_upload` |
82
- | 页面感知 | `page_snapshot` `page_screenshot` `page_selected_element` `page_frames` |
83
- | 环境模拟 | `set_device_emulation` `set_timezone` |
84
- | 用户信息 | `get_user_info` |
85
- | 录制 | `record_start` `record_stop` |
86
- | TDBank | `tdbank_account` |
87
- | 浏览器 | `browser_list` `browser_launch` `browser_close` |
88
-
89
- 页面交互动作(`page_click` / `page_type` / `page_hover` / `page_scroll` / `page_press` / `page_upload`)默认内置观察:同一次调用内执行动作并等待异步稳定,返回 `{ action, observation }`;传 `observe: false` 可关闭观察仅执行裸动作。观察结果不替代完整页面理解:`mode: "delta"` 只返回主文档中的 `effects.notifications`、`effects.interactives` 和 `effects.focus` 等高置信度信号,并明确携带 `scope: "main-document"`;`mode: "navigation"` 且 `ready: true` 时,页面已通过网络静默、骨架状态或保守的内容稳定判定,可在新页面重建快照。仅在 `fullSnapshotRecommended` 为 true 时根据 `snapshotReasons` 回退到完整快照或截图。
90
-
91
- `page_snapshot` 默认返回完整 AX Tree;长列表可传 `mode: "viewport"`,只需要控件时传 `mode: "interactive"`,已知区域时传 `rootSelector`。页面缺少 AX 控件语义时,`interactive` 会自动回退到 viewport,并返回 `fallbackMode: "viewport"`。`maxNodes` / `maxChars` 截断会同时保留首尾内容。
75
+ | 分类 | Actions |
76
+ | ----------- | --------------------------------------------------------------------------------------------------------- |
77
+ | API 调试 | `get_requests` `get_logs` `get_events` `get_api_schema` |
78
+ | Mock & 规则 | `set_mock` `get_mocks` `set_rule` `get_rules` |
79
+ | 网络代理 | `send_request` `send_mtop_request` |
80
+ | 标签页 | `tab_open` `tab_close` `tab_list` |
81
+ | 页面操作 | `page_click` `page_type` `page_scroll` `page_eval` `page_press` `page_wait` `page_navigate` `page_upload` |
82
+ | 页面感知 | `page_snapshot` `page_screenshot` `page_selected_element` `page_frames` |
83
+ | 环境模拟 | `set_device_emulation` `set_timezone` |
84
+ | 用户信息 | `get_user_info` |
85
+ | 录制 | `record_start` `record_stop` |
86
+ | TDBank | `tdbank_account` |
87
+ | 浏览器 | `browser_list` `browser_launch` `browser_close` |
88
+
89
+ 页面交互动作(`page_click` / `page_type` / `page_hover` / `page_scroll` / `page_press` / `page_upload`)默认内置观察:同一次调用内执行动作并等待异步稳定,返回 `{ action, observation }`;传 `observe: false` 可关闭观察仅执行裸动作。观察结果不替代完整页面理解:`mode: "delta"` 只返回主文档中的 `effects.notifications`、`effects.interactives` 和 `effects.focus` 等高置信度信号,并明确携带 `scope: "main-document"`;可交互节点会尽量携带真实 backend `node.ref`,后续动作优先使用 ref,缺少 ref 时使用 `node.selector`。`mode: "navigation"` 且 `ready: true` 时,页面已通过网络静默、骨架状态或保守的内容稳定判定,可在新页面重建快照。通常仅在 `fullSnapshotRecommended` 为 true 时根据 `snapshotReasons` 回退;滚动后若下一步需要读取新视口内容,可按需获取 viewport 快照。`page_eval` 默认裸执行,只有显式传入 `observe` 对象时才启用观察。
90
+
91
+ `page_snapshot` 默认返回完整 AX Tree;长列表可传 `mode: "viewport"`,只需要当前视口内的控件时传 `mode: "interactive"`,已知 CSS 区域时传 `rootSelector`,已有 ref 时传 `rootRef`(可用 `ancestorDepth` 向上补充上下文),只查找特定文案或角色时传 `query`。视口内缺少 AX 控件语义时,`interactive` 会自动回退到 viewport,并返回 `fallbackMode: "viewport"`。`maxNodes` / `maxChars` 截断会同时保留首尾内容。
92
+
93
+ 重复文本点击可用 `page_click.scope` 限定 CSS / ref 子树;ref 指向滚动容器内的子节点时,可用 `page_scroll.containerPolicy: "nearest"` 自动解析最近可滚动祖先。`page_click.clickMode` 默认 `auto`:可见桌面页派发可信 mouse,移动模拟页派发可信 touch;隐藏页使用 DOM fallback,返回 `dispatchMode: "dom"` 和 `fallbackReason: "page-hidden"`,且不切换标签或还原窗口。可用 `dom` / `mouse` / `touch` 覆盖自动策略;可信输入返回实际 `pointerType`。点击结果的 `resolvedTarget` 和滚动结果的前后位置、边界字段可用于诊断实际派发目标与滚动效果。
92
94
 
93
95
  `browser_list` 统一列出普通浏览器和托管浏览器。`type` 区分 `regular` / `managed`,`status` 区分 `connected` / `running_disconnected` / `stopped`;只有 `connected` 的浏览器可作为操作目标。
94
96
 
@@ -33,6 +33,8 @@ export function resolveActionTimeoutSec(action, data, fallback = 15) {
33
33
  const waitMs = data.time ?? data.timeout ?? 10000;
34
34
  return Math.max(fallback, Math.ceil((Number(waitMs) + 5000) / 1000));
35
35
  }
36
+ if (action === 'tab_open')
37
+ return Math.max(fallback, 40);
36
38
  if (action === 'browser_launch')
37
39
  return Math.max(fallback, 90);
38
40
  if (action === 'browser_close' || action === 'tdbank_account')
package/dist/commands.js CHANGED
@@ -43,9 +43,15 @@ export const COMMANDS = [
43
43
  { name: 'filter', type: 'string', description: '按 name 或 url 过滤,支持正则' },
44
44
  { name: 'since', type: 'number', description: '只返回最近 N 秒内的事件' },
45
45
  { name: 'limit', type: 'number', description: '返回条数,默认 20' },
46
+ {
47
+ name: 'includeRaw',
48
+ type: 'boolean',
49
+ description: '返回完整 URL、_raw 和 _context;默认 false',
50
+ },
46
51
  ],
47
52
  examples: [
48
53
  `get_events --payload '{"source":"aplus","event_type":"CLK","limit":10}'`,
54
+ `get_events --payload '{"filter":"order","includeRaw":true,"limit":1}'`,
49
55
  `get_events --payload '{"tabId":12345,"source":"all","limit":20}'`,
50
56
  ],
51
57
  },
@@ -285,12 +291,12 @@ export const COMMANDS = [
285
291
  // ── 页面操作 ──────────────────────────────────────────────────────────────
286
292
  {
287
293
  name: 'page_click',
288
- description: '点击页面元素,支持 selector / text / point 三种定位方式;默认等待异步稳定并返回页面变化信号',
294
+ description: '点击页面元素,支持 selector / text / point 三种定位方式;auto 在可见页按设备模拟状态使用可信 mouse/touch,隐藏页使用 DOM fallback',
289
295
  params: [
290
296
  {
291
297
  name: 'selector',
292
298
  type: 'string',
293
- description: '原生 CSS 选择器,或 @eN 形式的 snapshot ref(来自 page_snapshot,必须带 @ 前缀)。不支持 :has-text/:visible 等 Playwright 私有伪类',
299
+ description: '原生 CSS 选择器,或 page_snapshot / 页面动作 observation 返回的 @eN ref(必须带 @ 前缀)。不支持 :has-text/:visible 等 Playwright 私有伪类',
294
300
  },
295
301
  {
296
302
  name: 'text',
@@ -313,9 +319,14 @@ export const COMMANDS = [
313
319
  description: '配合 text 使用,默认 true 精确匹配;false 时按子串匹配',
314
320
  },
315
321
  {
316
- name: 'clickType',
317
- type: '"js" | "cdp"',
318
- description: '点击方式,默认 js(对 selector/@ref 调用 el.click());cdp 走真实 mouse/touch 事件',
322
+ name: 'scope',
323
+ type: 'string',
324
+ description: '配合 text 使用,把文本匹配限制在指定 CSS 元素或 @eN ref 子树内,适合消除重复文案歧义',
325
+ },
326
+ {
327
+ name: 'clickMode',
328
+ type: '"auto" | "dom" | "mouse" | "touch"',
329
+ description: '点击模式;auto 在可见页按设备模拟状态选择可信 mouse/touch、隐藏页走 DOM,checkbox/radio 校验状态;其他值强制指定派发方式',
319
330
  },
320
331
  {
321
332
  name: 'observe',
@@ -327,8 +338,10 @@ export const COMMANDS = [
327
338
  examples: [
328
339
  `page_click --payload '{"text":"提交"}'`,
329
340
  `page_click --payload '{"text":"退款明细","role":"button"}'`,
341
+ `page_click --payload '{"text":"确定","scope":"@e12"}'`,
330
342
  `page_click --payload '{"selector":"@e3"}'`,
331
343
  `page_click --payload '{"selector":".submit-btn"}'`,
344
+ `page_click --payload '{"selector":".gesture-btn","clickMode":"touch"}'`,
332
345
  `page_click --payload '{"point":{"x":336,"y":117}}'`,
333
346
  ],
334
347
  },
@@ -340,7 +353,7 @@ export const COMMANDS = [
340
353
  name: 'selector',
341
354
  type: 'string',
342
355
  required: true,
343
- description: '原生 CSS 选择器或 @eN snapshot ref(必须带 @ 前缀)',
356
+ description: '原生 CSS 选择器,或 page_snapshot / 页面动作 observation 返回的 @eN ref(必须带 @ 前缀)',
344
357
  },
345
358
  { name: 'text', type: 'string', required: true, description: '要填写的文本' },
346
359
  { name: 'clearFirst', type: 'boolean', description: '是否先清空原有内容,默认 true' },
@@ -361,7 +374,7 @@ export const COMMANDS = [
361
374
  name: 'selector',
362
375
  type: 'string',
363
376
  required: true,
364
- description: '原生 CSS 选择器或 @eN snapshot ref(必须带 @ 前缀)',
377
+ description: '原生 CSS 选择器,或 page_snapshot / 页面动作 observation 返回的 @eN ref(必须带 @ 前缀)',
365
378
  },
366
379
  {
367
380
  name: 'observe',
@@ -374,7 +387,7 @@ export const COMMANDS = [
374
387
  },
375
388
  {
376
389
  name: 'page_scroll',
377
- description: '滚动页面,默认观察懒加载等滚动后变化',
390
+ description: '滚动页面或指定容器,默认观察懒加载等滚动后变化',
378
391
  params: [
379
392
  {
380
393
  name: 'direction',
@@ -382,7 +395,17 @@ export const COMMANDS = [
382
395
  required: true,
383
396
  description: '滚动方向',
384
397
  },
385
- { name: 'distance', type: 'number', description: '滚动距离(px),默认 300' },
398
+ { name: 'distance', type: 'number', description: '滚动距离(px),默认 600' },
399
+ {
400
+ name: 'selector',
401
+ type: 'string',
402
+ description: '目标滚动容器的原生 CSS 选择器,或 page_snapshot 返回的 @eN ref;不传时滚动页面',
403
+ },
404
+ {
405
+ name: 'containerPolicy',
406
+ type: '"self" | "nearest"',
407
+ description: '默认 self,要求 selector 本身可滚动;nearest 会在其不可滚动时使用最近的可滚动祖先',
408
+ },
386
409
  {
387
410
  name: 'observe',
388
411
  type: 'object | false',
@@ -393,6 +416,8 @@ export const COMMANDS = [
393
416
  examples: [
394
417
  `page_scroll --payload '{"direction":"down"}'`,
395
418
  `page_scroll --payload '{"direction":"bottom"}'`,
419
+ `page_scroll --payload '{"selector":".virtual-list","direction":"down","distance":800}'`,
420
+ `page_scroll --payload '{"selector":"@e8","containerPolicy":"nearest","direction":"bottom"}'`,
396
421
  ],
397
422
  },
398
423
  {
@@ -405,6 +430,11 @@ export const COMMANDS = [
405
430
  type: 'boolean',
406
431
  description: '表达式返回 Promise 时等待完成,默认 true',
407
432
  },
433
+ {
434
+ name: 'observe',
435
+ type: 'object',
436
+ description: '仅在表达式会修改页面且需要观察结果时显式传入;不传保持轻量裸执行',
437
+ },
408
438
  { name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
409
439
  ],
410
440
  examples: [`page_eval --payload '{"expression":"document.title"}'`],
@@ -456,19 +486,29 @@ export const COMMANDS = [
456
486
  },
457
487
  {
458
488
  name: 'page_navigate',
459
- description: '在当前标签页内导航到新 URL,或用 refresh 直接刷新当前页面',
489
+ description: '在当前标签页内导航到 URL、刷新页面,或沿浏览历史后退/前进',
460
490
  params: [
461
- { name: 'url', type: 'string', description: '要导航到的 URL(refresh 为 true 时可省略)' },
491
+ {
492
+ name: 'url',
493
+ type: 'string',
494
+ description: '要导航到的 URL;与 refresh/history 互斥',
495
+ },
462
496
  {
463
497
  name: 'refresh',
464
498
  type: 'boolean',
465
- description: '为 true 时直接重新加载当前页面(忽略 url),默认 false',
499
+ description: '为 true 时直接重新加载当前页面;与 url/history 互斥',
500
+ },
501
+ {
502
+ name: 'history',
503
+ type: '"back" | "forward"',
504
+ description: '沿当前标签页浏览历史后退或前进;与 url/refresh 互斥',
466
505
  },
467
506
  { name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
468
507
  ],
469
508
  examples: [
470
509
  `page_navigate --payload '{"tabId":12345,"url":"https://example.com/page2"}'`,
471
510
  `page_navigate --payload '{"tabId":12345,"refresh":true}'`,
511
+ `page_navigate --payload '{"tabId":12345,"history":"back"}'`,
472
512
  ],
473
513
  },
474
514
  {
@@ -479,7 +519,7 @@ export const COMMANDS = [
479
519
  name: 'selector',
480
520
  type: 'string',
481
521
  required: true,
482
- description: '原生 CSS 选择器或 @eN snapshot ref(必须带 @ 前缀),必须指向 input[type=file]',
522
+ description: '原生 CSS 选择器,或 page_snapshot / 页面动作 observation 返回的 @eN ref(必须带 @ 前缀),必须指向 input[type=file]',
483
523
  },
484
524
  { name: 'filePaths', type: 'string[]', required: true, description: '本地文件路径数组' },
485
525
  {
@@ -502,12 +542,27 @@ export const COMMANDS = [
502
542
  {
503
543
  name: 'mode',
504
544
  type: '"full" | "interactive" | "viewport"',
505
- description: '输出范围,默认 full;长列表优先使用 viewport',
545
+ description: '输出范围,默认 full;interactive 只保留当前视口内的语义控件;长列表优先使用 viewport',
506
546
  },
507
547
  {
508
548
  name: 'rootSelector',
509
549
  type: 'string',
510
- description: '只获取指定 CSS 元素的 AX 子树,可与 mode 组合',
550
+ description: '只获取指定 CSS 元素的 AX 子树,可与 mode 组合;与 rootRef 互斥',
551
+ },
552
+ {
553
+ name: 'rootRef',
554
+ type: 'string',
555
+ description: '以已有 @eN ref 为根获取局部 AX 子树;与 rootSelector 互斥',
556
+ },
557
+ {
558
+ name: 'ancestorDepth',
559
+ type: 'number',
560
+ description: 'rootRef 向上扩展的 DOM 祖先层数,默认 0,最大 20',
561
+ },
562
+ {
563
+ name: 'query',
564
+ type: '{ text?: string; role?: string; exact?: boolean }',
565
+ description: '服务端过滤 AX 树,只保留按 accessibility name / role 命中的节点及祖先路径',
511
566
  },
512
567
  { name: 'maxNodes', type: 'number', description: '最多输出节点数,0 表示不限制' },
513
568
  {
@@ -521,6 +576,8 @@ export const COMMANDS = [
521
576
  'page_snapshot',
522
577
  `page_snapshot --payload '{"tabId":1,"mode":"viewport"}'`,
523
578
  `page_snapshot --payload '{"tabId":1,"rootSelector":"[role=dialog]"}'`,
579
+ `page_snapshot --payload '{"tabId":1,"rootRef":"@e8","ancestorDepth":1}'`,
580
+ `page_snapshot --payload '{"tabId":1,"query":{"text":"保存","role":"button"}}'`,
524
581
  ],
525
582
  },
526
583
  {
package/dist/index.d.ts CHANGED
@@ -44,6 +44,8 @@ export interface GetEventsParams {
44
44
  filter?: string;
45
45
  since?: number;
46
46
  limit?: number;
47
+ /** Include full tracking URL, raw payload, and parsed context. Defaults to false. */
48
+ includeRaw?: boolean;
47
49
  }
48
50
  export declare function getEvents(params?: GetEventsParams): Promise<any>;
49
51
  export interface SetMockParams {
@@ -245,6 +247,7 @@ export declare function tabList(): Promise<any>;
245
247
  * 页面交互动作(click/type/hover/scroll/press/upload)默认内置观察:
246
248
  * 同一次调用内执行动作并等待异步稳定,返回 `{ action, observation }`。
247
249
  * 传 `observe: false` 关闭观察,仅执行裸动作并直接返回其结果。
250
+ * page_eval 默认裸执行,显式传 observe 对象时才进入同一观察链路。
248
251
  */
249
252
  export interface PageObserveOptions {
250
253
  quietMs?: number;
@@ -257,7 +260,7 @@ export interface PageObserveOptions {
257
260
  }
258
261
  export interface PageClickParams {
259
262
  tabId: number;
260
- /** 原生 CSS 选择器或 @eN snapshot ref。selector/text/point 三选一。 */
263
+ /** 原生 CSS 选择器,或 snapshot / 页面动作 observation 返回的 @eN ref。 */
261
264
  selector?: string;
262
265
  /** 按可见文本(AX name)定位;可配合 role/exact 消歧。 */
263
266
  text?: string;
@@ -270,11 +273,14 @@ export interface PageClickParams {
270
273
  role?: string;
271
274
  /** 配合 text,默认 true(精确匹配),false 时子串匹配。 */
272
275
  exact?: boolean;
276
+ /** 配合 text,把 AX 文本匹配限制在指定 CSS 元素或 @eN ref 子树内。 */
277
+ scope?: string;
273
278
  /**
274
- * 点击方式。默认 'js'(对 selector / @ref 调用 el.click())。
275
- * 'cdp' 走真实 mouse/touch 事件;text 与 point 始终用 CDP。
279
+ * 点击模式。auto 会在可见页按设备模拟状态选择可信 mouse/touch,在隐藏页
280
+ * 使用 DOM fallback;checkbox/radio 使用带状态校验的 DOM 路径。
281
+ * dom/mouse/touch 可强制指定实际派发方式。
276
282
  */
277
- clickType?: 'js' | 'cdp';
283
+ clickMode?: 'auto' | 'dom' | 'mouse' | 'touch';
278
284
  /** 观察选项;传 false 关闭内置观察。 */
279
285
  observe?: PageObserveOptions | false;
280
286
  }
@@ -290,8 +296,12 @@ export interface PageTypeParams {
290
296
  export declare function pageType(params: PageTypeParams): Promise<any>;
291
297
  export interface PageScrollParams {
292
298
  tabId: number;
293
- direction: string;
299
+ direction: 'up' | 'down' | 'top' | 'bottom';
294
300
  distance?: number;
301
+ /** 原生 CSS 选择器或 page_snapshot 返回的 @eN ref;不传时滚动页面。 */
302
+ selector?: string;
303
+ /** selector 指向子节点时,是否自动使用最近的可滚动祖先。默认 self。 */
304
+ containerPolicy?: 'self' | 'nearest';
295
305
  /** 观察选项;传 false 关闭内置观察。 */
296
306
  observe?: PageObserveOptions | false;
297
307
  }
@@ -308,14 +318,32 @@ export interface PageEvalParams {
308
318
  expression: string;
309
319
  frameId?: string;
310
320
  awaitPromise?: boolean;
321
+ /** 显式传入时观察表达式引发的页面变化;不传保持轻量裸执行。 */
322
+ observe?: PageObserveOptions;
311
323
  }
312
324
  export declare function pageEval(params: PageEvalParams): Promise<any>;
325
+ export interface PageSnapshotQuery {
326
+ /** 按 accessibility name 匹配。 */
327
+ text?: string;
328
+ /** 按 AX role 匹配。 */
329
+ role?: string;
330
+ /** 默认 true 精确匹配;false 时按子串匹配 text。 */
331
+ exact?: boolean;
332
+ }
313
333
  export interface PageSnapshotParams {
314
334
  tabId: number;
315
335
  depth?: number;
316
336
  maxChars?: number;
317
337
  maxNodes?: number;
338
+ /** CSS 根元素;与 rootRef 互斥。 */
318
339
  rootSelector?: string;
340
+ /** 以已有 @eN ref 为根获取局部 AX 子树;与 rootSelector 互斥。 */
341
+ rootRef?: string;
342
+ /** rootRef 向上扩展的 DOM 祖先层数,默认 0,最大 20。 */
343
+ ancestorDepth?: number;
344
+ /** 服务端过滤 AX 树,只保留命中节点及其祖先路径。 */
345
+ query?: PageSnapshotQuery;
346
+ /** full 为完整树;interactive 为当前视口内的语义控件;viewport 为当前可视区域。 */
319
347
  mode?: 'full' | 'interactive' | 'viewport';
320
348
  }
321
349
  export declare function pageSnapshot(params: PageSnapshotParams): Promise<any>;
@@ -339,10 +367,12 @@ export interface PageWaitParams {
339
367
  export declare function pageWait(params: PageWaitParams): Promise<any>;
340
368
  export interface PageNavigateParams {
341
369
  tabId: number;
342
- /** 要导航到的 URL;refresh 为 true 时可省略。 */
370
+ /** 要导航到的 URL;与 refresh/history 互斥。 */
343
371
  url?: string;
344
- /** 为 true 时直接重新加载当前页面(忽略 url),用于刷新页面。 */
372
+ /** 为 true 时直接重新加载当前页面;与 url/history 互斥。 */
345
373
  refresh?: boolean;
374
+ /** 沿当前标签页的浏览历史后退或前进;与 url/refresh 互斥。 */
375
+ history?: 'back' | 'forward';
346
376
  }
347
377
  export declare function pageNavigate(params: PageNavigateParams): Promise<any>;
348
378
  export interface PageUploadParams {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mearl/client",
3
- "version": "2.0.1",
3
+ "version": "2.0.2",
4
4
  "description": "Client SDK & CLI for Mearl — communicate with Chrome Extension via Unix Socket",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",