@mearl/client 2.8.2 → 2.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -69,6 +69,7 @@ mearl browser_launch --payload '{"name":"account-b","query":"test_account"}'
69
69
  mearl browser_launch --payload '{"name":"cookie-copy","copyCookieDomains":["example.com"]}'
70
70
  mearl browser_launch --payload '{"name":"cloud-login","provider":"agentbay","persistent":true,"userAgentMode":"desktop","copyCookieDomains":["example.com"],"url":"https://example.com/account"}'
71
71
  mearl browser_launch --browser '<控制浏览器 browserId>' --payload '{"name":"cloud-login","provider":"agentbay","reuse":"require","copyCookieDomains":["example.com"]}'
72
+ mearl browser_launch --payload '{"name":"cloud-tools","provider":"agentbay","copyCookieDomains":"mearl-services"}'
72
73
  mearl browser_launch --payload '{"name":"figma","userAgentMode":"desktop","copyCookieDomains":["figma.com"]}'
73
74
  mearl browser_list
74
75
  mearl browser_release
@@ -84,40 +85,44 @@ mearl browser_release
84
85
  | `--payload <json>` | 直接传入 JSON 参数 |
85
86
  | `--payload-file <path>` | 从文件读取 JSON 参数 |
86
87
  | `--timeout <seconds>` | 请求超时时间 |
87
- | `--compact` | 紧凑输出 |
88
+ | `--compact` | stdout 紧凑输出 |
88
89
  | `--output <path>` | 将结果写入文件(如截图) |
89
90
  | `--browser <id\|名称>` | 指定目标浏览器 |
90
91
  | `--connector <id\|名称>` | 限制到一台远端机器 |
91
92
  | `--local` | 只使用当前机器 |
93
+ | `--cdp` | 当前机器强制使用 CDP |
92
94
  | `--server <url>` | 覆盖 cloud-server 地址 |
93
95
 
96
+ `check` 有独立的选项说明,运行 `mearl check --help` 查看。其中 `--json` 仅用于输出机器可读的检查结果。
97
+
94
98
  ## 支持的操作
95
99
 
96
- | 分类 | Actions |
97
- | ----------- | --------------------------------------------------------------------------------------------------------------------- |
98
- | API 调试 | `tab_checkpoint` `get_requests` `get_logs` `get_events` `get_api_schema` |
99
- | Mock & 规则 | `set_mock` `get_mocks` `set_rule` `get_rules` |
100
- | 网络代理 | `send_request` `send_mtop_request` |
101
- | 标签页 | `tab_open` `tab_close` `tab_list` |
102
- | 页面操作 | `page_click` `page_drag` `page_type` `page_scroll` `page_eval` `page_press` `page_wait` `page_navigate` `page_upload` |
103
- | 页面感知 | `page_snapshot` `page_screenshot` `page_selected_element` `page_frames` |
104
- | 环境与状态 | `set_device_emulation` `set_timezone` `get_cookie` `set_cookie` |
105
- | 用户信息 | `get_user_info` |
106
- | 录制 | `record_start` `record_stop` |
107
- | TDBank | `tdbank_account` |
108
- | 浏览器 | `browser_list` `browser_release` `browser_launch` `browser_close` |
100
+ | 分类 | Actions |
101
+ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
102
+ | API 调试 | `tab_checkpoint` `get_requests` `get_logs` `get_events` `get_api_schema` |
103
+ | Mock & 规则 | `set_mock` `get_mocks` `set_rule` `get_rules` |
104
+ | 网络请求 | `send_request` `send_mtop_request` `request_domain_permission` |
105
+ | 标签页 | `tab_open` `tab_close` `tab_list` |
106
+ | 页面操作 | `page_click` `page_drag` `page_type` `page_hover` `page_scroll` `page_eval` `page_press` `page_wait` `page_navigate` `page_upload` |
107
+ | 组合调用 | `run_actions` |
108
+ | 页面感知 | `page_snapshot` `page_screenshot` `page_selected_element` `page_frames` |
109
+ | 环境与 Cookie | `set_device_emulation` `set_app_profile` `set_timezone` `get_cookie` `set_cookie` |
110
+ | 用户信息 | `get_user_info` |
111
+ | 录制 | `record_start` `record_stop` |
112
+ | TDBank | `tdbank_account` |
113
+ | 浏览器 | `browser_list` `browser_release` `browser_launch` `browser_close` |
109
114
 
