@mearl/client 2.7.1 → 2.7.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/README.md CHANGED
@@ -73,6 +73,9 @@ mearl browser_list
73
73
  mearl browser_release
74
74
  ```
75
75
 
76
+ 输入不存在或拼写有误的 action 时,CLI 会基于可用命令和常见别名直接返回最多三个候选及调用示例,
77
+ 不连接浏览器,也不会自动执行推荐命令。例如 `mearl tab new` 会优先推荐 `mearl tab_open`。
78
+
76
79
  **通用选项:**
77
80
 
78
81
  | 选项 | 说明 |
@@ -91,7 +94,7 @@ mearl browser_release
91
94
 
92
95
  | 分类 | Actions |
93
96
  | ----------- | --------------------------------------------------------------------------------------------------------------------- |
94
- | API 调试 | `capture_checkpoint` `get_requests` `get_logs` `get_events` `get_api_schema` |
97
+ | API 调试 | `tab_checkpoint` `get_requests` `get_logs` `get_events` `get_api_schema` |
95
98
  | Mock & 规则 | `set_mock` `get_mocks` `set_rule` `get_rules` |
96
99
  | 网络代理 | `send_request` `send_mtop_request` |
97
100
  | 标签页 | `tab_open` `tab_close` `tab_list` |
@@ -103,11 +106,11 @@ mearl browser_release
103
106
  | TDBank | `tdbank_account` |
104
107
  | 浏览器 | `browser_list` `browser_release` `browser_launch` `browser_close` |
105
108
 
106
- 页面交互动作(`page_click` / `page_drag` / `page_type` / `page_hover` / `page_scroll` / `page_press` / `page_upload`)默认内置观察与原子诊断:同一次调用内执行动作、等待异步稳定,并返回 `{ action, observation, diagnostics }`;`diagnostics` 默认包含新增 error logs 和全部业务 requests。传 `observe: false` 只关闭 DOM/导航观察并保留诊断;同时传 `diagnostics: false` 才仅执行裸动作。观察结果不替代完整页面理解:`mode: "delta"` 只返回主文档中的 `effects.notifications`、`effects.interactives` 和 `effects.focus` 等高置信度信号,并明确携带 `scope: "main-document"`;可交互节点会尽量携带真实 backend `node.ref`,后续动作优先使用 ref,缺少 ref 时使用 `node.selector`。`mode: "navigation"` 且 `ready: true` 时,页面已通过网络静默、骨架状态或保守的内容稳定判定,可在新页面重建快照。动作直接打开新标签页时,`observation.openedTabs` 返回新标签页的 `tabId`、URL、标题和加载状态,可直接把该 `tabId` 用于后续操作,不必调用 `tab_list`。通常仅在 `fullSnapshotRecommended` 为 true 时根据 `snapshotReasons` 回退;滚动后若下一步需要读取新视口内容,可按需获取 viewport 快照。`page_eval` 默认裸执行;显式传 `observe` 对象可启用观察,传 `diagnostics: true` 或对象可启用原子诊断。
109
+ 页面交互动作(`page_click` / `page_drag` / `page_type` / `page_hover` / `page_scroll` / `page_press` / `page_upload`)默认等待异步稳定并返回 `{ action, observation }`。参数、ref 或目标解析在派发前失败时返回 `action.stage: "precondition"`,省略无意义的 `observation` / `diagnostics`,CLI 退出码为 1。传 `observe: false` 可执行裸动作;需要同一动作期间的新增 error logs 和业务 requests 时传 `diagnostics: true`,埋点通过 `diagnostics.events` 按需开启。`page_eval` 默认裸执行,可按需开启观察或诊断。
107
110
 
108
111
  `page_snapshot` 默认返回完整 AX Tree;长列表可传 `mode: "viewport"`,只需要当前视口内的控件时传 `mode: "interactive"`,已知 CSS 区域时传 `rootSelector`,已有 ref 时传 `rootRef`(可用 `ancestorDepth` 向上补充上下文),只查找特定文案或角色时传 `query`。视口内缺少 AX 控件语义时,`interactive` 会自动回退到 viewport,并返回 `fallbackMode: "viewport"`。`maxNodes` / `maxChars` 截断会同时保留首尾内容。
109
112
 
110
- 重复文本点击可用 `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` 和滚动结果的前后位置、边界字段可用于诊断实际派发目标与滚动效果。
113
+ 重复文本点击可用 `page_click.scope` 限定 CSS / ref 子树;ref 指向滚动容器内的子节点时,可用 `page_scroll.containerPolicy: "nearest"` 自动解析最近可滚动祖先。点击结果的 `resolvedTarget` 和滚动结果的前后位置、边界字段可用于诊断实际目标与效果。
111
114
 
112
115
  `browser_list` 统一列出普通浏览器和托管浏览器。`type` 区分 `regular` / `managed`,`status` 区分 `connected` / `running_disconnected` / `stopped`;只有 `connected` 的浏览器可作为操作目标。
113
116
 
@@ -1,5 +1,7 @@
1
1
  import { PAGE_ACT_ACTIONS } from './generated-browser-action-protocol.js';
2
2
  const SEND_REQUEST_FILE_TRANSFER_TIMEOUT_MS = 120_000;
3
+ // AgentBay staging can spend up to 60s transferring bytes and then 120s syncing the session disk.
4
+ const PAGE_UPLOAD_FILE_TRANSFER_TIMEOUT_MS = 180_000;
3
5
  // AgentBay context sync can poll for about 12 minutes before session deletion waits up to 5 more.
4
6
  const BROWSER_CLOSE_TIMEOUT_SEC = 18 * 60;
5
7
  function boundedNumber(value, fallback, minimum, maximum) {
@@ -56,6 +58,10 @@ export function resolveActionTimeoutSec(action, data, fallback = 15) {
56
58
  const observationEnabled = action === 'page_eval'
57
59
  ? data.observe !== null && typeof data.observe === 'object' && !Array.isArray(data.observe)
58
60
  : data.observe !== false;
61
+ if (action === 'page_upload') {
62
+ const actionTimeoutSec = observationEnabled ? resolveObservedActionTimeoutSec(data) : fallback;
63
+ return Math.max(fallback, actionTimeoutSec + Math.ceil(PAGE_UPLOAD_FILE_TRANSFER_TIMEOUT_MS / 1000));
64
+ }
59
65
  if (observedAction && observationEnabled) {
60
66
  return Math.max(fallback, resolveObservedActionTimeoutSec(data));
61
67
  }
package/dist/cli.js CHANGED
@@ -2,14 +2,15 @@ import { readFileSync, writeFileSync } from 'node:fs';
2
2
  import { resolve } from 'node:path';
3
3
  import { resolveActionTimeoutSec } from './actionTimeouts.js';
4
4
  import { runUnifiedCheck, parseCheckTimeout } from './check.js';
5
- import { COMMAND_MAP } from './commands.js';
5
+ import { commandInput, findCommandSuggestions, formatCommandSuggestions, } from './commandSuggestions.js';
6
+ import { COMMANDS, COMMAND_MAP } from './commands.js';
6
7
  import { CLIENT_VERSION } from './socket.js';
7
8
  import { UnifiedClient } from './unified.js';
8
9
  import { getCloudServerConfigPath, loadCloudServerConfig } from './unifiedConfig.js';
9
10
  const CATEGORIES = [
10
11
  {
11
12
  title: 'API 调试',
12
- names: ['capture_checkpoint', 'get_requests', 'get_logs', 'get_events', 'get_api_schema'],
13
+ names: ['tab_checkpoint', 'get_requests', 'get_logs', 'get_events', 'get_api_schema'],
13
14
  },
14
15
  { title: 'Mock & 规则', names: ['set_mock', 'get_mocks', 'set_rule', 'get_rules'] },
15
16
  { title: '网络代理', names: ['send_request', 'send_mtop_request'] },
@@ -45,6 +46,15 @@ const CATEGORIES = [
45
46
  names: ['browser_list', 'browser_release', 'browser_launch', 'browser_close'],
46
47
  },
47
48
  ];
49
+ const BUILTIN_COMMANDS = [
50
+ {
51
+ name: 'check',
52
+ description: '检查指定浏览器,未指定时检查全部已连接浏览器',
53
+ examples: ['check'],
54
+ },
55
+ ];
56
+ const SUGGESTABLE_COMMANDS = [...COMMANDS, ...BUILTIN_COMMANDS];
57
+ const ADVANCED_BUILTIN_COMMANDS = new Set(['connector_list']);
48
58
  function optionValue(args, name) {
49
59
  const index = args.indexOf(name);
50
60
  return index >= 0 ? args[index + 1] : undefined;
@@ -76,7 +86,6 @@ function printUsage(commandName, version) {
76
86
  '',
77
87
  '内置命令:',
78
88
  ' check 检查指定浏览器,未指定时检查全部已连接浏览器',
79
- ' connector_list 列出 cloud-server 下的 connector',
80
89
  ];
81
90
  for (const category of CATEGORIES) {
82
91
  lines.push('', ` ${category.title}`);
@@ -89,6 +98,17 @@ function printUsage(commandName, version) {
89
98
  lines.push('', `运行 ${commandName} <action> --help 查看 action 参数。`);
90
99
  console.error(lines.join('\n'));
91
100
  }
101
+ function printAdvancedCommandHelp(commandName, action) {
102
+ if (action !== 'connector_list')
103
+ return;
104
+ console.error([
105
+ 'connector_list',
106
+ ' 列出 cloud-server 下的 connector(高级诊断)',
107
+ '',
108
+ '用法:',
109
+ ` ${commandName} connector_list [--server <url>] [--timeout <seconds>]`,
110
+ ].join('\n'));
111
+ }
92
112
  function printCommandHelp(commandName, command) {
93
113
  const lines = [
94
114
  `${command.name}`,
@@ -102,7 +122,7 @@ function printCommandHelp(commandName, command) {
102
122
  lines.push('参数(--payload JSON 字段):');
103
123
  for (const parameter of command.params) {
104
124
  const required = parameter.required ? '必填' : '可选';
105
- lines.push(` ${parameter.name.padEnd(22)}${required.padEnd(6)}${parameter.type.padEnd(28)}${parameter.description}`);
125
+ lines.push(` ${parameter.name.padEnd(22)}${required.padEnd(6)}${parameter.type.padEnd(28)} ${parameter.description}`);
106
126
  }
107
127
  lines.push('');
108
128
  }
@@ -113,6 +133,18 @@ function printCommandHelp(commandName, command) {
113
133
  }
114
134
  console.error(lines.join('\n'));
115
135
  }
136
+ function printUnknownCommand(commandName, args) {
137
+ const input = commandInput(args) || args[0] || '';
138
+ const suggestions = findCommandSuggestions(args, SUGGESTABLE_COMMANDS);
139
+ const lines = [`不支持的命令: ${input}`];
140
+ if (suggestions.length > 0) {
141
+ lines.push('', '你可能想用:', ...formatCommandSuggestions(commandName, suggestions));
142
+ }
143
+ else {
144
+ lines.push(`运行 ${commandName} --help 查看所有可用命令`);
145
+ }
146
+ console.error(lines.join('\n'));
147
+ }
116
148
  function parsePositiveTimeout(value, fallback) {
117
149
  if (value === undefined)
118
150
  return fallback;
@@ -230,6 +262,8 @@ function writeOutput(action, result, outputPath) {
230
262
  export async function runMearlCli(args, options = {}) {
231
263
  const commandName = options.commandName ?? 'mearl';
232
264
  const clientVersion = options.clientVersion ?? CLIENT_VERSION;
265
+ if (args[0] === 'capture_checkpoint')
266
+ args = ['tab_checkpoint', ...args.slice(1)];
233
267
  if (args.includes('--version') || args.includes('-v')) {
234
268
  console.log(clientVersion);
235
269
  return 0;
@@ -242,10 +276,22 @@ export async function runMearlCli(args, options = {}) {
242
276
  const command = COMMAND_MAP.get(args[0]);
243
277
  if (command)
244
278
  printCommandHelp(commandName, command);
245
- else
279
+ else if (ADVANCED_BUILTIN_COMMANDS.has(args[0])) {
280
+ printAdvancedCommandHelp(commandName, args[0]);
281
+ }
282
+ else if (args[0]?.startsWith('-') || BUILTIN_COMMANDS.some(item => item.name === args[0])) {
246
283
  printUsage(commandName, clientVersion);
284
+ }
285
+ else {
286
+ printUnknownCommand(commandName, args);
287
+ return 2;
288
+ }
247
289
  return 0;
248
290
  }
291
+ if (args[0] !== 'check' && args[0] !== 'connector_list' && !COMMAND_MAP.has(args[0])) {
292
+ printUnknownCommand(commandName, args);
293
+ return 2;
294
+ }
249
295
  let parsed;
250
296
  try {
251
297
  parsed = parseArgs(args);
@@ -272,11 +318,6 @@ export async function runMearlCli(args, options = {}) {
272
318
  });
273
319
  return ok ? 0 : 1;
274
320
  }
275
- if (parsed.action !== 'connector_list' && !COMMAND_MAP.has(parsed.action)) {
276
- console.error(`不支持的 action: ${parsed.action}`);
277
- console.error(`运行 ${commandName} --help 查看所有可用命令`);
278
- return 2;
279
- }
280
321
  if (parsed.action === 'page_selected_element' && parsed.outputPath) {
281
322
  parsed.payload = { ...parsed.payload, includeScreenshot: true };
282
323
  }
@@ -298,7 +339,7 @@ export async function runMearlCli(args, options = {}) {
298
339
  else {
299
340
  process.stdout.write(`${parsed.compact ? JSON.stringify(result) : JSON.stringify(result, null, 2)}\n`);
300
341
  }
301
- return 0;
342
+ return result?.action?.success === false ? 1 : 0;
302
343
  }
303
344
  catch (error) {
304
345
  console.error(error instanceof Error ? error.message : String(error));
@@ -0,0 +1,13 @@
1
+ export interface SuggestableCommand {
2
+ readonly aliases?: readonly string[];
3
+ readonly description: string;
4
+ readonly examples?: readonly string[];
5
+ readonly name: string;
6
+ }
7
+ export interface CommandSuggestion {
8
+ command: SuggestableCommand;
9
+ score: number;
10
+ }
11
+ export declare function commandInput(args: readonly string[]): string;
12
+ export declare function findCommandSuggestions(args: readonly string[], commands: readonly SuggestableCommand[], limit?: number): CommandSuggestion[];
13
+ export declare function formatCommandSuggestions(commandName: string, suggestions: readonly CommandSuggestion[]): string[];
@@ -0,0 +1,59 @@
1
+ import { distance } from 'fastest-levenshtein';
2
+ const MIN_SIMILARITY = 0.5;
3
+ const MAX_SCORE_GAP = 0.1;
4
+ function normalizeCommand(value) {
5
+ return value
6
+ .normalize('NFKC')
7
+ .toLowerCase()
8
+ .replace(/[^a-z0-9]+/g, '_')
9
+ .replace(/^_+|_+$/g, '');
10
+ }
11
+ function leadingCommandParts(args) {
12
+ const parts = [];
13
+ for (const arg of args) {
14
+ if (arg.startsWith('-'))
15
+ break;
16
+ parts.push(arg);
17
+ }
18
+ return parts;
19
+ }
20
+ function commandQueries(args) {
21
+ const parts = leadingCommandParts(args);
22
+ const queries = new Set();
23
+ for (let length = parts.length; length > 0; length -= 1) {
24
+ const query = normalizeCommand(parts.slice(0, length).join('_'));
25
+ if (query)
26
+ queries.add(query);
27
+ }
28
+ return [...queries];
29
+ }
30
+ function similarity(left, right) {
31
+ const length = Math.max(left.length, right.length);
32
+ return length === 0 ? 0 : (length - distance(left, right)) / length;
33
+ }
34
+ export function commandInput(args) {
35
+ return leadingCommandParts(args).join(' ');
36
+ }
37
+ export function findCommandSuggestions(args, commands, limit = 3) {
38
+ const queries = commandQueries(args);
39
+ if (queries.length === 0 || limit <= 0)
40
+ return [];
41
+ const ranked = commands
42
+ .map(command => {
43
+ const keys = [command.name, ...(command.aliases ?? [])].map(normalizeCommand);
44
+ const score = Math.max(...queries.flatMap(query => keys.map(key => similarity(query, key))));
45
+ return { command, score };
46
+ })
47
+ .filter(suggestion => suggestion.score >= MIN_SIMILARITY)
48
+ .sort((left, right) => right.score - left.score || left.command.name.localeCompare(right.command.name));
49
+ const bestScore = ranked[0]?.score;
50
+ if (bestScore === undefined)
51
+ return [];
52
+ return ranked.filter(suggestion => bestScore - suggestion.score <= MAX_SCORE_GAP).slice(0, limit);
53
+ }
54
+ export function formatCommandSuggestions(commandName, suggestions) {
55
+ return suggestions.map(({ command }) => {
56
+ const invocation = command.examples?.[0] ?? command.name;
57
+ return ` ${commandName} ${invocation}\n ${command.description}`;
58
+ });
59
+ }
@@ -8,6 +8,8 @@ export interface ParamDef {
8
8
  export interface CommandDef {
9
9
  name: BrowserCommandAction;
10
10
  description: string;
11
+ /** CLI 中用于推荐 canonical action 的常见表达,不会作为可执行 action。 */
12
+ aliases?: readonly string[];
11
13
  /** payload 字段说明 */
12
14
  params?: ParamDef[];
13
15
  /** 是否支持 --output */
@@ -15,14 +17,14 @@ export interface CommandDef {
15
17
  examples?: string[];
16
18
  }
17
19
  export declare const COMMANDS: readonly [{
18
- readonly name: "capture_checkpoint";
19
- readonly description: "为目标标签页建立 console/network 增量边界";
20
+ readonly name: "tab_checkpoint";
21
+ readonly description: "为目标标签页建立日志、请求和埋点增量边界";
20
22
  readonly params: [{
21
23
  readonly name: "tabId";
22
24
  readonly type: "number";
23
25
  readonly description: "目标标签页 ID,从 tab_open 获取";
24
26
  }];
25
- readonly examples: ["capture_checkpoint --payload '{\"tabId\":12345}'"];
27
+ readonly examples: ["tab_checkpoint --payload '{\"tabId\":12345}'"];
26
28
  }, {
27
29
  readonly name: "get_requests";
28
30
  readonly description: "获取最近的网络请求(mtop 或普通 xhr/fetch)";
@@ -49,7 +51,7 @@ export declare const COMMANDS: readonly [{
49
51
  }, {
50
52
  readonly name: "after";
51
53
  readonly type: "string";
52
- readonly description: "只返回指定 capture cursor 之后的请求";
54
+ readonly description: "只返回指定 tab checkpoint 或同类查询 cursor 之后的请求";
53
55
  }, {
54
56
  readonly name: "includeBody";
55
57
  readonly type: "boolean";
@@ -82,7 +84,7 @@ export declare const COMMANDS: readonly [{
82
84
  }, {
83
85
  readonly name: "after";
84
86
  readonly type: "string";
85
- readonly description: "只返回指定 capture cursor 之后的日志";
87
+ readonly description: "只返回指定 tab checkpoint 或同类查询 cursor 之后的日志";
86
88
  }];
87
89
  readonly examples: ["get_logs --payload '{\"limit\":10,\"level\":\"error\"}'"];
88
90
  }, {
@@ -108,6 +110,10 @@ export declare const COMMANDS: readonly [{
108
110
  readonly name: "since";
109
111
  readonly type: "number";
110
112
  readonly description: "只返回最近 N 秒内的事件";
113
+ }, {
114
+ readonly name: "after";
115
+ readonly type: "string";
116
+ readonly description: "只返回指定 tab checkpoint 之后的事件";
111
117
  }, {
112
118
  readonly name: "limit";
113
119
  readonly type: "number";
@@ -383,6 +389,7 @@ export declare const COMMANDS: readonly [{
383
389
  }, {
384
390
  readonly name: "tab_open";
385
391
  readonly description: "打开或按 URL 规则复用 Tab,并等待新页面加载完成";
392
+ readonly aliases: readonly ["tab_new", "new_tab", "tab_create", "create_tab"];
386
393
  readonly params: [{
387
394
  readonly name: "url";
388
395
  readonly type: "string";
@@ -425,6 +432,7 @@ export declare const COMMANDS: readonly [{
425
432
  }, {
426
433
  readonly name: "tab_close";
427
434
  readonly description: "关闭指定标签页";
435
+ readonly aliases: readonly ["tab_remove", "remove_tab", "tab_delete", "delete_tab"];
428
436
  readonly params: [{
429
437
  readonly name: "tabId";
430
438
  readonly type: "number";
@@ -435,10 +443,11 @@ export declare const COMMANDS: readonly [{
435
443
  }, {
436
444
  readonly name: "tab_list";
437
445
  readonly description: "获取当前窗口所有标签页列表";
446
+ readonly aliases: readonly ["tabs", "list_tabs", "show_tabs"];
438
447
  readonly examples: ["tab_list"];
439
448
  }, {
440
449
  readonly name: "page_click";
441
- readonly description: "点击页面元素,支持 selector / text / point 三种定位方式;auto 在可见页按设备模拟状态使用可信 mouse/touch,隐藏页使用 DOM fallback;点击直接打开新标签页时 observation.openedTabs 返回目标信息";
450
+ readonly description: "点击页面元素,支持 CSS/@ref、可见文本或视口坐标定位";
442
451
  readonly params: [{
443
452
  readonly name: "selector";
444
453
  readonly type: "string";
@@ -466,12 +475,8 @@ export declare const COMMANDS: readonly [{
466
475
  }, {
467
476
  readonly name: "clickMode";
468
477
  readonly type: "\"auto\" | \"dom\" | \"mouse\" | \"touch\"";
469
- readonly description: "点击模式;auto 在可见页按设备模拟状态选择可信 mouse/touch、隐藏页走 DOM,checkbox/radio 校验状态;其他值强制指定派发方式";
470
- }, {
471
- readonly name: "observe";
472
- readonly type: "object | false";
473
- readonly description: "观察选项(quietMs/firstChangeTimeoutMs/timeoutMs/navigationGraceMs/navigationTimeoutMs/networkIdleMs/contentReadyAfterMs);传 false 只关闭 DOM/导航观察,默认诊断仍会返回";
474
- }, ParamDef, {
478
+ readonly description: "默认 auto:可见页使用匹配设备的可信输入,隐藏页使用 DOM;dom/mouse/touch 可强制指定派发方式";
479
+ }, ParamDef, ParamDef, {
475
480
  readonly name: "tabId";
476
481
  readonly type: "number";
477
482
  readonly required: true;
@@ -480,7 +485,7 @@ export declare const COMMANDS: readonly [{
480
485
  readonly examples: ["page_click --payload '{\"text\":\"提交\"}'", "page_click --payload '{\"text\":\"退款明细\",\"role\":\"button\"}'", "page_click --payload '{\"text\":\"确定\",\"scope\":\"@e12\"}'", "page_click --payload '{\"selector\":\"@e3\"}'", "page_click --payload '{\"selector\":\".submit-btn\"}'", "page_click --payload '{\"selector\":\".gesture-btn\",\"clickMode\":\"touch\"}'", "page_click --payload '{\"point\":{\"x\":336,\"y\":117}}'"];
481
486
  }, {
482
487
  readonly name: "page_drag";
483
- readonly description: "在页面内执行拖动;from/to 均可使用视口坐标或 CSS/@ref,auto 在可见页使用可信 mouse/touch、隐藏页使用 DOM 模拟,并默认观察拖动后的页面变化";
488
+ readonly description: "拖动页面元素或视口坐标,适用于轮播图、滑块和拖放";
484
489
  readonly params: [{
485
490
  readonly name: "from";
486
491
  readonly type: "string | { x: number; y: number }";
@@ -494,16 +499,12 @@ export declare const COMMANDS: readonly [{
494
499
  }, {
495
500
  readonly name: "dragMode";
496
501
  readonly type: "\"auto\" | \"dom\" | \"mouse\" | \"touch\"";
497
- readonly description: "拖动输入类型;默认 auto,可见页按设备使用可信输入、隐藏页使用 DOM 模拟;dom 可显式强制后台模拟";
502
+ readonly description: "默认 auto:可见页使用匹配设备的可信输入,隐藏页使用 DOM;dom/mouse/touch 可强制指定派发方式";
498
503
  }, {
499
504
  readonly name: "durationMs";
500
505
  readonly type: "number";
501
506
  readonly description: "拖动持续时间,0–5000ms,默认 400ms;内部自动分段移动";
502
- }, {
503
- readonly name: "observe";
504
- readonly type: "object | false";
505
- readonly description: "观察选项;传 false 只关闭 DOM/导航观察,默认诊断仍会返回";
506
- }, ParamDef, {
507
+ }, ParamDef, ParamDef, {
507
508
  readonly name: "tabId";
508
509
  readonly type: "number";
509
510
  readonly required: true;
@@ -512,7 +513,7 @@ export declare const COMMANDS: readonly [{
512
513
  readonly examples: ["page_drag --payload '{\"from\":{\"x\":350,\"y\":80},\"to\":{\"x\":80,\"y\":80}}'", "page_drag --payload '{\"from\":\"@e3\",\"to\":\"#drop-zone\",\"dragMode\":\"mouse\"}'"];
513
514
  }, {
514
515
  readonly name: "page_type";
515
- readonly description: "向输入框填写文本,兼容 React 受控组件;默认观察校验提示等异步变化";
516
+ readonly description: "向输入框填写文本,兼容 React 受控组件";
516
517
  readonly params: [{
517
518
  readonly name: "selector";
518
519
  readonly type: "string";
@@ -527,11 +528,7 @@ export declare const COMMANDS: readonly [{
527
528
  readonly name: "clearFirst";
528
529
  readonly type: "boolean";
529
530
  readonly description: "是否先清空原有内容,默认 true";
530
- }, {
531
- readonly name: "observe";
532
- readonly type: "object | false";
533
- readonly description: "观察选项;传 false 只关闭 DOM/导航观察,默认诊断仍会返回";
534
- }, ParamDef, {
531
+ }, ParamDef, ParamDef, {
535
532
  readonly name: "tabId";
536
533
  readonly type: "number";
537
534
  readonly required: true;
@@ -540,17 +537,13 @@ export declare const COMMANDS: readonly [{
540
537
  readonly examples: ["page_type --payload '{\"selector\":\"@e6\",\"text\":\"搜索关键词\"}'"];
541
538
  }, {
542
539
  readonly name: "page_hover";
543
- readonly description: "将鼠标悬停在元素上,默认观察下拉菜单、提示信息等 hover 后变化";
540
+ readonly description: "将鼠标悬停在页面元素上";
544
541
  readonly params: [{
545
542
  readonly name: "selector";
546
543
  readonly type: "string";
547
544
  readonly required: true;
548
545
  readonly description: "原生 CSS 选择器,或 page_snapshot / 页面动作 observation 返回的 @eN ref(必须带 @ 前缀)";
549
- }, {
550
- readonly name: "observe";
551
- readonly type: "object | false";
552
- readonly description: "观察选项;传 false 只关闭 DOM/导航观察,默认诊断仍会返回";
553
- }, ParamDef, {
546
+ }, ParamDef, ParamDef, {
554
547
  readonly name: "tabId";
555
548
  readonly type: "number";
556
549
  readonly required: true;
@@ -559,7 +552,7 @@ export declare const COMMANDS: readonly [{
559
552
  readonly examples: ["page_hover --payload '{\"selector\":\".nav-menu\"}'"];
560
553
  }, {
561
554
  readonly name: "page_scroll";
562
- readonly description: "滚动页面或指定容器,默认观察懒加载等滚动后变化";
555
+ readonly description: "滚动页面或指定容器";
563
556
  readonly params: [{
564
557
  readonly name: "direction";
565
558
  readonly type: "\"up\" | \"down\" | \"top\" | \"bottom\"";
@@ -577,11 +570,7 @@ export declare const COMMANDS: readonly [{
577
570
  readonly name: "containerPolicy";
578
571
  readonly type: "\"self\" | \"nearest\"";
579
572
  readonly description: "默认 self,要求 selector 本身可滚动;nearest 会在其不可滚动时使用最近的可滚动祖先";
580
- }, {
581
- readonly name: "observe";
582
- readonly type: "object | false";
583
- readonly description: "观察选项;传 false 只关闭 DOM/导航观察,默认诊断仍会返回";
584
- }, ParamDef, {
573
+ }, ParamDef, ParamDef, {
585
574
  readonly name: "tabId";
586
575
  readonly type: "number";
587
576
  readonly required: true;
@@ -613,7 +602,7 @@ export declare const COMMANDS: readonly [{
613
602
  readonly examples: ["page_eval --payload '{\"expression\":\"document.title\"}'"];
614
603
  }, {
615
604
  readonly name: "page_press";
616
- readonly description: "在页面中按下键盘按键,默认观察提交、关闭弹窗等结果";
605
+ readonly description: "在页面中按下键盘按键或组合键";
617
606
  readonly params: [{
618
607
  readonly name: "key";
619
608
  readonly type: "string";
@@ -623,11 +612,7 @@ export declare const COMMANDS: readonly [{
623
612
  readonly name: "modifiers";
624
613
  readonly type: "string[]";
625
614
  readonly description: "修饰键数组:ctrl/alt/shift/meta/cmd";
626
- }, {
627
- readonly name: "observe";
628
- readonly type: "object | false";
629
- readonly description: "观察选项;传 false 只关闭 DOM/导航观察,默认诊断仍会返回";
630
- }, ParamDef, {
615
+ }, ParamDef, ParamDef, {
631
616
  readonly name: "tabId";
632
617
  readonly type: "number";
633
618
  readonly required: true;
@@ -688,7 +673,7 @@ export declare const COMMANDS: readonly [{
688
673
  readonly examples: ["page_navigate --payload '{\"tabId\":12345,\"url\":\"https://example.com/page2\"}'", "page_navigate --payload '{\"tabId\":12345,\"refresh\":true}'", "page_navigate --payload '{\"tabId\":12345,\"history\":\"back\"}'"];
689
674
  }, {
690
675
  readonly name: "page_upload";
691
- readonly description: "向 <input type=\"file\"> 元素上传文件,默认观察上传状态变化";
676
+ readonly description: "向 <input type=\"file\"> 元素上传一个或多个文件";
692
677
  readonly params: [{
693
678
  readonly name: "selector";
694
679
  readonly type: "string";
@@ -699,11 +684,7 @@ export declare const COMMANDS: readonly [{
699
684
  readonly type: "string[]";
700
685
  readonly required: true;
701
686
  readonly description: "本地文件路径数组";
702
- }, {
703
- readonly name: "observe";
704
- readonly type: "object | false";
705
- readonly description: "观察选项;传 false 只关闭 DOM/导航观察,默认诊断仍会返回";
706
- }, ParamDef, {
687
+ }, ParamDef, ParamDef, {
707
688
  readonly name: "tabId";
708
689
  readonly type: "number";
709
690
  readonly required: true;
package/dist/commands.js CHANGED
@@ -1,15 +1,20 @@
1
1
  const PAGE_DIAGNOSTICS_PARAM = {
2
2
  name: 'diagnostics',
3
3
  type: 'object | boolean',
4
- description: '交互动作默认在执行前原子建立边界,并返回新增 error logs/全部业务 requests;传 false 关闭,或传对象自定义过滤',
4
+ description: '默认关闭;传 true 返回动作期间新增的 error logs/业务 requests,或传对象自定义通道与过滤',
5
+ };
6
+ const PAGE_OBSERVE_PARAM = {
7
+ name: 'observe',
8
+ type: 'object | false',
9
+ description: '默认开启 DOM/导航观察;传 false 关闭,不影响显式请求的 diagnostics',
5
10
  };
6
11
  export const COMMANDS = [
7
12
  // ── API 调试 ──────────────────────────────────────────────────────────────
8
13
  {
9
- name: 'capture_checkpoint',
10
- description: '为目标标签页建立 console/network 增量边界',
14
+ name: 'tab_checkpoint',
15
+ description: '为目标标签页建立日志、请求和埋点增量边界',
11
16
  params: [{ name: 'tabId', type: 'number', description: '目标标签页 ID,从 tab_open 获取' }],
12
- examples: [`capture_checkpoint --payload '{"tabId":12345}'`],
17
+ examples: [`tab_checkpoint --payload '{"tabId":12345}'`],
13
18
  },
14
19
  {
15
20
  name: 'get_requests',
@@ -24,7 +29,11 @@ export const COMMANDS = [
24
29
  },
25
30
  { name: 'filter', type: 'string', description: '按 URL 或 API 名称过滤,支持正则' },
26
31
  { name: 'since', type: 'number', description: '只返回最近 N 秒内的请求' },
27
- { name: 'after', type: 'string', description: '只返回指定 capture cursor 之后的请求' },
32
+ {
33
+ name: 'after',
34
+ type: 'string',
35
+ description: '只返回指定 tab checkpoint 或同类查询 cursor 之后的请求',
36
+ },
28
37
  { name: 'includeBody', type: 'boolean', description: '是否包含请求/响应体,默认 true' },
29
38
  ],
30
39
  examples: [
@@ -41,7 +50,11 @@ export const COMMANDS = [
41
50
  { name: 'level', type: 'string', description: '按日志级别过滤:log/info/warn/error' },
42
51
  { name: 'filter', type: 'string', description: '按内容过滤,支持正则' },
43
52
  { name: 'since', type: 'number', description: '只返回最近 N 秒内的日志' },
44
- { name: 'after', type: 'string', description: '只返回指定 capture cursor 之后的日志' },
53
+ {
54
+ name: 'after',
55
+ type: 'string',
56
+ description: '只返回指定 tab checkpoint 或同类查询 cursor 之后的日志',
57
+ },
45
58
  ],
46
59
  examples: [`get_logs --payload '{"limit":10,"level":"error"}'`],
47
60
  },
@@ -58,6 +71,7 @@ export const COMMANDS = [
58
71
  { name: 'event_type', type: 'string', description: '按事件类型过滤,支持正则,如 CLK/PV' },
59
72
  { name: 'filter', type: 'string', description: '按 name 或 url 过滤,支持正则' },
60
73
  { name: 'since', type: 'number', description: '只返回最近 N 秒内的事件' },
74
+ { name: 'after', type: 'string', description: '只返回指定 tab checkpoint 之后的事件' },
61
75
  { name: 'limit', type: 'number', description: '返回条数,默认 20' },
62
76
  {
63
77
  name: 'includeRaw',
@@ -311,6 +325,7 @@ export const COMMANDS = [
311
325
  {
312
326
  name: 'tab_open',
313
327
  description: '打开或按 URL 规则复用 Tab,并等待新页面加载完成',
328
+ aliases: ['tab_new', 'new_tab', 'tab_create', 'create_tab'],
314
329
  params: [
315
330
  { name: 'url', type: 'string', required: true, description: '要打开的 URL' },
316
331
  { name: 'active', type: 'boolean', description: '是否激活新 Tab,默认 false' },
@@ -360,18 +375,20 @@ export const COMMANDS = [
360
375
  {
361
376
  name: 'tab_close',
362
377
  description: '关闭指定标签页',
378
+ aliases: ['tab_remove', 'remove_tab', 'tab_delete', 'delete_tab'],
363
379
  params: [{ name: 'tabId', type: 'number', required: true, description: '要关闭的标签页 ID' }],
364
380
  examples: [`tab_close --payload '{"tabId":123}'`],
365
381
  },
366
382
  {
367
383
  name: 'tab_list',
368
384
  description: '获取当前窗口所有标签页列表',
385
+ aliases: ['tabs', 'list_tabs', 'show_tabs'],
369
386
  examples: ['tab_list'],
370
387
  },
371
388
  // ── 页面操作 ──────────────────────────────────────────────────────────────
372
389
  {
373
390
  name: 'page_click',
374
- description: '点击页面元素,支持 selector / text / point 三种定位方式;auto 在可见页按设备模拟状态使用可信 mouse/touch,隐藏页使用 DOM fallback;点击直接打开新标签页时 observation.openedTabs 返回目标信息',
391
+ description: '点击页面元素,支持 CSS/@ref、可见文本或视口坐标定位',
375
392
  params: [
376
393
  {
377
394
  name: 'selector',
@@ -406,13 +423,9 @@ export const COMMANDS = [
406
423
  {
407
424
  name: 'clickMode',
408
425
  type: '"auto" | "dom" | "mouse" | "touch"',
409
- description: '点击模式;auto 在可见页按设备模拟状态选择可信 mouse/touch、隐藏页走 DOM,checkbox/radio 校验状态;其他值强制指定派发方式',
410
- },
411
- {
412
- name: 'observe',
413
- type: 'object | false',
414
- description: '观察选项(quietMs/firstChangeTimeoutMs/timeoutMs/navigationGraceMs/navigationTimeoutMs/networkIdleMs/contentReadyAfterMs);传 false 只关闭 DOM/导航观察,默认诊断仍会返回',
426
+ description: '默认 auto:可见页使用匹配设备的可信输入,隐藏页使用 DOM;dom/mouse/touch 可强制指定派发方式',
415
427
  },
428
+ PAGE_OBSERVE_PARAM,
416
429
  PAGE_DIAGNOSTICS_PARAM,
417
430
  { name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
418
431
  ],
@@ -428,7 +441,7 @@ export const COMMANDS = [
428
441
  },
429
442
  {
430
443
  name: 'page_drag',
431
- description: '在页面内执行拖动;from/to 均可使用视口坐标或 CSS/@ref,auto 在可见页使用可信 mouse/touch、隐藏页使用 DOM 模拟,并默认观察拖动后的页面变化',
444
+ description: '拖动页面元素或视口坐标,适用于轮播图、滑块和拖放',
432
445
  params: [
433
446
  {
434
447
  name: 'from',
@@ -445,18 +458,14 @@ export const COMMANDS = [
445
458
  {
446
459
  name: 'dragMode',
447
460
  type: '"auto" | "dom" | "mouse" | "touch"',
448
- description: '拖动输入类型;默认 auto,可见页按设备使用可信输入、隐藏页使用 DOM 模拟;dom 可显式强制后台模拟',
461
+ description: '默认 auto:可见页使用匹配设备的可信输入,隐藏页使用 DOM;dom/mouse/touch 可强制指定派发方式',
449
462
  },
450
463
  {
451
464
  name: 'durationMs',
452
465
  type: 'number',
453
466
  description: '拖动持续时间,0–5000ms,默认 400ms;内部自动分段移动',
454
467
  },
455
- {
456
- name: 'observe',
457
- type: 'object | false',
458
- description: '观察选项;传 false 只关闭 DOM/导航观察,默认诊断仍会返回',
459
- },
468
+ PAGE_OBSERVE_PARAM,
460
469
  PAGE_DIAGNOSTICS_PARAM,
461
470
  { name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
462
471
  ],
@@ -467,7 +476,7 @@ export const COMMANDS = [
467
476
  },
468
477
  {
469
478
  name: 'page_type',
470
- description: '向输入框填写文本,兼容 React 受控组件;默认观察校验提示等异步变化',
479
+ description: '向输入框填写文本,兼容 React 受控组件',
471
480
  params: [
472
481
  {
473
482
  name: 'selector',
@@ -477,11 +486,7 @@ export const COMMANDS = [
477
486
  },
478
487
  { name: 'text', type: 'string', required: true, description: '要填写的文本' },
479
488
  { name: 'clearFirst', type: 'boolean', description: '是否先清空原有内容,默认 true' },
480
- {
481
- name: 'observe',
482
- type: 'object | false',
483
- description: '观察选项;传 false 只关闭 DOM/导航观察,默认诊断仍会返回',
484
- },
489
+ PAGE_OBSERVE_PARAM,
485
490
  PAGE_DIAGNOSTICS_PARAM,
486
491
  { name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
487
492
  ],
@@ -489,7 +494,7 @@ export const COMMANDS = [
489
494
  },
490
495
  {
491
496
  name: 'page_hover',
492
- description: '将鼠标悬停在元素上,默认观察下拉菜单、提示信息等 hover 后变化',
497
+ description: '将鼠标悬停在页面元素上',
493
498
  params: [
494
499
  {
495
500
  name: 'selector',
@@ -497,11 +502,7 @@ export const COMMANDS = [
497
502
  required: true,
498
503
  description: '原生 CSS 选择器,或 page_snapshot / 页面动作 observation 返回的 @eN ref(必须带 @ 前缀)',
499
504
  },
500
- {
501
- name: 'observe',
502
- type: 'object | false',
503
- description: '观察选项;传 false 只关闭 DOM/导航观察,默认诊断仍会返回',
504
- },
505
+ PAGE_OBSERVE_PARAM,
505
506
  PAGE_DIAGNOSTICS_PARAM,
506
507
  { name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
507
508
  ],
@@ -509,7 +510,7 @@ export const COMMANDS = [
509
510
  },
510
511
  {
511
512
  name: 'page_scroll',
512
- description: '滚动页面或指定容器,默认观察懒加载等滚动后变化',
513
+ description: '滚动页面或指定容器',
513
514
  params: [
514
515
  {
515
516
  name: 'direction',
@@ -528,11 +529,7 @@ export const COMMANDS = [
528
529
  type: '"self" | "nearest"',
529
530
  description: '默认 self,要求 selector 本身可滚动;nearest 会在其不可滚动时使用最近的可滚动祖先',
530
531
  },
531
- {
532
- name: 'observe',
533
- type: 'object | false',
534
- description: '观察选项;传 false 只关闭 DOM/导航观察,默认诊断仍会返回',
535
- },
532
+ PAGE_OBSERVE_PARAM,
536
533
  PAGE_DIAGNOSTICS_PARAM,
537
534
  { name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
538
535
  ],
@@ -565,7 +562,7 @@ export const COMMANDS = [
565
562
  },
566
563
  {
567
564
  name: 'page_press',
568
- description: '在页面中按下键盘按键,默认观察提交、关闭弹窗等结果',
565
+ description: '在页面中按下键盘按键或组合键',
569
566
  params: [
570
567
  {
571
568
  name: 'key',
@@ -574,11 +571,7 @@ export const COMMANDS = [
574
571
  description: '按键名称:Enter/Tab/Escape/Backspace 等',
575
572
  },
576
573
  { name: 'modifiers', type: 'string[]', description: '修饰键数组:ctrl/alt/shift/meta/cmd' },
577
- {
578
- name: 'observe',
579
- type: 'object | false',
580
- description: '观察选项;传 false 只关闭 DOM/导航观察,默认诊断仍会返回',
581
- },
574
+ PAGE_OBSERVE_PARAM,
582
575
  PAGE_DIAGNOSTICS_PARAM,
583
576
  { name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
584
577
  ],
@@ -638,7 +631,7 @@ export const COMMANDS = [
638
631
  },
639
632
  {
640
633
  name: 'page_upload',
641
- description: '向 <input type="file"> 元素上传文件,默认观察上传状态变化',
634
+ description: '向 <input type="file"> 元素上传一个或多个文件',
642
635
  params: [
643
636
  {
644
637
  name: 'selector',
@@ -647,11 +640,7 @@ export const COMMANDS = [
647
640
  description: '原生 CSS 选择器,或 page_snapshot / 页面动作 observation 返回的 @eN ref(必须带 @ 前缀),必须指向 input[type=file]',
648
641
  },
649
642
  { name: 'filePaths', type: 'string[]', required: true, description: '本地文件路径数组' },
650
- {
651
- name: 'observe',
652
- type: 'object | false',
653
- description: '观察选项;传 false 只关闭 DOM/导航观察,默认诊断仍会返回',
654
- },
643
+ PAGE_OBSERVE_PARAM,
655
644
  PAGE_DIAGNOSTICS_PARAM,
656
645
  { name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
657
646
  ],
@@ -4,7 +4,7 @@ export interface GetRequestsParams {
4
4
  filter?: string;
5
5
  /** Relative time window in seconds. */
6
6
  since?: number;
7
- /** Opaque cursor returned by capture_checkpoint or a previous query. */
7
+ /** Opaque cursor returned by tab_checkpoint or a previous query. */
8
8
  after?: string;
9
9
  includeBody?: boolean;
10
10
  includeHeaders?: boolean;
@@ -19,7 +19,7 @@ export interface GetLogsParams {
19
19
  level?: 'log' | 'warn' | 'error' | 'info' | 'all';
20
20
  /** Relative time window in seconds. */
21
21
  since?: number;
22
- /** Opaque cursor returned by capture_checkpoint or a previous query. */
22
+ /** Opaque cursor returned by tab_checkpoint or a previous query. */
23
23
  after?: string;
24
24
  limit?: number;
25
25
  filter?: string;
@@ -39,6 +39,8 @@ export interface GetEventsParams {
39
39
  event_type?: string;
40
40
  filter?: string;
41
41
  since?: number;
42
+ /** Opaque cursor returned by tab_checkpoint or a previous event query. */
43
+ after?: string;
42
44
  limit?: number;
43
45
  includeRaw?: boolean;
44
46
  }
@@ -299,6 +301,7 @@ export interface PageObservationWaitOptions {
299
301
  export interface PageDiagnosticsOptions {
300
302
  logs?: boolean | Pick<GetLogsParams, 'level' | 'limit' | 'filter'>;
301
303
  requests?: boolean | Pick<GetRequestsParams, 'count' | 'filter' | 'includeBody' | 'includeHeaders' | 'maxBodySize' | 'fields' | 'keysOnly' | 'source'>;
304
+ events?: boolean | Pick<GetEventsParams, 'source' | 'event_type' | 'filter' | 'limit' | 'includeRaw'>;
302
305
  }
303
306
  export type PageDiagnosticsSetting = PageDiagnosticsOptions | boolean;
304
307
  export interface PageClickParams {
@@ -471,6 +474,11 @@ export interface RunActionsParams {
471
474
  tabId: number;
472
475
  }
473
476
  export interface BrowserActionMap {
477
+ tab_checkpoint: {
478
+ request: CaptureCheckpointParams;
479
+ response: CaptureCheckpointResult;
480
+ };
481
+ /** Compatibility alias for tab_checkpoint. */
474
482
  capture_checkpoint: {
475
483
  request: CaptureCheckpointParams;
476
484
  response: CaptureCheckpointResult;
@@ -652,6 +660,7 @@ export type ExtensionBrowserAction = Exclude<BrowserCommandAction, 'browser_list
652
660
  export declare const PAGE_ACT_ACTIONS: readonly ["page_click", "page_drag", "page_type", "page_hover", "page_scroll", "page_press", "page_upload", "page_eval"];
653
661
  export type PageActAction = (typeof PAGE_ACT_ACTIONS)[number];
654
662
  export declare const BROWSER_ACTIONS: {
663
+ readonly tab_checkpoint: true;
655
664
  readonly capture_checkpoint: true;
656
665
  readonly get_requests: true;
657
666
  readonly get_logs: true;
@@ -697,6 +706,7 @@ export declare const BROWSER_ACTIONS: {
697
706
  readonly run_actions: true;
698
707
  };
699
708
  export declare const BROWSER_COMMAND_ACTIONS: {
709
+ readonly tab_checkpoint: true;
700
710
  readonly capture_checkpoint: true;
701
711
  readonly get_requests: true;
702
712
  readonly get_logs: true;
@@ -741,6 +751,7 @@ export declare const BROWSER_COMMAND_ACTIONS: {
741
751
  readonly run_actions: true;
742
752
  };
743
753
  export declare const EXTENSION_BROWSER_ACTIONS: {
754
+ readonly tab_checkpoint: true;
744
755
  readonly capture_checkpoint: true;
745
756
  readonly get_requests: true;
746
757
  readonly get_logs: true;
@@ -17,6 +17,7 @@ export const PAGE_ACT_ACTIONS = [
17
17
  'page_eval',
18
18
  ];
19
19
  export const BROWSER_ACTIONS = {
20
+ tab_checkpoint: true,
20
21
  capture_checkpoint: true,
21
22
  get_requests: true,
22
23
  get_logs: true,
@@ -62,6 +63,7 @@ export const BROWSER_ACTIONS = {
62
63
  run_actions: true,
63
64
  };
64
65
  export const BROWSER_COMMAND_ACTIONS = {
66
+ tab_checkpoint: true,
65
67
  capture_checkpoint: true,
66
68
  get_requests: true,
67
69
  get_logs: true,
@@ -106,6 +108,7 @@ export const BROWSER_COMMAND_ACTIONS = {
106
108
  run_actions: true,
107
109
  };
108
110
  export const EXTENSION_BROWSER_ACTIONS = {
111
+ tab_checkpoint: true,
109
112
  capture_checkpoint: true,
110
113
  get_requests: true,
111
114
  get_logs: true,
package/dist/index.d.ts CHANGED
@@ -10,7 +10,9 @@ export { BROWSER_ACTIONS, BROWSER_COMMAND_ACTIONS, EXTENSION_BROWSER_ACTIONS, PA
10
10
  export type { ActionStep, BrowserAction, BrowserActionMap, BrowserActionRequest, BrowserActionResponse, BrowserCloseParams, BrowserCommandAction, BrowserInfo, BrowserInfoBase, BrowserLaunchParams, BrowserListResult, BrowserReleaseFailure, BrowserReleaseResult, BrowserSource, BrowserStatus, CaptureCheckpointParams, CaptureCheckpointResult, BrowserDevicePresetName, BrowserEmulationOptions, ExtensionBrowserAction, GetApiSchemaParams, GetCookieParams, GetCookieResult, GetEventsParams, GetLogsParams, GetMocksParams, GetRequestsParams, GetUserInfoParams, ManagedBrowserAccount, ManagedBrowserInfo, PageClickParams, PageDragEndpoint, PageDragParams, PageDragPoint, PageActAction, PageDiagnosticsOptions, PageDiagnosticsSetting, PageEvalParams, PageFramesParams, PageHoverParams, PageNavigateParams, PageObservationWaitOptions, PagePressParams, PageScreenshotParams, PageScrollParams, PageSelectedElementParams, PageSnapshotParams, PageSnapshotQuery, PageTypeParams, PageUploadParams, PageWaitParams, RecordParams, RegularBrowserInfo, RequestDomainPermissionParams, RulesResult, RunActionName, RunActionsParams, SelectBrowserParams, SelectBrowserResult, SendRequestFile, SendRequestFormValue, SendMtopRequestParams, SendRequestParams, SetCookieParams, SetCookieResult, SetDeviceEmulationParams, SetMockParams, SetRuleParams, SetTimezoneParams, SetTimezoneResult, TabCloseParams, TabOpenParams, TdbankAccountParams, } from './generated-browser-action-protocol.js';
11
11
  import { type UnifiedInvokeOptions } from './unified.js';
12
12
  import type * as Protocol from './generated-browser-action-protocol.js';
13
- export declare function captureCheckpoint(params?: Protocol.CaptureCheckpointParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'capture_checkpoint'>>;
13
+ export declare function tabCheckpoint(params?: Protocol.CaptureCheckpointParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'tab_checkpoint'>>;
14
+ /** Compatibility wrapper for tabCheckpoint. */
15
+ export declare function captureCheckpoint(params?: Protocol.CaptureCheckpointParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'tab_checkpoint'>>;
14
16
  export declare function getRequests(params?: Protocol.GetRequestsParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'get_requests'>>;
15
17
  export declare function getLogs(params?: Protocol.GetLogsParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'get_logs'>>;
16
18
  export declare function getEvents(params?: Protocol.GetEventsParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'get_events'>>;
package/dist/index.js CHANGED
@@ -7,8 +7,12 @@
7
7
  export { UnifiedClient, UnifiedClient as MearlClient, decodeBrowserTarget, invoke, listCloudConnectors, } from './unified.js';
8
8
  export { BROWSER_ACTIONS, BROWSER_COMMAND_ACTIONS, EXTENSION_BROWSER_ACTIONS, PAGE_ACT_ACTIONS, SEND_REQUEST_MAX_FILES, SEND_REQUEST_MAX_TOTAL_BASE64_FILE_BYTES, SEND_REQUEST_MAX_TOTAL_FILE_BYTES, isBrowserAction, isBrowserCommandAction, isExtensionBrowserAction, } from './generated-browser-action-protocol.js';
9
9
  import { invoke } from './unified.js';
10
+ export function tabCheckpoint(params = {}, options) {
11
+ return invoke('tab_checkpoint', params, options);
12
+ }
13
+ /** Compatibility wrapper for tabCheckpoint. */
10
14
  export function captureCheckpoint(params = {}, options) {
11
- return invoke('capture_checkpoint', params, options);
15
+ return tabCheckpoint(params, options);
12
16
  }
13
17
  export function getRequests(params = {}, options) {
14
18
  return invoke('get_requests', params, options);
package/dist/unified.js CHANGED
@@ -205,7 +205,12 @@ export class UnifiedClient {
205
205
  if (!localAvailable && connectors.length === 0) {
206
206
  throw new Error('No browser host is available. Install @mearl/native-host locally or connect a cloud connector.');
207
207
  }
208
- throw new Error('The browser host for browser_launch is ambiguous. Pass --local, --connector <id|name>, or --browser <global-id>.');
208
+ const availableHosts = [
209
+ ...(localAvailable ? ['this machine [--local]'] : []),
210
+ ...connectors.map(connector => `${connector.name} [${connector.connectorId}]`),
211
+ ].join(', ');
212
+ throw new Error('The browser host for browser_launch is ambiguous. ' +
213
+ `Pass --local, --connector <id|name>, or --browser <global-id>. Available: ${availableHosts}`);
209
214
  }
210
215
  async selectDefaultBrowser(data, options, timeoutSec) {
211
216
  const selector = typeof data.browser === 'string' ? data.browser.trim() : '';
@@ -261,11 +266,14 @@ export class UnifiedClient {
261
266
  async resolveConnector(selector, timeoutSec) {
262
267
  const connectors = (await this.listConnectors(timeoutSec)).connectors;
263
268
  const selection = resolveCloudConnectorSelector(connectors, selector);
269
+ const available = connectors
270
+ .map(connector => `${connector.name} [${connector.connectorId}]`)
271
+ .join(', ');
264
272
  if (selection.status === 'ambiguous') {
265
- throw new Error(`Cloud connector selector "${selector}" is ambiguous. Use an exact connectorId.`);
273
+ throw new Error(`Cloud connector selector "${selector}" is ambiguous. Use an exact connectorId. Available: ${available}`);
266
274
  }
267
275
  if (selection.status !== 'matched') {
268
- throw new Error(`No cloud connector matches "${selector}".`);
276
+ throw new Error(`No cloud connector matches "${selector}". Available: ${available}`);
269
277
  }
270
278
  return selection.connector;
271
279
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mearl/client",
3
- "version": "2.7.1",
3
+ "version": "2.7.3",
4
4
  "description": "Unified Mearl SDK & CLI for local and remote browsers",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -35,7 +35,8 @@
35
35
  "mearl": "./dist/bin.js"
36
36
  },
37
37
  "files": [
38
- "dist"
38
+ "dist",
39
+ "!dist/**/*.map"
39
40
  ],
40
41
  "keywords": [
41
42
  "mearl",
@@ -48,8 +49,9 @@
48
49
  "registry": "https://registry.npmjs.org"
49
50
  },
50
51
  "dependencies": {
52
+ "fastest-levenshtein": "^1.0.16",
51
53
  "ws": "^8.18.0",
52
- "@mearl/cloud-types": "2.7.1"
54
+ "@mearl/cloud-types": "2.7.3"
53
55
  },
54
56
  "devDependencies": {
55
57
  "@types/node": "^24.9.1",