@mearl/client 2.8.2 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/dist/cli.d.ts +16 -0
- package/dist/cli.js +46 -49
- package/dist/commands.d.ts +21 -5
- package/dist/commands.js +25 -3
- package/dist/generated-browser-action-protocol.d.ts +22 -2
- package/package.json +6 -2
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
|
|
@@ -111,13 +112,13 @@ mearl browser_release
|
|
|
111
112
|
|
|
112
113
|
`page_snapshot` 默认返回完整 AX Tree;长列表可传 `mode: "viewport"`,只需要当前视口内的控件时传 `mode: "interactive"`,已知 CSS 区域时传 `rootSelector`,已有 ref 时传 `rootRef`(可用 `ancestorDepth` 向上补充上下文),只查找特定文案或角色时传 `query`。视口内缺少 AX 控件语义时,`interactive` 会自动回退到 viewport,并返回 `fallbackMode: "viewport"`。`maxNodes` / `maxChars` 截断会同时保留首尾内容。
|
|
113
114
|
|
|
114
|
-
重复文本点击可用 `page_click.scope` 限定 CSS / ref
|
|
115
|
+
重复文本点击可用 `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
116
|
|
|
116
117
|
`browser_list` 统一列出普通浏览器和托管浏览器。`type` 区分 `regular` / `managed`,`status` 区分 `connected` / `running_disconnected` / `stopped`;只有 `connected` 的浏览器可作为操作目标。
|
|
117
118
|
|
|
118
119
|
`browser_release` 仅在用户明确要求结束调试、退出接管或清理会话资源时使用,不作为普通任务收尾。它会释放当前目标浏览器的 debugger/CDP 控制和会话级临时状态(包括设备/时区模拟),保留浏览器及全部标签页;后续浏览器操作可自动重新建立控制。
|
|
119
120
|
|
|
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`
|
|
121
|
+
托管浏览器使用独立 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
122
|
|
|
122
123
|
## 架构
|
|
123
124
|
|
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';
|
|
@@ -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}`,
|
|
@@ -159,9 +156,7 @@ function parsePositiveTimeout(value, fallback) {
|
|
|
159
156
|
}
|
|
160
157
|
return parsed;
|
|
161
158
|
}
|
|
162
|
-
function parsePayload(
|
|
163
|
-
const payloadRaw = optionValue(args, '--payload');
|
|
164
|
-
const payloadFile = optionValue(args, '--payload-file');
|
|
159
|
+
function parsePayload(payloadRaw, payloadFile) {
|
|
165
160
|
if (payloadRaw !== undefined && payloadFile !== undefined) {
|
|
166
161
|
throw new Error('--payload 与 --payload-file 不能同时使用');
|
|
167
162
|
}
|
|
@@ -183,33 +178,7 @@ function parsePayload(args) {
|
|
|
183
178
|
}
|
|
184
179
|
return {};
|
|
185
180
|
}
|
|
186
|
-
function
|
|
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');
|
|
181
|
+
function resolveServer(explicit) {
|
|
213
182
|
if (explicit)
|
|
214
183
|
return { serverUrl: explicit, serverUrlSource: '--server' };
|
|
215
184
|
if (process.env.MEARL_SERVER_URL) {
|
|
@@ -220,31 +189,59 @@ function resolveServer(args) {
|
|
|
220
189
|
? { serverUrl: config.server, serverUrlSource: getCloudServerConfigPath() }
|
|
221
190
|
: {};
|
|
222
191
|
}
|
|
223
|
-
function
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
192
|
+
export function parseClientArgs(args) {
|
|
193
|
+
const program = new Command()
|
|
194
|
+
.name('mearl')
|
|
195
|
+
.helpOption(false)
|
|
196
|
+
.allowExcessArguments(false)
|
|
197
|
+
.exitOverride()
|
|
198
|
+
.configureOutput({ writeErr: () => { }, writeOut: () => { } })
|
|
199
|
+
.argument('<action>')
|
|
200
|
+
.option('--payload <json>')
|
|
201
|
+
.option('--payload-file <path>')
|
|
202
|
+
.option('--timeout <seconds>')
|
|
203
|
+
.option('--compact')
|
|
204
|
+
.option('--json')
|
|
205
|
+
.option('--output <path>')
|
|
206
|
+
.option('--browser <id-or-name>')
|
|
207
|
+
.option('--connector <id-or-name>')
|
|
208
|
+
.option('--local')
|
|
209
|
+
.option('--cdp')
|
|
210
|
+
.option('--server <url>');
|
|
211
|
+
try {
|
|
212
|
+
program.parse(['node', 'mearl', ...args]);
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
if (error instanceof CommanderError) {
|
|
216
|
+
throw new Error(error.message.replace(/^error:\s*/i, ''), { cause: error });
|
|
217
|
+
}
|
|
218
|
+
throw error;
|
|
219
|
+
}
|
|
220
|
+
const action = program.processedArgs[0];
|
|
221
|
+
const options = program.opts();
|
|
222
|
+
const json = options.json === true;
|
|
227
223
|
if (json && action !== 'check')
|
|
228
224
|
throw new Error('--json 仅适用于 check');
|
|
229
|
-
const payload = parsePayload(
|
|
225
|
+
const payload = parsePayload(options.payload, options.payloadFile);
|
|
230
226
|
const fallbackTimeout = resolveActionTimeoutSec(action, payload, 60);
|
|
231
|
-
const forceCdp =
|
|
232
|
-
const local = forceCdp ||
|
|
233
|
-
const connector =
|
|
227
|
+
const forceCdp = options.cdp === true;
|
|
228
|
+
const local = forceCdp || options.local === true;
|
|
229
|
+
const connector = options.connector;
|
|
234
230
|
if (local && connector)
|
|
235
231
|
throw new Error('--local/--cdp 不能与 --connector 同时使用');
|
|
236
232
|
return {
|
|
237
233
|
action,
|
|
238
234
|
payload,
|
|
239
|
-
timeoutSec: parsePositiveTimeout(
|
|
240
|
-
|
|
235
|
+
timeoutSec: parsePositiveTimeout(options.timeout, fallbackTimeout),
|
|
236
|
+
...(options.timeout !== undefined ? { timeoutOption: options.timeout } : {}),
|
|
237
|
+
compact: options.compact === true,
|
|
241
238
|
forceCdp,
|
|
242
239
|
json,
|
|
243
240
|
local,
|
|
244
|
-
...(
|
|
245
|
-
...(
|
|
241
|
+
...(options.output ? { outputPath: options.output } : {}),
|
|
242
|
+
...(options.browser ? { browser: options.browser } : {}),
|
|
246
243
|
...(connector ? { connector } : {}),
|
|
247
|
-
...resolveServer(
|
|
244
|
+
...resolveServer(options.server),
|
|
248
245
|
};
|
|
249
246
|
}
|
|
250
247
|
function screenshotData(action, result) {
|
|
@@ -305,14 +302,14 @@ export async function runMearlCli(args, options = {}) {
|
|
|
305
302
|
}
|
|
306
303
|
let parsed;
|
|
307
304
|
try {
|
|
308
|
-
parsed =
|
|
305
|
+
parsed = parseClientArgs(args);
|
|
309
306
|
}
|
|
310
307
|
catch (error) {
|
|
311
308
|
console.error(error instanceof Error ? error.message : String(error));
|
|
312
309
|
return 2;
|
|
313
310
|
}
|
|
314
311
|
if (parsed.action === 'check') {
|
|
315
|
-
const timeoutSec = parseCheckTimeout(
|
|
312
|
+
const timeoutSec = parseCheckTimeout(parsed.timeoutOption);
|
|
316
313
|
if (timeoutSec === null) {
|
|
317
314
|
console.error('--timeout 必须是正整数秒');
|
|
318
315
|
return 2;
|
package/dist/commands.d.ts
CHANGED
|
@@ -439,10 +439,10 @@ export declare const COMMANDS: readonly [{
|
|
|
439
439
|
readonly description: "CDP 控制浏览器中用于读取 TDBank Cookie 的标签页";
|
|
440
440
|
}, {
|
|
441
441
|
readonly name: "copyCookieDomains";
|
|
442
|
-
readonly type: "string[]";
|
|
443
|
-
readonly description: "
|
|
442
|
+
readonly type: "string[] | \"mearl-services\"";
|
|
443
|
+
readonly description: "从控制浏览器复制 Cookie:传域名数组,或传 mearl-services 同步 Mearl 依赖平台登录态";
|
|
444
444
|
}];
|
|
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\"]}'"];
|
|
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\":\"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
446
|
}, {
|
|
447
447
|
readonly name: "browser_close";
|
|
448
448
|
readonly description: "关闭指定托管浏览器并按策略保留或清理本地 Profile / AgentBay Context";
|
|
@@ -510,6 +510,10 @@ export declare const COMMANDS: readonly [{
|
|
|
510
510
|
readonly name: "simulateSystemBars";
|
|
511
511
|
readonly type: "boolean";
|
|
512
512
|
readonly description: "与 appProfile 配合;是否模拟顶部状态/导航栏与底部手势栏,默认 true";
|
|
513
|
+
}, {
|
|
514
|
+
readonly name: "bridgeConfig";
|
|
515
|
+
readonly type: "object";
|
|
516
|
+
readonly description: "与 appProfile 配合;声明式覆盖桥方法,形如 {methods:{api:{behavior|response|noop,silent?}}}";
|
|
513
517
|
}];
|
|
514
518
|
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
519
|
}, {
|
|
@@ -542,7 +546,15 @@ export declare const COMMANDS: readonly [{
|
|
|
542
546
|
}, {
|
|
543
547
|
readonly name: "point";
|
|
544
548
|
readonly type: "{ x: number; y: number }";
|
|
545
|
-
readonly description: "按视口坐标点击(CSS
|
|
549
|
+
readonly description: "按视口坐标点击(CSS 像素)。默认使用 outer-viewport;容器或 iframe 内坐标配合 coordinateSpace: \"active-frame\"";
|
|
550
|
+
}, {
|
|
551
|
+
readonly name: "frameId";
|
|
552
|
+
readonly type: "string";
|
|
553
|
+
readonly description: "浏览器扩展后端:显式指定 CSS/text 查询或 active-frame 坐标所属的 frame;省略时容器模式自动使用当前业务 frame";
|
|
554
|
+
}, {
|
|
555
|
+
readonly name: "coordinateSpace";
|
|
556
|
+
readonly type: "\"outer-viewport\" | \"active-frame\"";
|
|
557
|
+
readonly description: "仅配合 point 使用;默认 outer-viewport;浏览器扩展后端的 active-frame 会换算 iframe 偏移与缩放后派发可信输入";
|
|
546
558
|
}, {
|
|
547
559
|
readonly name: "role";
|
|
548
560
|
readonly type: "string";
|
|
@@ -565,7 +577,7 @@ export declare const COMMANDS: readonly [{
|
|
|
565
577
|
readonly required: true;
|
|
566
578
|
readonly description: "目标标签页 ID";
|
|
567
579
|
}];
|
|
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}}'"];
|
|
580
|
+
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
581
|
}, {
|
|
570
582
|
readonly name: "page_drag";
|
|
571
583
|
readonly description: "拖动页面元素或视口坐标,适用于轮播图、滑块和拖放";
|
|
@@ -968,6 +980,10 @@ export declare const COMMANDS: readonly [{
|
|
|
968
980
|
readonly name: "emulation";
|
|
969
981
|
readonly type: "object";
|
|
970
982
|
readonly description: "覆盖档案推荐的设备模拟参数,字段同 set_device_emulation 去掉 enabled";
|
|
983
|
+
}, {
|
|
984
|
+
readonly name: "bridgeConfig";
|
|
985
|
+
readonly type: "object";
|
|
986
|
+
readonly description: "声明式覆盖桥方法,形如 {methods:{api:{behavior|response|noop,silent?}}};不执行配置脚本";
|
|
971
987
|
}, {
|
|
972
988
|
readonly name: "reload";
|
|
973
989
|
readonly type: "boolean";
|
package/dist/commands.js
CHANGED
|
@@ -325,8 +325,8 @@ export const COMMANDS = [
|
|
|
325
325
|
},
|
|
326
326
|
{
|
|
327
327
|
name: 'copyCookieDomains',
|
|
328
|
-
type: 'string[]',
|
|
329
|
-
description: '
|
|
328
|
+
type: 'string[] | "mearl-services"',
|
|
329
|
+
description: '从控制浏览器复制 Cookie:传域名数组,或传 mearl-services 同步 Mearl 依赖平台登录态',
|
|
330
330
|
},
|
|
331
331
|
],
|
|
332
332
|
examples: [
|
|
@@ -334,6 +334,7 @@ export const COMMANDS = [
|
|
|
334
334
|
`browser_launch --payload '{"name":"cloud-public","provider":"agentbay","imageId":"browser_latest","url":"https://example.com"}'`,
|
|
335
335
|
`browser_launch --payload '{"name":"cloud-login","provider":"agentbay","persistent":true,"copyCookieDomains":["example.com"],"url":"https://example.com/account"}'`,
|
|
336
336
|
`browser_launch --payload '{"name":"cloud-login","provider":"agentbay","reuse":"require","copyCookieDomains":["example.com"]}'`,
|
|
337
|
+
`browser_launch --payload '{"name":"cloud-tools","provider":"agentbay","copyCookieDomains":"mearl-services"}'`,
|
|
337
338
|
`browser_launch --payload '{"name":"account-a","headless":true,"accountId":12345}'`,
|
|
338
339
|
`browser_launch --payload '{"name":"figma","userAgentMode":"desktop","copyCookieDomains":["figma.com"]}'`,
|
|
339
340
|
`browser_launch --payload '{"name":"account-b","query":"test_account","url":"https://www.taobao.com"}'`,
|
|
@@ -420,6 +421,11 @@ export const COMMANDS = [
|
|
|
420
421
|
type: 'boolean',
|
|
421
422
|
description: '与 appProfile 配合;是否模拟顶部状态/导航栏与底部手势栏,默认 true',
|
|
422
423
|
},
|
|
424
|
+
{
|
|
425
|
+
name: 'bridgeConfig',
|
|
426
|
+
type: 'object',
|
|
427
|
+
description: '与 appProfile 配合;声明式覆盖桥方法,形如 {methods:{api:{behavior|response|noop,silent?}}}',
|
|
428
|
+
},
|
|
423
429
|
],
|
|
424
430
|
examples: [
|
|
425
431
|
`tab_open --payload '{"url":"https://example.com"}'`,
|
|
@@ -461,7 +467,17 @@ export const COMMANDS = [
|
|
|
461
467
|
{
|
|
462
468
|
name: 'point',
|
|
463
469
|
type: '{ x: number; y: number }',
|
|
464
|
-
description: '按视口坐标点击(CSS
|
|
470
|
+
description: '按视口坐标点击(CSS 像素)。默认使用 outer-viewport;容器或 iframe 内坐标配合 coordinateSpace: "active-frame"',
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
name: 'frameId',
|
|
474
|
+
type: 'string',
|
|
475
|
+
description: '浏览器扩展后端:显式指定 CSS/text 查询或 active-frame 坐标所属的 frame;省略时容器模式自动使用当前业务 frame',
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
name: 'coordinateSpace',
|
|
479
|
+
type: '"outer-viewport" | "active-frame"',
|
|
480
|
+
description: '仅配合 point 使用;默认 outer-viewport;浏览器扩展后端的 active-frame 会换算 iframe 偏移与缩放后派发可信输入',
|
|
465
481
|
},
|
|
466
482
|
{
|
|
467
483
|
name: 'role',
|
|
@@ -495,6 +511,7 @@ export const COMMANDS = [
|
|
|
495
511
|
`page_click --payload '{"selector":".submit-btn"}'`,
|
|
496
512
|
`page_click --payload '{"selector":".gesture-btn","clickMode":"touch"}'`,
|
|
497
513
|
`page_click --payload '{"point":{"x":336,"y":117}}'`,
|
|
514
|
+
`page_click --payload '{"point":{"x":196,"y":240},"coordinateSpace":"active-frame"}'`,
|
|
498
515
|
],
|
|
499
516
|
},
|
|
500
517
|
{
|
|
@@ -870,6 +887,11 @@ export const COMMANDS = [
|
|
|
870
887
|
type: 'object',
|
|
871
888
|
description: '覆盖档案推荐的设备模拟参数,字段同 set_device_emulation 去掉 enabled',
|
|
872
889
|
},
|
|
890
|
+
{
|
|
891
|
+
name: 'bridgeConfig',
|
|
892
|
+
type: 'object',
|
|
893
|
+
description: '声明式覆盖桥方法,形如 {methods:{api:{behavior|response|noop,silent?}}};不执行配置脚本',
|
|
894
|
+
},
|
|
873
895
|
{ name: 'reload', type: 'boolean', description: '应用/清除后是否重载页面,默认 true' },
|
|
874
896
|
{ name: 'tabId', type: 'number', required: true, description: '目标标签页 ID' },
|
|
875
897
|
],
|
|
@@ -219,8 +219,8 @@ export interface BrowserLaunchParams {
|
|
|
219
219
|
site?: string | number;
|
|
220
220
|
query?: string;
|
|
221
221
|
tabId?: number;
|
|
222
|
-
/** Copy
|
|
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' | '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.
|
|
3
|
+
"version": "2.9.0",
|
|
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.
|
|
58
|
+
"@mearl/cloud-types": "2.9.0"
|
|
55
59
|
},
|
|
56
60
|
"devDependencies": {
|
|
57
61
|
"@types/node": "^24.9.1",
|