110
115
  页面交互动作(`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` 默认裸执行,可按需开启观察或诊断。
111
116
 
112
117
  `page_snapshot` 默认返回完整 AX Tree;长列表可传 `mode: "viewport"`,只需要当前视口内的控件时传 `mode: "interactive"`,已知 CSS 区域时传 `rootSelector`,已有 ref 时传 `rootRef`(可用 `ancestorDepth` 向上补充上下文),只查找特定文案或角色时传 `query`。视口内缺少 AX 控件语义时,`interactive` 会自动回退到 viewport,并返回 `fallbackMode: "viewport"`。`maxNodes` / `maxChars` 截断会同时保留首尾内容。
113
118
 
114
- 重复文本点击可用 `page_click.scope` 限定 CSS / ref 子树;ref 指向滚动容器内的子节点时,可用 `page_scroll.containerPolicy: "nearest"` 自动解析最近可滚动祖先。点击结果的 `resolvedTarget` 和滚动结果的前后位置、边界字段可用于诊断实际目标与效果。
119
+ 重复文本点击可用 `page_click.scope` 限定 CSS / ref 子树;浏览器扩展后端中,容器或 iframe 内的点坐标使用 `coordinateSpace: "active-frame"`,CSS/text 查询可用 `frameId` 显式指定 frame。点击结果通过 `requestedTarget`、`resolvedTarget`、`dispatchTarget`、`hitTarget` 和 `coordinates` 区分请求语义、DOM 解析、派发节点与可信输入实际命中;ref 指向滚动容器内的子节点时,可用 `page_scroll.containerPolicy: "nearest"` 自动解析最近可滚动祖先。
115
120
 
116
121
  `browser_list` 统一列出普通浏览器和托管浏览器。`type` 区分 `regular` / `managed`,`status` 区分 `connected` / `running_disconnected` / `stopped`;只有 `connected` 的浏览器可作为操作目标。
117
122
 
118
123
  `browser_release` 仅在用户明确要求结束调试、退出接管或清理会话资源时使用,不作为普通任务收尾。它会释放当前目标浏览器的 debugger/CDP 控制和会话级临时状态(包括设备/时区模拟),保留浏览器及全部标签页;后续浏览器操作可自动重新建立控制。
119
124
 
120
- 托管浏览器使用独立 Profile。控制浏览器需先登录 TDBank;生成的 SSO 地址在本地内部传递,本地实例可以使用 `headless: true`(默认)完成测试账号登录。AgentBay 固定为非 headless,传 `headless: true` 会被拒绝;`imageId` 可指定镜像别名或具体镜像 ID,省略时使用已验证的 Linux Browser Use 内网镜像。`persistent: true` 会让本地实例保留 Profile,让 AgentBay 同名实例绑定稳定的云端 Browser Context;正常关闭时同步 Cookie、LocalStorage、IndexedDB 等状态,下次启动无需再次复制本地登录态。`deleteProfile: true` 会显式删除对应 Profile 或 Context。AgentBay 的 `reuse` 支持 `never`(默认)、`prefer` 和 `require`:`prefer` 存在运行实例时复用、否则创建,`require` 只复用且不会意外创建计费会话。`copyCookieDomains` 可在首次启动或复用运行实例时把控制浏览器指定域的 Cookie 写入目标,Cookie 值不会经过 cloud-server,也不会出现在命令结果或日志中;`userAgentMode: "desktop"` 让本地实例使用匹配本机 Chrome 版本的桌面 UA,AgentBay 则复用当前控制浏览器的桌面 UA。`browser_list` 仅通过 `agentbayImageId`、`agentbayContextId` 和 `agentbayContextName` 返回 AgentBay 实例的稳定配置。无影浏览器串流入口包含临时访问凭据且会过期,因此不会写入实例记录或列表结果;需要时运行 `mearl check --browser <id|名称>` 实时获取,并按敏感信息处理。完整设计见 [托管浏览器与 TDBank 多账号设计](../../docs/managed-browsers.md)。
125
+ 托管浏览器使用独立 Profile。控制浏览器需先登录 TDBank;生成的 SSO 地址在本地内部传递,本地实例可以使用 `headless: true`(默认)完成测试账号登录。AgentBay 固定为非 headless,传 `headless: true` 会被拒绝;`imageId` 可指定镜像别名或具体镜像 ID,省略时使用已验证的 Linux Browser Use 内网镜像。`persistent: true` 会让本地实例保留 Profile,让 AgentBay 同名实例绑定稳定的云端 Browser Context;正常关闭时同步 Cookie、LocalStorage、IndexedDB 等状态,下次启动无需再次复制本地登录态。`deleteProfile: true` 会显式删除对应 Profile 或 Context。AgentBay 的 `reuse` 支持 `never`(默认)、`prefer` 和 `require`:`prefer` 存在运行实例时复用、否则创建,`require` 只复用且不会意外创建计费会话。`copyCookieDomains` 传数组时把控制浏览器指定域的 Cookie 写入目标,传 `"mearl-services"` 时同步 Mearl 依赖平台登录态。Cookie 值不会经过 cloud-server,也不会出现在命令结果或日志中;`userAgentMode: "desktop"` 让本地实例使用匹配本机 Chrome 版本的桌面 UA,AgentBay 则复用当前控制浏览器的桌面 UA。`browser_list` 仅通过 `agentbayImageId`、`agentbayContextId` 和 `agentbayContextName` 返回 AgentBay 实例的稳定配置。无影浏览器串流入口包含临时访问凭据且会过期,因此不会写入实例记录或列表结果;需要时运行 `mearl check --browser <id|名称>` 实时获取,并按敏感信息处理。完整设计见 [托管浏览器与 TDBank 多账号设计](../../docs/managed-browsers.md)。
121
126
 
122
127
  ## 架构
123
128
 
package/dist/check.js CHANGED
@@ -190,6 +190,13 @@ export async function runUnifiedCheck(options, dependencies = {}) {
190
190
  const browserChecks = [];
191
191
  await Promise.all(targets.map(async (browser) => {
192
192
  try {
193
+ if (options.transport === 'cdp') {
194
+ await client.invoke('tab_list', {}, {
195
+ timeoutSec,
196
+ browser: browser.browserId,
197
+ transport: 'cdp',
198
+ });
199
+ }
193
200
  const versions = (await client.invoke('get_versions', {}, {
194
201
  timeoutSec,
195
202
  browser: browser.browserId,
@@ -243,7 +250,9 @@ export async function runUnifiedCheck(options, dependencies = {}) {
243
250
  status: accessUrlWarning ? 'warning' : 'ok',
244
251
  label: accessUrlWarning
245
252
  ? 'Browser command path ready; AgentBay access URL unavailable'
246
- : 'Browser command path',
253
+ : options.transport === 'cdp'
254
+ ? 'CDP command path'
255
+ : 'Browser command path',
247
256
  details,
248
257
  },
249
258
  versions: publicVersions,
package/dist/cli.d.ts CHANGED
@@ -2,4 +2,20 @@ export interface MearlCliOptions {
2
2
  commandName?: string;
3
3
  clientVersion?: string;
4
4
  }
5
+ export interface ParsedArgs {
6
+ action: string;
7
+ browser?: string;
8
+ compact: boolean;
9
+ connector?: string;
10
+ forceCdp: boolean;
11
+ json: boolean;
12
+ local: boolean;
13
+ outputPath?: string;
14
+ payload: Record<string, any>;
15
+ serverUrl?: string;
16
+ serverUrlSource?: string;
17
+ timeoutSec: number;
18
+ timeoutOption?: string;
19
+ }
20
+ export declare function parseClientArgs(args: string[]): ParsedArgs;
5
21
  export declare function runMearlCli(args: string[], options?: MearlCliOptions): Promise<number>;
package/dist/cli.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { readFileSync, writeFileSync } from 'node:fs';
2
2
  import { resolve } from 'node:path';
3
+ import { Command, CommanderError } from 'commander';
3
4
  import { resolveActionTimeoutSec } from './actionTimeouts.js';
4
5
  import { runUnifiedCheck, parseCheckTimeout } from './check.js';
5
6
  import { commandInput, findCommandSuggestions, formatCommandSuggestions, } from './commandSuggestions.js';
@@ -14,7 +15,7 @@ const CATEGORIES = [
14
15
  },
15
16
  { title: 'Mock & 规则', names: ['set_mock', 'get_mocks', 'set_rule', 'get_rules'] },
16
17
  {
17
- title: '网络代理',
18
+ title: '网络请求',
18
19
  names: ['send_request', 'send_mtop_request', 'request_domain_permission'],
19
20
  },
20
21
  { title: '标签页', names: ['tab_open', 'tab_close', 'tab_list'] },
@@ -59,10 +60,6 @@ const BUILTIN_COMMANDS = [
59
60
  ];
60
61
  const SUGGESTABLE_COMMANDS = [...COMMANDS, ...BUILTIN_COMMANDS];
61
62
  const ADVANCED_BUILTIN_COMMANDS = new Set(['connector_list']);
62
- function optionValue(args, name) {
63
- const index = args.indexOf(name);
64
- return index >= 0 ? args[index + 1] : undefined;
65
- }
66
63
  function printUsage(commandName, version) {
67
64
  const lines = [
68
65
  `${commandName} v${version}`,
@@ -70,18 +67,17 @@ function printUsage(commandName, version) {
70
67
  '用法:',
71
68
  ` ${commandName} <action> [选项]`,
72
69
  ` ${commandName} <action> --help`,
73
- ` ${commandName} check [--browser <id|名称>] [--connector <id|名称>]`,
70
+ ` ${commandName} check [选项]`,
74
71
  '',
75
72
  '统一目标发现:',
76
- ' browser_list 默认列出当前机器和 cloud-server 下所有 connector 的浏览器。',
77
- ' 后续操作使用列表返回的全局 browserId,客户端会自动选择本地或远端传输。',
73
+ ' browser_list 默认聚合当前机器及已配置 cloud-server 下的浏览器。',
74
+ ' 后续操作通过 --browser <browserId> 指定目标,客户端会自动选择本地或远端传输。',
78
75
  '',
79
76
  '通用选项:',
80
77
  ' --payload <json> 直接传入 JSON 参数',
81
78
  ' --payload-file <path> 从文件读取整个 JSON 参数',
82
79
  ' --timeout <seconds> 超时时间(默认按 action 推导)',
83
- ' --compact 输出紧凑格式 JSON',
84
- ' --json check 输出机器可读 JSON',
80
+ ' --compact stdout 输出紧凑格式 JSON',
85
81
  ' --output <path> 保存输出或截图',
86
82
  ' --browser <id|名称> 指定 browser_list 返回的浏览器',
87
83
  ' --connector <id|名称> 限制到一台远端 connector',
@@ -89,6 +85,10 @@ function printUsage(commandName, version) {
89
85
  ' --cdp 当前机器强制使用 CDP(隐含 --local)',
90
86
  ' --server <url> 覆盖 cloud-server WebSocket URL',
91
87
  '',
88
+ '其他选项:',
89
+ ' -h, --help 查看帮助',
90
+ ' -v, --version 查看版本',
91
+ '',
92
92
  '内置命令:',
93
93
  ' check 检查指定浏览器,未指定时检查全部已连接浏览器',
94
94
  ];
@@ -97,12 +97,31 @@ function printUsage(commandName, version) {
97
97
  for (const name of category.names) {
98
98
  const command = COMMAND_MAP.get(name);
99
99
  if (command)
100
- lines.push(` ${name.padEnd(26)}${command.description}`);
100
+ lines.push(` ${name.padEnd(26)}${command.summary ?? command.description}`);
101
101
  }
102
102
  }
103
103
  lines.push('', `运行 ${commandName} <action> --help 查看 action 参数。`);
104
104
  console.error(lines.join('\n'));
105
105
  }
106
+ function printCheckHelp(commandName) {
107
+ console.error([
108
+ 'check',
109
+ ' 检查指定浏览器,未指定时检查全部已连接浏览器',
110
+ '',
111
+ '用法:',
112
+ ` ${commandName} check [选项]`,
113
+ '',
114
+ '选项:',
115
+ ' --browser <id|名称> 只检查指定浏览器',
116
+ ' --connector <id|名称> 限制到一台远端 connector',
117
+ ' --local 只检查当前机器,不能与 --connector 同时使用',
118
+ ' --cdp 当前机器强制使用 CDP(隐含 --local)',
119
+ ' --server <url> 覆盖 cloud-server WebSocket URL',
120
+ ' --timeout <seconds> 单项检查超时时间,默认 5 秒',
121
+ ' --json 输出机器可读 JSON',
122
+ ' -h, --help 查看帮助',
123
+ ].join('\n'));
124
+ }
106
125
  function printAdvancedCommandHelp(commandName, action) {
107
126
  if (action !== 'connector_list')
108
127
  return;
@@ -115,12 +134,13 @@ function printAdvancedCommandHelp(commandName, action) {
115
134
  ].join('\n'));
116
135
  }
117
136
  function printCommandHelp(commandName, command) {
137
+ const payloadUsage = command.params?.length ? ' [--payload <json> | --payload-file <path>]' : '';
118
138
  const lines = [
119
139
  `${command.name}`,
120
140
  ` ${command.description}`,
121
141
  '',
122
142
  '用法:',
123
- ` ${commandName} ${command.name} [--payload <json>] [--browser <id|名称>]`,
143
+ ` ${commandName} ${command.name}${payloadUsage} [通用选项]`,
124
144
  '',
125
145
  ];
126
146
  if (command.params?.length) {
@@ -136,6 +156,7 @@ function printCommandHelp(commandName, command) {
136
156
  for (const example of command.examples)
137
157
  lines.push(` ${commandName} ${example}`);
138
158
  }
159
+ lines.push('', `运行 ${commandName} --help 查看通用选项。`);
139
160
  console.error(lines.join('\n'));
140
161
  }
141
162
  function printUnknownCommand(commandName, args) {
@@ -159,9 +180,7 @@ function parsePositiveTimeout(value, fallback) {
159
180
  }
160
181
  return parsed;
161
182
  }
162
- function parsePayload(args) {
163
- const payloadRaw = optionValue(args, '--payload');
164
- const payloadFile = optionValue(args, '--payload-file');
183
+ function parsePayload(payloadRaw, payloadFile) {
165
184
  if (payloadRaw !== undefined && payloadFile !== undefined) {
166
185
  throw new Error('--payload 与 --payload-file 不能同时使用');
167
186
  }
@@ -183,33 +202,7 @@ function parsePayload(args) {
183
202
  }
184
203
  return {};
185
204
  }
186
- function validateOptions(args) {
187
- const optionsWithValues = new Set([
188
- '--payload',
189
- '--payload-file',
190
- '--timeout',
191
- '--output',
192
- '--browser',
193
- '--connector',
194
- '--server',
195
- ]);
196
- const flags = new Set(['--compact', '--json', '--local', '--cdp', '--help', '-h']);
197
- for (let index = 1; index < args.length; index += 1) {
198
- const arg = args[index];
199
- if (optionsWithValues.has(arg)) {
200
- if (!args[index + 1] || args[index + 1].startsWith('--')) {
201
- throw new Error(`缺少 ${arg} 的参数值`);
202
- }
203
- index += 1;
204
- continue;
205
- }
206
- if (flags.has(arg))
207
- continue;
208
- throw new Error(`未知参数: ${arg}`);
209
- }
210
- }
211
- function resolveServer(args) {
212
- const explicit = optionValue(args, '--server');
205
+ function resolveServer(explicit) {
213
206
  if (explicit)
214
207
  return { serverUrl: explicit, serverUrlSource: '--server' };
215
208
  if (process.env.MEARL_SERVER_URL) {
@@ -220,31 +213,59 @@ function resolveServer(args) {
220
213
  ? { serverUrl: config.server, serverUrlSource: getCloudServerConfigPath() }
221
214
  : {};
222
215
  }
223
- function parseArgs(args) {
224
- validateOptions(args);
225
- const action = args[0];
226
- const json = args.includes('--json');
216
+ export function parseClientArgs(args) {
217
+ const program = new Command()
218
+ .name('mearl')
219
+ .helpOption(false)
220
+ .allowExcessArguments(false)
221
+ .exitOverride()
222
+ .configureOutput({ writeErr: () => { }, writeOut: () => { } })
223
+ .argument('<action>')
224
+ .option('--payload <json>')
225
+ .option('--payload-file <path>')
226
+ .option('--timeout <seconds>')
227
+ .option('--compact')
228
+ .option('--json')
229
+ .option('--output <path>')
230
+ .option('--browser <id-or-name>')
231
+ .option('--connector <id-or-name>')
232
+ .option('--local')
233
+ .option('--cdp')
234
+ .option('--server <url>');
235
+ try {
236
+ program.parse(['node', 'mearl', ...args]);
237
+ }
238
+ catch (error) {
239
+ if (error instanceof CommanderError) {
240
+ throw new Error(error.message.replace(/^error:\s*/i, ''), { cause: error });
241
+ }
242
+ throw error;
243
+ }
244
+ const action = program.processedArgs[0];
245
+ const options = program.opts();
246
+ const json = options.json === true;
227
247
  if (json && action !== 'check')
228
248
  throw new Error('--json 仅适用于 check');
229
- const payload = parsePayload(args);
249
+ const payload = parsePayload(options.payload, options.payloadFile);
230
250
  const fallbackTimeout = resolveActionTimeoutSec(action, payload, 60);
231
- const forceCdp = args.includes('--cdp');
232
- const local = forceCdp || args.includes('--local');
233
- const connector = optionValue(args, '--connector');
251
+ const forceCdp = options.cdp === true;
252
+ const local = forceCdp || options.local === true;
253
+ const connector = options.connector;
234
254
  if (local && connector)
235
255
  throw new Error('--local/--cdp 不能与 --connector 同时使用');
236
256
  return {
237
257
  action,
238
258
  payload,
239
- timeoutSec: parsePositiveTimeout(optionValue(args, '--timeout'), fallbackTimeout),
240
- compact: args.includes('--compact'),
259
+ timeoutSec: parsePositiveTimeout(options.timeout, fallbackTimeout),
260
+ ...(options.timeout !== undefined ? { timeoutOption: options.timeout } : {}),
261
+ compact: options.compact === true,
241
262
  forceCdp,
242
263
  json,
243
264
  local,
244
- ...(optionValue(args, '--output') ? { outputPath: optionValue(args, '--output') } : {}),
245
- ...(optionValue(args, '--browser') ? { browser: optionValue(args, '--browser') } : {}),
265
+ ...(options.output ? { outputPath: options.output } : {}),
266
+ ...(options.browser ? { browser: options.browser } : {}),
246
267
  ...(connector ? { connector } : {}),
247
- ...resolveServer(args),
268
+ ...resolveServer(options.server),
248
269
  };
249
270
  }
250
271
  function screenshotData(action, result) {
@@ -285,10 +306,12 @@ export async function runMearlCli(args, options = {}) {
285
306
  const command = COMMAND_MAP.get(args[0]);
286
307
  if (command)
287
308
  printCommandHelp(commandName, command);
309
+ else if (args[0] === 'check')
310
+ printCheckHelp(commandName);
288
311
  else if (ADVANCED_BUILTIN_COMMANDS.has(args[0])) {
289
312
  printAdvancedCommandHelp(commandName, args[0]);
290
313
  }
291
- else if (args[0]?.startsWith('-') || BUILTIN_COMMANDS.some(item => item.name === args[0])) {
314
+ else if (args[0]?.startsWith('-')) {
292
315
  printUsage(commandName, clientVersion);
293
316
  }
294
317
  else {
@@ -305,14 +328,14 @@ export async function runMearlCli(args, options = {}) {
305
328
  }
306
329
  let parsed;
307
330
  try {
308
- parsed = parseArgs(args);
331
+ parsed = parseClientArgs(args);
309
332
  }
310
333
  catch (error) {
311
334
  console.error(error instanceof Error ? error.message : String(error));
312
335
  return 2;
313
336
  }
314
337
  if (parsed.action === 'check') {
315
- const timeoutSec = parseCheckTimeout(optionValue(args, '--timeout'));
338
+ const timeoutSec = parseCheckTimeout(parsed.timeoutOption);
316
339
  if (timeoutSec === null) {
317
340
  console.error('--timeout 必须是正整数秒');
318
341
  return 2;
@@ -8,6 +8,8 @@ export interface ParamDef {
8
8
  export interface CommandDef {
9
9
  name: BrowserCommandAction;
10
10
  description: string;
11
+ /** 顶层命令列表使用的简短描述;完整说明保留在 action help。 */
12
+ summary?: string;
11
13
  /** CLI 中用于推荐 canonical action 的常见表达,不会作为可执行 action。 */
12
14
  aliases?: readonly string[];
13
15
  /** payload 字段说明 */
@@ -372,10 +374,12 @@ export declare const COMMANDS: readonly [{
372
374
  }, {
373
375
  readonly name: "browser_list";
374
376
  readonly description: "列出所有浏览器及其连接状态、类型和托管实例信息;AgentBay 可包含镜像与持久化 Context";
377
+ readonly summary: "列出本地及远端浏览器与连接状态";
375
378
  readonly examples: ["browser_list"];
376
379
  }, {
377
380
  readonly name: "browser_release";
378
381
  readonly description: "按用户明确要求释放调试控制和会话级临时效果(含设备/时区模拟),保留浏览器和全部标签页;不用于普通任务收尾";
382
+ readonly summary: "释放浏览器调试控制及会话级临时效果";
379
383
  readonly examples: ["browser_release", "browser_release --browser chrome-a"];
380
384
  }, {
381
385
  readonly name: "browser_launch";
@@ -439,10 +443,10 @@ export declare const COMMANDS: readonly [{
439
443
  readonly description: "CDP 控制浏览器中用于读取 TDBank Cookie 的标签页";
440
444
  }, {
441
445
  readonly name: "copyCookieDomains";
442
- readonly type: "string[]";
443
- readonly description: "从控制浏览器复制到本地新实例或 AgentBay 新建/复用实例的 Cookie 域名列表,可与本地 TDBank 登录组合";
446
+ readonly type: "string[] | \"mearl-services\"";
447
+ readonly description: "从控制浏览器复制 Cookie:传域名数组,或传 mearl-services 同步 Mearl 依赖平台登录态";
444
448
  }];
445
- readonly examples: ["browser_launch --payload '{\"name\":\"cloud-a\",\"provider\":\"agentbay\",\"userAgentMode\":\"desktop\",\"url\":\"https://example.com\"}'", "browser_launch --payload '{\"name\":\"cloud-public\",\"provider\":\"agentbay\",\"imageId\":\"browser_latest\",\"url\":\"https://example.com\"}'", "browser_launch --payload '{\"name\":\"cloud-login\",\"provider\":\"agentbay\",\"persistent\":true,\"copyCookieDomains\":[\"example.com\"],\"url\":\"https://example.com/account\"}'", "browser_launch --payload '{\"name\":\"cloud-login\",\"provider\":\"agentbay\",\"reuse\":\"require\",\"copyCookieDomains\":[\"example.com\"]}'", "browser_launch --payload '{\"name\":\"account-a\",\"headless\":true,\"accountId\":12345}'", "browser_launch --payload '{\"name\":\"figma\",\"userAgentMode\":\"desktop\",\"copyCookieDomains\":[\"figma.com\"]}'", "browser_launch --payload '{\"name\":\"account-b\",\"query\":\"test_account\",\"url\":\"https://www.taobao.com\"}'", "browser_launch --payload '{\"name\":\"with-cookies\",\"copyCookieDomains\":[\"example.com\",\"sub.example.org\"]}'"];
449
+ readonly examples: ["browser_launch --payload '{\"name\":\"cloud-a\",\"provider\":\"agentbay\",\"userAgentMode\":\"desktop\",\"url\":\"https://example.com\"}'", "browser_launch --payload '{\"name\":\"cloud-public\",\"provider\":\"agentbay\",\"imageId\":\"browser_latest\",\"url\":\"https://example.com\"}'", "browser_launch --payload '{\"name\":\"cloud-login\",\"provider\":\"agentbay\",\"persistent\":true,\"copyCookieDomains\":[\"example.com\"],\"url\":\"https://example.com/account\"}'", "browser_launch --payload '{\"name\":\"cloud-login\",\"provider\":\"agentbay\",\"reuse\":\"require\",\"copyCookieDomains\":[\"example.com\"]}'", "browser_launch --payload '{\"name\":\"cloud-tools\",\"provider\":\"agentbay\",\"copyCookieDomains\":\"mearl-services\"}'", "browser_launch --payload '{\"name\":\"account-a\",\"headless\":true,\"accountId\":12345}'", "browser_launch --payload '{\"name\":\"figma\",\"userAgentMode\":\"desktop\",\"copyCookieDomains\":[\"figma.com\"]}'", "browser_launch --payload '{\"name\":\"account-b\",\"query\":\"test_account\",\"url\":\"https://www.taobao.com\"}'", "browser_launch --payload '{\"name\":\"with-cookies\",\"copyCookieDomains\":[\"example.com\",\"sub.example.org\"]}'"];
446
450
  }, {
447
451
  readonly name: "browser_close";
448
452
  readonly description: "关闭指定托管浏览器并按策略保留或清理本地 Profile / AgentBay Context";
@@ -510,6 +514,10 @@ export declare const COMMANDS: readonly [{
510
514
  readonly name: "simulateSystemBars";
511
515
  readonly type: "boolean";
512
516
  readonly description: "与 appProfile 配合;是否模拟顶部状态/导航栏与底部手势栏,默认 true";
517
+ }, {
518
+ readonly name: "bridgeConfig";
519
+ readonly type: "object";
520
+ readonly description: "与 appProfile 配合;声明式覆盖桥方法,形如 {methods:{api:{behavior|response|noop,silent?}}}";
513
521
  }];
514
522
  readonly examples: ["tab_open --payload '{\"url\":\"https://example.com\"}'", "tab_open --payload '{\"url\":\"https://example.com/page\",\"reuse\":\"prefer\",\"match\":{\"ignoreSearch\":true}}'", "tab_open --payload '{\"url\":\"https://m.example.com\",\"emulation\":{\"preset\":\"iphone-15-pro\"}}'", "tab_open --payload '{\"url\":\"https://market.m.taobao.com/app/trip/rx-home/pages/home\",\"appProfile\":\"fliggy\"}'", "tab_open --payload '{\"url\":\"https://example.com\",\"appProfile\":\"fliggy\",\"os\":\"android\"}'", "tab_open --payload '{\"url\":\"https://example.com\",\"group\":\"验证任务\"}'"];
515
523
  }, {
@@ -525,7 +533,7 @@ export declare const COMMANDS: readonly [{
525
533
  readonly examples: ["tab_close --payload '{\"tabId\":123}'"];
526
534
  }, {
527
535
  readonly name: "tab_list";
528
- readonly description: "获取当前窗口所有标签页列表";
536
+ readonly description: "列出目标浏览器所有窗口中的标签页";
529
537
  readonly aliases: readonly ["tabs", "list_tabs", "show_tabs"];
530
538
  readonly examples: ["tab_list"];
531
539
  }, {
@@ -542,7 +550,15 @@ export declare const COMMANDS: readonly [{
542
550
  }, {
543
551
  readonly name: "point";
544
552
  readonly type: "{ x: number; y: number }";
545
- readonly description: "按视口坐标点击(CSS 像素)。selector/text 都不适用的兜底场景";
553
+ readonly description: "按视口坐标点击(CSS 像素)。默认使用 outer-viewport;容器或 iframe 内坐标配合 coordinateSpace: \"active-frame\"";
554
+ }, {
555
+ readonly name: "frameId";
556
+ readonly type: "string";
557
+ readonly description: "浏览器扩展后端:显式指定 CSS/text 查询或 active-frame 坐标所属的 frame;省略时容器模式自动使用当前业务 frame";
558
+ }, {
559
+ readonly name: "coordinateSpace";
560
+ readonly type: "\"outer-viewport\" | \"active-frame\"";
561
+ readonly description: "仅配合 point 使用;默认 outer-viewport;浏览器扩展后端的 active-frame 会换算 iframe 偏移与缩放后派发可信输入";
546
562
  }, {
547
563
  readonly name: "role";
548
564
  readonly type: "string";
@@ -565,7 +581,7 @@ export declare const COMMANDS: readonly [{
565
581
  readonly required: true;
566
582
  readonly description: "目标标签页 ID";
567
583
  }];
568
- 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}}'"];
584
+ 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}}'", "page_click --payload '{\"point\":{\"x\":196,\"y\":240},\"coordinateSpace\":\"active-frame\"}'"];
569
585
  }, {
570
586
  readonly name: "page_drag";
571
587
  readonly description: "拖动页面元素或视口坐标,适用于轮播图、滑块和拖放";
@@ -818,7 +834,7 @@ export declare const COMMANDS: readonly [{
818
834
  readonly examples: ["page_snapshot", "page_snapshot --payload '{\"tabId\":1,\"mode\":\"viewport\"}'", "page_snapshot --payload '{\"tabId\":1,\"rootSelector\":\"[role=dialog]\"}'", "page_snapshot --payload '{\"tabId\":1,\"rootRef\":\"@e8\",\"ancestorDepth\":1}'", "page_snapshot --payload '{\"tabId\":1,\"query\":{\"text\":\"保存\",\"role\":\"button\"}}'"];
819
835
  }, {
820
836
  readonly name: "page_screenshot";
821
- readonly description: "获取当前页面或指定元素截图";
837
+ readonly description: "获取当前视口或指定元素截图";
822
838
  readonly outputFlag: true;
823
839
  readonly params: [{
824
840
  readonly name: "selector";
@@ -860,7 +876,7 @@ export declare const COMMANDS: readonly [{
860
876
  readonly examples: ["page_selected_element", "page_selected_element --output ./element.png"];
861
877
  }, {
862
878
  readonly name: "get_user_info";
863
- readonly description: "获取当前登录用户的信息";
879
+ readonly description: "获取当前浏览器登录的阿里员工信息";
864
880
  readonly params: [{
865
881
  readonly name: "detail";
866
882
  readonly type: "boolean";
@@ -879,6 +895,7 @@ export declare const COMMANDS: readonly [{
879
895
  }, {
880
896
  readonly name: "record_stop";
881
897
  readonly description: "停止录制并返回完整结果(操作 + 关联请求);未在录制时不报错,返回 wasRecording: false";
898
+ readonly summary: "停止录制并返回操作和关联请求";
882
899
  readonly params: [{
883
900
  readonly name: "tabId";
884
901
  readonly type: "number";
@@ -888,6 +905,7 @@ export declare const COMMANDS: readonly [{
888
905
  }, {
889
906
  readonly name: "set_device_emulation";
890
907
  readonly description: "把目标 tab 切换为移动端模拟(视口/UA/触摸),等价 DevTools 设备工具栏,作用域 per-tab;需保持调试控制才持续生效";
908
+ readonly summary: "设置或清除目标标签页的设备模拟";
891
909
  readonly params: [{
892
910
  readonly name: "enabled";
893
911
  readonly type: "boolean";
@@ -939,6 +957,7 @@ export declare const COMMANDS: readonly [{
939
957
  }, {
940
958
  readonly name: "set_app_profile";
941
959
  readonly description: "把目标 tab 切换为 App 容器模拟态(客户端 UA + JSBridge 托管 + 页面跳转 iframe 容器栈 + scheme 唤端映射 + 自适应系统标题栏),系统栏由 iframe 外层统一渲染,并根据页面协议与桥调用切换普通、沉浸或隐藏状态;用于桌面浏览器近似实机验证 App 内 H5,需保持调试控制才持续生效";
960
+ readonly summary: "设置或清除目标标签页的 App 容器模拟";
942
961
  readonly params: [{
943
962
  readonly name: "enabled";
944
963
  readonly type: "boolean";
@@ -968,6 +987,10 @@ export declare const COMMANDS: readonly [{
968
987
  readonly name: "emulation";
969
988
  readonly type: "object";
970
989
  readonly description: "覆盖档案推荐的设备模拟参数,字段同 set_device_emulation 去掉 enabled";
990
+ }, {
991
+ readonly name: "bridgeConfig";
992
+ readonly type: "object";
993
+ readonly description: "声明式覆盖桥方法,形如 {methods:{api:{behavior|response|noop,silent?}}};不执行配置脚本";
971
994
  }, {
972
995
  readonly name: "reload";
973
996
  readonly type: "boolean";
@@ -1051,7 +1074,7 @@ export declare const COMMANDS: readonly [{
1051
1074
  readonly examples: ["set_cookie --payload '{\"tabId\":12345,\"name\":\"feature_flag\",\"value\":\"enabled\"}'", "set_cookie --payload '{\"tabId\":12345,\"name\":\"edith_switch_br.rx-vehicle-search_home\",\"value\":\"3.6.63\",\"domain\":\"taobao.com\",\"reload\":true}'"];
1052
1075
  }, {
1053
1076
  readonly name: "page_frames";
1054
- readonly description: "获取页面所有 iframe 列表";
1077
+ readonly description: "获取页面主 frame 与所有 iframe 列表";
1055
1078
  readonly params: [{
1056
1079
  readonly name: "tabId";
1057
1080
  readonly type: "number";
@@ -1061,7 +1084,7 @@ export declare const COMMANDS: readonly [{
1061
1084
  readonly examples: ["page_frames --payload '{\"tabId\":12345}'"];
1062
1085
  }, {
1063
1086
  readonly name: "request_domain_permission";
1064
- readonly description: "申请访问指定域名的权限(弹窗让用户授权)";
1087
+ readonly description: "申请访问指定域名的权限(必要时弹窗让用户授权)";
1065
1088
  readonly params: [{
1066
1089
  readonly name: "domain";
1067
1090
  readonly type: "string";
@@ -1072,6 +1095,7 @@ export declare const COMMANDS: readonly [{
1072
1095
  }, {
1073
1096
  readonly name: "run_actions";
1074
1097
  readonly description: "批量顺序执行多个 action,减少往返延迟。遇错即停,返回已完成步骤结果;步骤内的页面动作不带内置观察";
1098
+ readonly summary: "批量顺序执行多个 action,遇错即停";
1075
1099
  readonly params: [{
1076
1100
  readonly name: "actions";
1077
1101
  readonly type: "Array<{action: string, data?: object}>";
package/dist/commands.js CHANGED
@@ -266,11 +266,13 @@ export const COMMANDS = [
266
266
  {
267
267
  name: 'browser_list',
268
268
  description: '列出所有浏览器及其连接状态、类型和托管实例信息;AgentBay 可包含镜像与持久化 Context',
269
+ summary: '列出本地及远端浏览器与连接状态',
269
270
  examples: ['browser_list'],
270
271
  },
271
272
  {
272
273
  name: 'browser_release',
273
274
  description: '按用户明确要求释放调试控制和会话级临时效果(含设备/时区模拟),保留浏览器和全部标签页;不用于普通任务收尾',
275
+ summary: '释放浏览器调试控制及会话级临时效果',
274
276
  examples: ['browser_release', 'browser_release --browser chrome-a'],
275
277
  },
276
278
  {
@@ -325,8 +327,8 @@ export const COMMANDS = [
325
327
  },
326
328
  {
327
329
  name: 'copyCookieDomains',
328
- type: 'string[]',
329
- description: '从控制浏览器复制到本地新实例或 AgentBay 新建/复用实例的 Cookie 域名列表,可与本地 TDBank 登录组合',
330
+ type: 'string[] | "mearl-services"',
331
+ description: '从控制浏览器复制 Cookie:传域名数组,或传 mearl-services 同步 Mearl 依赖平台登录态',
330
332
  },
331
333
  ],
332
334
  examples: [
@@ -334,6 +336,7 @@ export const COMMANDS = [
334
336
  `browser_launch --payload '{"name":"cloud-public","provider":"agentbay","imageId":"browser_latest","url":"https://example.com"}'`,
335
337
  `browser_launch --payload '{"name":"cloud-login","provider":"agentbay","persistent":true,"copyCookieDomains":["example.com"],"url":"https://example.com/account"}'`,
336
338
  `browser_launch --payload '{"name":"cloud-login","provider":"agentbay","reuse":"require","copyCookieDomains":["example.com"]}'`,
339
+ `browser_launch --payload '{"name":"cloud-tools","provider":"agentbay","copyCookieDomains":"mearl-services"}'`,
337
340
  `browser_launch --payload '{"name":"account-a","headless":true,"accountId":12345}'`,
338
341
  `browser_launch --payload '{"name":"figma","userAgentMode":"desktop","copyCookieDomains":["figma.com"]}'`,
339
342
  `browser_launch --payload '{"name":"account-b","query":"test_account","url":"https://www.taobao.com"}'`,
@@ -420,6 +423,11 @@ export const COMMANDS = [
420
423
  type: 'boolean',
421
424
  description: '与 appProfile 配合;是否模拟顶部状态/导航栏与底部手势栏,默认 true',
422
425
  },
426
+ {
427
+ name: 'bridgeConfig',
428
+ type: 'object',
429
+ description: '与 appProfile 配合;声明式覆盖桥方法,形如 {methods:{api:{behavior|response|noop,silent?}}}',
430
+ },
423
431
  ],
424
432
  examples: [
425
433
  `tab_open --payload '{"url":"https://example.com"}'`,
@@ -439,7 +447,7 @@ export const COMMANDS = [
439
447
  },
440
448
  {
441
449
  name: 'tab_list',
442
- description: '获取当前窗口所有标签页列表',
450
+ description: '列出目标浏览器所有窗口中的标签页',
443
451
  aliases: ['tabs', 'list_tabs', 'show_tabs'],
444
452
  examples: ['tab_list'],
445
453
  },
@@ -461,7 +469,17 @@ export const COMMANDS = [
461
469
  {
462
470
  name: 'point',
463
471
  type: '{ x: number; y: number }',
464
- description: '按视口坐标点击(CSS 像素)。selector/text 都不适用的兜底场景',
472
+ description: '按视口坐标点击(CSS 像素)。默认使用 outer-viewport;容器或 iframe 内坐标配合 coordinateSpace: "active-frame"',
473
+ },
474
+ {
475
+ name: 'frameId',
476
+ type: 'string',
477
+ description: '浏览器扩展后端:显式指定 CSS/text 查询或 active-frame 坐标所属的 frame;省略时容器模式自动使用当前业务 frame',
478
+ },
479
+ {
480
+ name: 'coordinateSpace',
481
+ type: '"outer-viewport" | "active-frame"',
482
+ description: '仅配合 point 使用;默认 outer-viewport;浏览器扩展后端的 active-frame 会换算 iframe 偏移与缩放后派发可信输入',
465
483
  },
466
484
  {
467
485
  name: 'role',
@@ -495,6 +513,7 @@ export const COMMANDS = [
495
513
  `page_click --payload '{"selector":".submit-btn"}'`,
496
514
  `page_click --payload '{"selector":".gesture-btn","clickMode":"touch"}'`,
497
515
  `page_click --payload '{"point":{"x":336,"y":117}}'`,
516
+ `page_click --payload '{"point":{"x":196,"y":240},"coordinateSpace":"active-frame"}'`,
498
517
  ],
499
518
  },
500
519
  {
@@ -755,7 +774,7 @@ export const COMMANDS = [
755
774
  },
756
775
  {
757
776
  name: 'page_screenshot',
758
- description: '获取当前页面或指定元素截图',
777
+ description: '获取当前视口或指定元素截图',
759
778
  outputFlag: true,
760
779
  params: [
761
780
  { name: 'selector', type: 'string', description: 'CSS 选择器,提供后只截取该元素区域' },
@@ -789,7 +808,7 @@ export const COMMANDS = [
789
808
  },
790
809
  {
791
810
  name: 'get_user_info',
792
- description: '获取当前登录用户的信息',
811
+ description: '获取当前浏览器登录的阿里员工信息',
793
812
  params: [
794
813
  {
795
814
  name: 'detail',
@@ -809,6 +828,7 @@ export const COMMANDS = [
809
828
  {
810
829
  name: 'record_stop',
811
830
  description: '停止录制并返回完整结果(操作 + 关联请求);未在录制时不报错,返回 wasRecording: false',
831
+ summary: '停止录制并返回操作和关联请求',
812
832
  params: [{ name: 'tabId', type: 'number', description: '目标标签页 ID,从 tab_list 获取' }],
813
833
  examples: ['record_stop'],
814
834
  },
@@ -816,6 +836,7 @@ export const COMMANDS = [
816
836
  {
817
837
  name: 'set_device_emulation',
818
838
  description: '把目标 tab 切换为移动端模拟(视口/UA/触摸),等价 DevTools 设备工具栏,作用域 per-tab;需保持调试控制才持续生效',
839
+ summary: '设置或清除目标标签页的设备模拟',
819
840
  params: [
820
841
  { name: 'enabled', type: 'boolean', required: true, description: 'true=启用,false=清除' },
821
842
  {
@@ -846,6 +867,7 @@ export const COMMANDS = [
846
867
  {
847
868
  name: 'set_app_profile',
848
869
  description: '把目标 tab 切换为 App 容器模拟态(客户端 UA + JSBridge 托管 + 页面跳转 iframe 容器栈 + scheme 唤端映射 + 自适应系统标题栏),系统栏由 iframe 外层统一渲染,并根据页面协议与桥调用切换普通、沉浸或隐藏状态;用于桌面浏览器近似实机验证 App 内 H5,需保持调试控制才持续生效',
870
+ summary: '设置或清除目标标签页的 App 容器模拟',
849
871
  params: [
850
872
  { name: 'enabled', type: 'boolean', required: true, description: 'true=启用,false=清除' },
851
873
  {
@@ -870,6 +892,11 @@ export const COMMANDS = [
870
892
  type: 'object',
871
893
  description: '覆盖档案推荐的设备模拟参数,字段同 set_device_emulation 去掉 enabled',
872
894
  },
895
+ {
896
+ name: 'bridgeConfig',
897
+ type: 'object',
898
+ description: '声明式覆盖桥方法,形如 {methods:{api:{behavior|response|noop,silent?}}};不执行配置脚本',
899
+ },
873
900
  { name: 'reload', type: 'boolean', description: '应用/清除后是否重载页面,默认 true' },
874
901
  { name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
875
902
  ],
@@ -953,13 +980,13 @@ export const COMMANDS = [
953
980
  // ── 其他 ──────────────────────────────────────────────────────────────────
954
981
  {
955
982
  name: 'page_frames',
956
- description: '获取页面所有 iframe 列表',
983
+ description: '获取页面主 frame 与所有 iframe 列表',
957
984
  params: [{ name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' }],
958
985
  examples: [`page_frames --payload '{"tabId":12345}'`],
959
986
  },
960
987
  {
961
988
  name: 'request_domain_permission',
962
- description: '申请访问指定域名的权限(弹窗让用户授权)',
989
+ description: '申请访问指定域名的权限(必要时弹窗让用户授权)',
963
990
  params: [
964
991
  {
965
992
  name: 'domain',
@@ -974,6 +1001,7 @@ export const COMMANDS = [
974
1001
  {
975
1002
  name: 'run_actions',
976
1003
  description: '批量顺序执行多个 action,减少往返延迟。遇错即停,返回已完成步骤结果;步骤内的页面动作不带内置观察',
1004
+ summary: '批量顺序执行多个 action,遇错即停',
977
1005
  params: [
978
1006
  {
979
1007
  name: 'actions',
@@ -219,8 +219,8 @@ export interface BrowserLaunchParams {
219
219
  site?: string | number;
220
220
  query?: string;
221
221
  tabId?: number;
222
- /** Copy matching cookies from the selected control browser into a new or reused instance. */
223
- copyCookieDomains?: string[];
222
+ /** Copy explicit domains or the fixed Mearl-service preset from the control browser. */
223
+ copyCookieDomains?: string[] | 'mearl-services';
224
224
  }
225
225
  export interface BrowserCloseParams {
226
226
  browser: string;
@@ -271,6 +271,18 @@ export interface BrowserEmulationOptions {
271
271
  orientation?: 'portrait' | 'landscape';
272
272
  touch?: boolean;
273
273
  }
274
+ export type AppBridgeConfigBehavior = 'navigate' | 'closeAll' | 'closeBackData' | 'postMessage' | 'notifySubscribe' | 'notifyUnsubscribe' | 'notifyPost' | 'sharedFileRead' | 'sharedFileWrite' | 'sharedDataGet' | 'sharedDataSet' | 'legacyBroadcastCreate' | 'legacyBroadcastPost' | 'legacyBroadcastClose' | 'memoryGet' | 'memorySet' | 'memoryDelete' | 'availabilityMap' | 'userInfo' | 'networkInfo' | 'geolocation' | 'permission' | 'prefetch' | 'fptTrack' | 'mtopStream' | 'previewFile' | 'toast' | 'unsupportedNativeInput' | 'payment' | 'userTrack' | 'calendar' | 'networkQualityMonitor' | 'beaconRequest';
275
+ /** 单个桥方法的声明式覆盖;行为、固定回包、成功空实现三选一。 */
276
+ export interface AppBridgeMethodConfig {
277
+ behavior?: AppBridgeConfigBehavior;
278
+ response?: unknown;
279
+ noop?: boolean;
280
+ silent?: boolean;
281
+ }
282
+ /** 追加或覆盖 App 档案中的桥方法。配置保持 JSON 可序列化,不执行配置提供的代码。 */
283
+ export interface AppBridgeConfig {
284
+ methods: Record<string, AppBridgeMethodConfig>;
285
+ }
274
286
  export interface TabOpenParams {
275
287
  url: string;
276
288
  active?: boolean;
@@ -297,6 +309,8 @@ export interface TabOpenParams {
297
309
  os?: 'ios' | 'android';
298
310
  /** 与 appProfile 配合使用;是否模拟顶部状态/导航栏与底部手势栏,默认 true */
299
311
  simulateSystemBars?: boolean;
312
+ /** 与 appProfile 配合使用;按方法覆盖档案内置桥配置 */
313
+ bridgeConfig?: AppBridgeConfig;
300
314
  }
301
315
  /**
302
316
  * 客户端容器模拟可用档案名。
@@ -319,6 +333,8 @@ export interface SetAppProfileParams {
319
333
  deviceModel?: string;
320
334
  /** 是否模拟顶部状态/导航栏与底部手势栏,默认 true */
321
335
  simulateSystemBars?: boolean;
336
+ /** 按方法覆盖档案内置桥配置,仅支持受控行为、固定 JSON 回包和成功空实现 */
337
+ bridgeConfig?: AppBridgeConfig;
322
338
  /** 覆盖档案推荐的设备模拟参数(视口/UA 默认取档案值) */
323
339
  emulation?: BrowserEmulationOptions;
324
340
  /** 默认 true:应用/清除后刷新页面使注入生效 */
@@ -350,6 +366,10 @@ export interface PageClickParams {
350
366
  x: number;
351
367
  y: number;
352
368
  };
369
+ /** CSS/text 查询的目标 frame;省略时容器模式自动使用当前业务 frame。 */
370
+ frameId?: string;
371
+ /** point 的坐标空间;默认 outer-viewport 以保持兼容。 */
372
+ coordinateSpace?: 'outer-viewport' | 'active-frame';
353
373
  role?: string;
354
374
  exact?: boolean;
355
375
  scope?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mearl/client",
3
- "version": "2.8.2",
3
+ "version": "2.9.1",
4
4
  "description": "Unified Mearl SDK & CLI for local and remote browsers",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -45,13 +45,17 @@
45
45
  "socket-client"
46
46
  ],
47
47
  "license": "ISC",
48
+ "engines": {
49
+ "node": ">=22.12.0"
50
+ },
48
51
  "publishConfig": {
49
52
  "registry": "https://registry.npmjs.org"
50
53
  },
51
54
  "dependencies": {
55
+ "commander": "^15.0.0",
52
56
  "fastest-levenshtein": "^1.0.16",
53
57
  "ws": "^8.18.0",
54
- "@mearl/cloud-types": "2.8.2"
58
+ "@mearl/cloud-types": "2.9.1"
55
59
  },
56
60
  "devDependencies": {
57
61
  "@types/node": "^24.9.1",