@mearl/client 2.14.0 → 2.15.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 +39 -21
- package/dist/actionTimeouts.js +2 -4
- package/dist/check.d.ts +0 -2
- package/dist/check.js +0 -2
- package/dist/cli.js +113 -20
- package/dist/commands.d.ts +20 -120
- package/dist/commands.js +19 -123
- package/dist/generated-browser-action-protocol.d.ts +20 -65
- package/dist/generated-browser-action-protocol.js +0 -9
- package/dist/index.d.ts +3 -5
- package/dist/index.js +1 -10
- package/dist/officialPluginCatalog.d.ts +79 -0
- package/dist/officialPluginCatalog.js +80 -0
- package/dist/officialPluginInstaller.d.ts +3 -0
- package/dist/officialPluginInstaller.js +130 -0
- package/dist/plugin.d.ts +22 -1
- package/dist/plugin.js +72 -3
- package/dist/pluginRegistry.d.ts +5 -1
- package/dist/pluginRegistry.js +15 -3
- package/dist/socket.d.ts +3 -2
- package/dist/socket.js +79 -36
- package/dist/unified.d.ts +3 -0
- package/dist/unified.js +24 -2
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -63,15 +63,10 @@ npx @mearl/setup update --local
|
|
|
63
63
|
# 查看某个 action 的帮助
|
|
64
64
|
mearl <action> --help
|
|
65
65
|
|
|
66
|
-
# 启动两个隔离的 headless Chrome
|
|
67
|
-
mearl browser_launch --payload '{"name":"
|
|
68
|
-
mearl browser_launch --payload '{"name":"
|
|
66
|
+
# 启动两个隔离的 headless Chrome
|
|
67
|
+
mearl browser_launch --payload '{"name":"browser-a","url":"https://example.com"}'
|
|
68
|
+
mearl browser_launch --payload '{"name":"browser-b","persistent":true}'
|
|
69
69
|
mearl browser_launch --payload '{"name":"cookie-copy","copyCookieDomains":["example.com"]}'
|
|
70
|
-
mearl browser_launch --payload '{"name":"cloud-login","provider":"agentbay","persistent":true,"userAgentMode":"desktop","copyCookieDomains":["example.com"],"url":"https://example.com/account"}'
|
|
71
|
-
mearl browser_launch --browser '<控制浏览器 browserId>' --payload '{"name":"cloud-login","provider":"agentbay","reuse":"require","copyCookieDomains":["example.com"]}'
|
|
72
|
-
mearl browser_launch --browser '<本地来源 browserId>' --payload '{"sessionId":"<其他设备创建的 AgentBay sessionId>","copyCookieDomains":["example.com"]}'
|
|
73
|
-
mearl browser_launch --payload '{"name":"cloud-tools","provider":"agentbay","copyCookieDomains":"mearl-services"}'
|
|
74
|
-
mearl browser_launch --payload '{"name":"cloud-tools-plus","provider":"agentbay","copyCookieDomains":{"presets":["mearl-services"],"domains":["figma.com"]}}'
|
|
75
70
|
mearl browser_launch --payload '{"name":"figma","userAgentMode":"desktop","copyCookieDomains":["figma.com"]}'
|
|
76
71
|
mearl browser_list
|
|
77
72
|
mearl browser_release
|
|
@@ -79,16 +74,19 @@ mearl browser_release
|
|
|
79
74
|
|
|
80
75
|
### 外部浏览器 Provider
|
|
81
76
|
|
|
82
|
-
Provider 浏览器与扩展、CDP
|
|
77
|
+
Provider 浏览器与扩展、CDP 浏览器一起出现在 `browser_list` 中,并使用同一个
|
|
83
78
|
全局 `browserId` 参与路由。Provider 的安装、更新和卸载由 `@mearl/setup` 管理:
|
|
84
79
|
|
|
85
80
|
```bash
|
|
86
81
|
npx @mearl/setup provider install @ali/mearl-provider-brow
|
|
82
|
+
npx @mearl/setup provider install @ali/mearl-provider-agentbay
|
|
87
83
|
|
|
88
|
-
#
|
|
89
|
-
mearl
|
|
84
|
+
# 查看 Provider 当前版本的能力、参数与使用流程
|
|
85
|
+
mearl brow
|
|
86
|
+
mearl agentbay --help
|
|
90
87
|
|
|
91
|
-
#
|
|
88
|
+
# Provider 启动参数统一放在 providerOptions
|
|
89
|
+
mearl browser_launch --payload '{"provider":"brow","providerOptions":{}}'
|
|
92
90
|
mearl browser_list
|
|
93
91
|
|
|
94
92
|
# 后续操作使用 browser_list 返回的全局 Browser ID
|
|
@@ -130,12 +128,13 @@ Mearl 默认聚合当前机器和已配置 cloud-server 下的浏览器,并通
|
|
|
130
128
|
`browser_list --help` 和 `browser_launch --help` 会按场景展示宿主选择参数;连接或传输排障运行
|
|
131
129
|
`mearl check --help`。其中 `--json` 仅用于输出机器可读的检查结果。
|
|
132
130
|
|
|
133
|
-
## Skill
|
|
131
|
+
## Skill 插件
|
|
134
132
|
|
|
135
133
|
安装 skill 并自动注册命令,或直接注册已有入口:
|
|
136
134
|
|
|
137
135
|
```bash
|
|
138
136
|
npx @mearl/setup plugin install trip/mearl --skill yuque-doc-fetch --yes
|
|
137
|
+
npx @mearl/setup plugin install trip/mearl --skill buc-request --yes
|
|
139
138
|
npx @mearl/setup plugin yuque /absolute/path/to/yuque-doc-fetch
|
|
140
139
|
npx @mearl/setup plugin uninstall yuque
|
|
141
140
|
mearl yuque read "https://aliyuque.antfin.com/group/book/doc"
|
|
@@ -146,7 +145,7 @@ mearl yuque --version
|
|
|
146
145
|
|
|
147
146
|
目录默认使用 `scripts/main.mjs`。入口默认导出 `register(app)`,可导出简短的 `description`
|
|
148
147
|
显示在 `mearl` 插件列表中,并通过 `app.command(signature, handler, description?)`
|
|
149
|
-
注册动作、`app.invoke(action, payload, options?)` 复用当前浏览器上下文,并用 `app.progress(message)`
|
|
148
|
+
注册动作、`app.invoke(action, payload, options?)` 复用当前浏览器上下文,并用 `app.progress(message)` 报告可选进度。调用另一个插件时,payload 使用 `{ command, input }` envelope;嵌套调用继承宿主选项并拒绝循环依赖。CLI 默认只输出最终结果,传入
|
|
150
149
|
`--verbose` 时才把进度写入 stderr。handler 返回文本或 JSON,宿主统一处理 `--output`、连接和错误。写命令在用户调用后直接执行,业务模块负责目标、状态、幂等和结果校验。
|
|
151
150
|
自动注册默认以 skill 安装目录名作为命令名,也可在入口导出 `name` 指定短名称。
|
|
152
151
|
setup 会补齐缺失或低于自身版本的 client、native-host;安装参数透传给 Ali Skills,并固定全局共享安装。
|
|
@@ -158,19 +157,38 @@ setup 会补齐缺失或低于自身版本的 client、native-host;安装参
|
|
|
158
157
|
插件接受位置参数或包含 command/input 的 `--payload`,两种形式不能混用。JSON 保留业务字段类型;正文等文件输入
|
|
159
158
|
按具体 skill 的字段约定处理。插件不使用上表中内置 action 的 `--payload-file` 入口。
|
|
160
159
|
|
|
160
|
+
注册后的插件也可从 SDK 调用;实例方法 `client.invokePlugin` 复用既有连接和默认浏览器:
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
import { invokePlugin } from '@mearl/client';
|
|
164
|
+
|
|
165
|
+
const result = await invokePlugin(
|
|
166
|
+
'yuque',
|
|
167
|
+
{ command: 'read', input: { url: 'https://aliyuque.antfin.com/group/book/doc' } },
|
|
168
|
+
{ browser: 'work' },
|
|
169
|
+
);
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
MCP Server 通过固定工具 `mearl_plugin` 接受同样的 `plugin`、`command` 和 `input`,不会把插件子命令动态扩展成 MCP 工具。SDK 与 MCP 不接受任意入口路径;调用官方目录中尚未注册的插件时,会通过匹配当前 client 版本的 setup 自动安装并重试一次。未知名称仍返回 `PLUGIN_NOT_REGISTERED`。
|
|
173
|
+
|
|
161
174
|
注册记录在 `~/.mearl/plugins/<name>.json`,保存入口路径和可选的简短描述;skill 业务代码原地更新直接生效,换路径或更新描述后重新注册。
|
|
162
175
|
`plugin uninstall <name>` 会对 `~/.agents/skills` 中的全局 Skill 调用 `ali-skills remove --global --yes`,
|
|
163
176
|
成功后清除相关注册;即使入口目录已被手动删除,也会完成 Ali Skills 跟踪记录的清理。
|
|
164
177
|
手工路径只解除注册并保留源码。
|
|
165
178
|
`PLUGIN_NOT_REGISTERED` 表示插件尚未注册。`PLUGIN_ENTRY_MISSING` 会显示失效入口,并给出带有实际插件名的
|
|
166
179
|
卸载清理命令。其他错误按实际原因处理。
|
|
167
|
-
编写规范见 [Mearl Skill Creator 的
|
|
180
|
+
编写规范见 [Mearl Skill Creator 的 Skill 插件规范](../skills/mearl-skill-creator/references/cli-plugin.md)。
|
|
181
|
+
|
|
182
|
+
需要 BUC 身份的内部 HTTP 接口通过官方 `buc` 插件调用。CLI 使用 `mearl buc request`,业务插件使用
|
|
183
|
+
`app.invoke('buc', { command: 'request', input })`;当前身份和人员资料分别使用 `whoami` 与 `profile`
|
|
184
|
+
子命令。BUC 插件按请求创建一次性凭据,只允许访问 HTTPS `alibaba-inc.com` 域名,过滤认证字段与
|
|
185
|
+
Cookie,并始终在运行 CLI、SDK 或 MCP Server 的机器上执行,不随浏览器或 connector 转发。
|
|
168
186
|
|
|
169
187
|
## 支持的操作
|
|
170
188
|
|
|
171
189
|
| 分类 | Actions |
|
|
172
190
|
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
|
173
|
-
| API 调试 | `tab_checkpoint` `get_requests` `get_logs` `get_events`
|
|
191
|
+
| API 调试 | `tab_checkpoint` `get_requests` `get_logs` `get_events` |
|
|
174
192
|
| Mock & 规则 | `set_mock` `get_mocks` `set_rule` `get_rules` |
|
|
175
193
|
| 网络请求 | `send_request` `send_mtop_request` `request_domain_permission` |
|
|
176
194
|
| 标签页 | `tab_open` `tab_close` `tab_list` |
|
|
@@ -178,9 +196,7 @@ setup 会补齐缺失或低于自身版本的 client、native-host;安装参
|
|
|
178
196
|
| 组合调用 | `run_actions` |
|
|
179
197
|
| 页面感知 | `page_snapshot` `page_screenshot` `page_selected_element` `page_frames` |
|
|
180
198
|
| 环境与 Cookie | `set_device_emulation` `set_app_profile` `set_timezone` `get_cookie` `set_cookie` |
|
|
181
|
-
| 用户信息 | `get_user_info` |
|
|
182
199
|
| 录制 | `record_start` `record_stop` |
|
|
183
|
-
| TDBank | `tdbank_account` |
|
|
184
200
|
| 浏览器 | `browser_list` `browser_release` `browser_launch` `browser_close` |
|
|
185
201
|
|
|
186
202
|
页面交互动作(`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` 默认裸执行,可按需开启观察或诊断。
|
|
@@ -193,9 +209,11 @@ setup 会补齐缺失或低于自身版本的 client、native-host;安装参
|
|
|
193
209
|
`regular` / `managed`,`status` 区分 `connected` / `pairing` / `running_disconnected` /
|
|
194
210
|
`stopped`;只有 `connected` 的浏览器可作为常规操作目标。
|
|
195
211
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
212
|
+
`browser_release` 仅在用户明确要求结束调试、退出接管或清理会话资源时调用;它会释放
|
|
213
|
+
debugger/CDP 控制和会话级临时状态,保留浏览器及全部标签页。托管实例的启动、关闭、持久化、
|
|
214
|
+
接入和登录态同步语义由各 Provider 声明;运行 `mearl <providerId>` 获取当前说明。访问入口不在
|
|
215
|
+
`browser_list` 中,需要时显式运行 `mearl check --browser <id|名称>`,并把返回的
|
|
216
|
+
`browserAccess.url` 按敏感信息处理。
|
|
199
217
|
|
|
200
218
|
## 架构
|
|
201
219
|
|
package/dist/actionTimeouts.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { PAGE_ACT_ACTIONS } from './generated-browser-action-protocol.js';
|
|
2
2
|
const SEND_REQUEST_FILE_TRANSFER_TIMEOUT_MS = 120_000;
|
|
3
|
-
//
|
|
3
|
+
// Remote Providers may stage files before forwarding a page upload.
|
|
4
4
|
const PAGE_UPLOAD_FILE_TRANSFER_TIMEOUT_MS = 180_000;
|
|
5
|
-
//
|
|
5
|
+
// Persistent Providers may need to synchronize remote state before closing an instance.
|
|
6
6
|
const BROWSER_CLOSE_TIMEOUT_SEC = 18 * 60;
|
|
7
7
|
function boundedNumber(value, fallback, minimum, maximum) {
|
|
8
8
|
const numeric = Number(value);
|
|
@@ -41,8 +41,6 @@ export function resolveActionTimeoutSec(action, data, fallback = 15) {
|
|
|
41
41
|
return Math.max(fallback, 90);
|
|
42
42
|
if (action === 'browser_close')
|
|
43
43
|
return Math.max(fallback, BROWSER_CLOSE_TIMEOUT_SEC);
|
|
44
|
-
if (action === 'tdbank_account')
|
|
45
|
-
return Math.max(fallback, 20);
|
|
46
44
|
if (action === 'run_actions') {
|
|
47
45
|
const actions = Array.isArray(data.actions) ? data.actions : [{}];
|
|
48
46
|
const timeoutSec = actions.reduce((total, step) => {
|
package/dist/check.d.ts
CHANGED
package/dist/check.js
CHANGED
|
@@ -3,8 +3,6 @@ function formatError(error) {
|
|
|
3
3
|
return error instanceof Error ? error.message : String(error);
|
|
4
4
|
}
|
|
5
5
|
function browserAccessLabel(access) {
|
|
6
|
-
if (access.kind === 'agentbay')
|
|
7
|
-
return 'AgentBay, temporary';
|
|
8
6
|
if (access.kind === 'sandbox-novnc' && 'environment' in access) {
|
|
9
7
|
return access.environment === 'opensandbox' ? 'OpenSandbox noVNC' : 'AONE Sandbox noVNC';
|
|
10
8
|
}
|
package/dist/cli.js
CHANGED
|
@@ -8,13 +8,13 @@ import { commandInput, findCommandSuggestions, formatCommandSuggestions, } from
|
|
|
8
8
|
import { COMMANDS, COMMAND_MAP } from './commands.js';
|
|
9
9
|
import { CLIENT_VERSION } from './socket.js';
|
|
10
10
|
import { UnifiedClient } from './unified.js';
|
|
11
|
-
import { findPluginEntry, findPluginRegistration, listPluginNames,
|
|
11
|
+
import { findPluginEntry, findPluginRegistration, findOfficialPlugin, listPluginNames, listOfficialPluginNames, loadRegisteredPlugin, PluginError, } from './plugin.js';
|
|
12
12
|
import { getCloudServerConfigPath, loadCloudServerConfig } from './unifiedConfig.js';
|
|
13
13
|
const TOP_LEVEL_COMMAND_NAME_WIDTH = 22;
|
|
14
14
|
const CATEGORIES = [
|
|
15
15
|
{
|
|
16
16
|
title: 'API 调试',
|
|
17
|
-
names: ['tab_checkpoint', 'get_requests', 'get_logs', 'get_events'
|
|
17
|
+
names: ['tab_checkpoint', 'get_requests', 'get_logs', 'get_events'],
|
|
18
18
|
},
|
|
19
19
|
{ title: 'Mock & 规则', names: ['set_mock', 'get_mocks', 'set_rule', 'get_rules'] },
|
|
20
20
|
{
|
|
@@ -46,9 +46,7 @@ const CATEGORIES = [
|
|
|
46
46
|
title: '环境与 Cookie',
|
|
47
47
|
names: ['set_device_emulation', 'set_app_profile', 'set_timezone', 'get_cookie', 'set_cookie'],
|
|
48
48
|
},
|
|
49
|
-
{ title: '用户信息', names: ['get_user_info'] },
|
|
50
49
|
{ title: '录制', names: ['record_start', 'record_stop'] },
|
|
51
|
-
{ title: 'TDBank', names: ['tdbank_account'] },
|
|
52
50
|
{
|
|
53
51
|
title: '浏览器',
|
|
54
52
|
names: ['browser_list', 'browser_release', 'browser_launch', 'browser_close'],
|
|
@@ -61,7 +59,16 @@ const BUILTIN_COMMANDS = [
|
|
|
61
59
|
examples: ['check'],
|
|
62
60
|
},
|
|
63
61
|
];
|
|
64
|
-
const
|
|
62
|
+
const OFFICIAL_PLUGIN_COMMANDS = listOfficialPluginNames().map(name => ({
|
|
63
|
+
name,
|
|
64
|
+
description: findOfficialPlugin(name).description,
|
|
65
|
+
examples: [name],
|
|
66
|
+
}));
|
|
67
|
+
const SUGGESTABLE_COMMANDS = [
|
|
68
|
+
...COMMANDS,
|
|
69
|
+
...BUILTIN_COMMANDS,
|
|
70
|
+
...OFFICIAL_PLUGIN_COMMANDS,
|
|
71
|
+
];
|
|
65
72
|
const ADVANCED_BUILTIN_COMMANDS = new Set(['connector_list']);
|
|
66
73
|
function printUsage(commandName, version) {
|
|
67
74
|
const lines = [
|
|
@@ -115,6 +122,14 @@ function printUsage(commandName, version) {
|
|
|
115
122
|
});
|
|
116
123
|
lines.push('', '已注册插件:', ...entries);
|
|
117
124
|
}
|
|
125
|
+
const installed = new Set(plugins);
|
|
126
|
+
const available = listOfficialPluginNames().filter(name => !installed.has(name));
|
|
127
|
+
if (available.length) {
|
|
128
|
+
lines.push('', '官方插件(首次调用自动安装):', ...available.map(name => {
|
|
129
|
+
const description = findOfficialPlugin(name).description;
|
|
130
|
+
return ` ${name.padEnd(TOP_LEVEL_COMMAND_NAME_WIDTH)}${description}`;
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
118
133
|
}
|
|
119
134
|
catch (error) {
|
|
120
135
|
lines.push('', error instanceof Error ? error.message : String(error));
|
|
@@ -126,6 +141,78 @@ function printUsage(commandName, version) {
|
|
|
126
141
|
lines.push('', `运行 ${commandName} <action> --help 查看 action 参数。`);
|
|
127
142
|
console.error(lines.join('\n'));
|
|
128
143
|
}
|
|
144
|
+
function providerSchemaLine(name, schema, required, indent = 2) {
|
|
145
|
+
const detail = [
|
|
146
|
+
required ? '必填' : '可选',
|
|
147
|
+
schema.type,
|
|
148
|
+
schema.type === 'string' && schema.secret ? '敏感' : undefined,
|
|
149
|
+
schema.title,
|
|
150
|
+
schema.description,
|
|
151
|
+
schema.default === undefined ? undefined : `默认 ${JSON.stringify(schema.default)}`,
|
|
152
|
+
].filter(Boolean);
|
|
153
|
+
return `${' '.repeat(indent)}${name.padEnd(Math.max(1, 24 - indent))}${detail.join(' · ')}`;
|
|
154
|
+
}
|
|
155
|
+
function providerSchemaLines(name, schema, required, indent = 2) {
|
|
156
|
+
const lines = [providerSchemaLine(name, schema, required, indent)];
|
|
157
|
+
if (schema.type === 'object') {
|
|
158
|
+
const childRequired = new Set(schema.required ?? []);
|
|
159
|
+
for (const [childName, childSchema] of Object.entries(schema.properties)) {
|
|
160
|
+
lines.push(...providerSchemaLines(childName, childSchema, childRequired.has(childName), indent + 2));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
else if (schema.type === 'array' && schema.items.type === 'object') {
|
|
164
|
+
const childRequired = new Set(schema.items.required ?? []);
|
|
165
|
+
for (const [childName, childSchema] of Object.entries(schema.items.properties)) {
|
|
166
|
+
lines.push(...providerSchemaLines(childName, childSchema, childRequired.has(childName), indent + 2));
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return lines;
|
|
170
|
+
}
|
|
171
|
+
function printProviderHelp(commandName, provider) {
|
|
172
|
+
const browserType = provider.browserType;
|
|
173
|
+
const lines = [
|
|
174
|
+
`${provider.providerId} — ${provider.name} v${provider.version}`,
|
|
175
|
+
'',
|
|
176
|
+
...(browserType.help ?? []).map(line => String(line)),
|
|
177
|
+
];
|
|
178
|
+
if (browserType.help?.length)
|
|
179
|
+
lines.push('');
|
|
180
|
+
lines.push('创建:', ` ${commandName} browser_launch --payload '{"provider":"${provider.providerId}","providerOptions":{}}'`, '', '启动参数(providerOptions):');
|
|
181
|
+
const required = new Set(browserType.inputSchema.required ?? []);
|
|
182
|
+
const properties = Object.entries(browserType.inputSchema.properties);
|
|
183
|
+
if (properties.length === 0)
|
|
184
|
+
lines.push(' (无)');
|
|
185
|
+
else {
|
|
186
|
+
for (const [name, schema] of properties) {
|
|
187
|
+
lines.push(...providerSchemaLines(name, schema, required.has(name)));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (browserType.inputSchema.oneOf?.length) {
|
|
191
|
+
lines.push('', '可选模式:');
|
|
192
|
+
browserType.inputSchema.oneOf.forEach((schema, index) => {
|
|
193
|
+
const mode = schema.title || `模式 ${index + 1}`;
|
|
194
|
+
const requiredFields = schema.required?.length ? schema.required.join(', ') : '无必填字段';
|
|
195
|
+
lines.push(` ${mode}(必填:${requiredFields})`);
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
lines.push('', '发现与检查:', ` ${commandName} browser_list`, ` ${commandName} check --browser <browserId>`, '', '管理:', ` npx @mearl/setup provider update ${provider.providerId}`, ` npx @mearl/setup provider uninstall ${provider.providerId}`);
|
|
199
|
+
if (browserType.configuration) {
|
|
200
|
+
lines.push('', 'Provider 配置(在 Mearl 浏览器管理器中填写):');
|
|
201
|
+
const configurationRequired = new Set(browserType.configuration.inputSchema.required ?? []);
|
|
202
|
+
for (const [name, schema] of Object.entries(browserType.configuration.inputSchema.properties)) {
|
|
203
|
+
lines.push(...providerSchemaLines(name, schema, configurationRequired.has(name)));
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
if (browserType.documentationUrl) {
|
|
207
|
+
lines.push('', `文档:${browserType.documentationUrl}`);
|
|
208
|
+
}
|
|
209
|
+
console.error(lines.join('\n'));
|
|
210
|
+
}
|
|
211
|
+
function installedProvider(name) {
|
|
212
|
+
if (!name)
|
|
213
|
+
return undefined;
|
|
214
|
+
return listInstalledProviders().find(provider => provider.providerId === name);
|
|
215
|
+
}
|
|
129
216
|
function printCheckHelp(commandName) {
|
|
130
217
|
console.error([
|
|
131
218
|
'check',
|
|
@@ -341,7 +428,7 @@ export function parseClientArgs(args, plugin = false) {
|
|
|
341
428
|
: {}),
|
|
342
429
|
};
|
|
343
430
|
}
|
|
344
|
-
async function runPluginCli(args,
|
|
431
|
+
async function runPluginCli(args, commandName) {
|
|
345
432
|
let parsed;
|
|
346
433
|
try {
|
|
347
434
|
parsed = parseClientArgs(args, true);
|
|
@@ -359,23 +446,23 @@ async function runPluginCli(args, entry, commandName) {
|
|
|
359
446
|
...(parsed.local ? { local: true } : {}),
|
|
360
447
|
...(parsed.forceCdp ? { transport: 'cdp' } : {}),
|
|
361
448
|
};
|
|
362
|
-
const plugin = await
|
|
363
|
-
options: invokeOptions,
|
|
364
|
-
progress(message) {
|
|
365
|
-
if (parsed.verbose) {
|
|
366
|
-
process.stderr.write(message.endsWith('\n') ? message : `${message}\n`);
|
|
367
|
-
}
|
|
368
|
-
},
|
|
449
|
+
const plugin = await loadRegisteredPlugin(parsed.action, {
|
|
369
450
|
async invoke(action, payload, options) {
|
|
370
451
|
client ??= new UnifiedClient({
|
|
371
452
|
...(parsed.serverUrl ? { serverUrl: parsed.serverUrl } : {}),
|
|
372
453
|
});
|
|
373
|
-
|
|
374
|
-
if (result?.action?.success === false)
|
|
375
|
-
throw new Error(result.action.error || `${action} failed`);
|
|
376
|
-
return result;
|
|
454
|
+
return client.invoke(action, payload, options);
|
|
377
455
|
},
|
|
378
|
-
},
|
|
456
|
+
}, {
|
|
457
|
+
...invokeOptions,
|
|
458
|
+
...(parsed.verbose
|
|
459
|
+
? {
|
|
460
|
+
onProgress(message) {
|
|
461
|
+
process.stderr.write(message.endsWith('\n') ? message : `${message}\n`);
|
|
462
|
+
},
|
|
463
|
+
}
|
|
464
|
+
: {}),
|
|
465
|
+
});
|
|
379
466
|
if (parsed.version) {
|
|
380
467
|
console.log(plugin.version ?? 'unknown');
|
|
381
468
|
return 0;
|
|
@@ -435,6 +522,12 @@ export async function runMearlCli(args, options = {}) {
|
|
|
435
522
|
const clientVersion = options.clientVersion ?? CLIENT_VERSION;
|
|
436
523
|
if (args[0] === 'capture_checkpoint')
|
|
437
524
|
args = ['tab_checkpoint', ...args.slice(1)];
|
|
525
|
+
const provider = installedProvider(args[0]);
|
|
526
|
+
if (provider &&
|
|
527
|
+
(args.length === 1 || args.slice(1).every(arg => arg === '--help' || arg === '-h'))) {
|
|
528
|
+
printProviderHelp(commandName, provider);
|
|
529
|
+
return 0;
|
|
530
|
+
}
|
|
438
531
|
if (args[0] &&
|
|
439
532
|
!args[0].startsWith('-') &&
|
|
440
533
|
!args[0].startsWith('__') &&
|
|
@@ -443,8 +536,8 @@ export async function runMearlCli(args, options = {}) {
|
|
|
443
536
|
!COMMAND_MAP.has(args[0])) {
|
|
444
537
|
try {
|
|
445
538
|
const entry = findPluginEntry(args[0]);
|
|
446
|
-
if (entry)
|
|
447
|
-
return await runPluginCli(args,
|
|
539
|
+
if (entry || findOfficialPlugin(args[0]))
|
|
540
|
+
return await runPluginCli(args, commandName);
|
|
448
541
|
}
|
|
449
542
|
catch (error) {
|
|
450
543
|
console.error(error instanceof Error ? error.message : String(error));
|
package/dist/commands.d.ts
CHANGED
|
@@ -142,24 +142,6 @@ export declare const COMMANDS: readonly [{
|
|
|
142
142
|
readonly description: "返回完整 URL、_raw 和 _context;默认 false";
|
|
143
143
|
}];
|
|
144
144
|
readonly examples: ["get_events --payload '{\"source\":\"aplus\",\"event_type\":\"CLK\",\"limit\":10}'", "get_events --payload '{\"filter\":\"order\",\"includeRaw\":true,\"limit\":1}'", "get_events --payload '{\"tabId\":12345,\"source\":\"all\",\"limit\":20}'"];
|
|
145
|
-
}, {
|
|
146
|
-
readonly name: "get_api_schema";
|
|
147
|
-
readonly description: "获取 API 接口 schema(出入参定义)";
|
|
148
|
-
readonly params: [{
|
|
149
|
-
readonly name: "api";
|
|
150
|
-
readonly type: "string";
|
|
151
|
-
readonly required: true;
|
|
152
|
-
readonly description: "API 名称";
|
|
153
|
-
}, {
|
|
154
|
-
readonly name: "version";
|
|
155
|
-
readonly type: "string";
|
|
156
|
-
readonly description: "API 版本,用于精确匹配接口定义";
|
|
157
|
-
}, {
|
|
158
|
-
readonly name: "fields";
|
|
159
|
-
readonly type: "(\"schema\" | \"hsf\")[]";
|
|
160
|
-
readonly description: "指定返回内容;不填时返回全部可用内容";
|
|
161
|
-
}];
|
|
162
|
-
readonly examples: ["get_api_schema --payload '{\"api\":\"mtop.trade.order.detail\"}'"];
|
|
163
145
|
}, {
|
|
164
146
|
readonly name: "set_mock";
|
|
165
147
|
readonly description: "设置 API mock 数据";
|
|
@@ -334,100 +316,43 @@ export declare const COMMANDS: readonly [{
|
|
|
334
316
|
readonly description: "超时毫秒数,默认 10000";
|
|
335
317
|
}];
|
|
336
318
|
readonly examples: ["send_mtop_request --payload '{\"api\":\"mtop.trade.order.detail\",\"data\":{\"orderId\":\"123\"}}'"];
|
|
337
|
-
}, {
|
|
338
|
-
readonly name: "tdbank_account";
|
|
339
|
-
readonly description: "TDBank 账号操作:获取扫码登录二维码、当前账号、账号列表、切换账号、快速借用并切换账号";
|
|
340
|
-
readonly params: [{
|
|
341
|
-
readonly name: "tabId";
|
|
342
|
-
readonly type: "number";
|
|
343
|
-
readonly description: "login 首次不传;后续传上次响应的 tabId;无法恢复待扫码状态时会返回新的 tabId;其他操作在 CDP 模式下用于读取 Cookie";
|
|
344
|
-
}, {
|
|
345
|
-
readonly name: "operation";
|
|
346
|
-
readonly type: "\"current\" | \"list\" | \"login\" | \"switch\" | \"borrow\"";
|
|
347
|
-
readonly description: "操作类型,默认 current";
|
|
348
|
-
}, {
|
|
349
|
-
readonly name: "refresh";
|
|
350
|
-
readonly type: "boolean";
|
|
351
|
-
readonly description: "list 时是否强制刷新账号列表";
|
|
352
|
-
}, {
|
|
353
|
-
readonly name: "pageIndex";
|
|
354
|
-
readonly type: "number";
|
|
355
|
-
readonly description: "list 时的页码,默认 1";
|
|
356
|
-
}, {
|
|
357
|
-
readonly name: "accountId";
|
|
358
|
-
readonly type: "string | number";
|
|
359
|
-
readonly description: "switch 时使用账号列表中的 id";
|
|
360
|
-
}, {
|
|
361
|
-
readonly name: "havanaId";
|
|
362
|
-
readonly type: "string | number";
|
|
363
|
-
readonly description: "switch 时直接指定 havanaId;TDBank 方式需配合 site,免密方式需配合 ssoKey";
|
|
364
|
-
}, {
|
|
365
|
-
readonly name: "site";
|
|
366
|
-
readonly type: "string | number";
|
|
367
|
-
readonly description: "TDBank 方式直接指定 havanaId 时必填";
|
|
368
|
-
}, {
|
|
369
|
-
readonly name: "ssoKey";
|
|
370
|
-
readonly type: "string";
|
|
371
|
-
readonly description: "switch 免密方式的秘钥;必须同时传 havanaId,site 固定为 taobao";
|
|
372
|
-
}, {
|
|
373
|
-
readonly name: "query";
|
|
374
|
-
readonly type: "string";
|
|
375
|
-
readonly description: "borrow 时输入要借用的账号 loginId/关键词";
|
|
376
|
-
}, {
|
|
377
|
-
readonly name: "identityId";
|
|
378
|
-
readonly type: "string | number";
|
|
379
|
-
readonly description: "login 返回 identity_required 后,传用户明确选择的 identityId";
|
|
380
|
-
}];
|
|
381
|
-
readonly examples: ["tdbank_account --payload '{\"operation\":\"login\"}'", "tdbank_account --payload '{\"operation\":\"login\",\"tabId\":12345}'", "tdbank_account --payload '{\"operation\":\"login\",\"tabId\":12345,\"identityId\":\"10001\"}'", "tdbank_account --payload '{\"operation\":\"current\"}'", "tdbank_account --payload '{\"operation\":\"list\",\"refresh\":true}'", "tdbank_account --payload '{\"operation\":\"switch\",\"accountId\":12345}'", "tdbank_account --payload '{\"operation\":\"switch\",\"havanaId\":\"1234567890\",\"ssoKey\":\"<secret>\"}'", "tdbank_account --payload '{\"operation\":\"borrow\",\"query\":\"test_account\"}'"];
|
|
382
319
|
}, {
|
|
383
320
|
readonly name: "browser_list";
|
|
384
|
-
readonly description: "
|
|
321
|
+
readonly description: "列出所有浏览器及其连接状态、类型和 Provider 托管实例信息";
|
|
385
322
|
readonly summary: "列出本地及远端浏览器与连接状态";
|
|
386
323
|
readonly examples: ["browser_list"];
|
|
387
324
|
}, {
|
|
388
325
|
readonly name: "browser_release";
|
|
389
|
-
readonly description: "
|
|
390
|
-
readonly summary: "
|
|
326
|
+
readonly description: "释放当前浏览器的调试控制和会话级临时效果(含设备/时区模拟);不用于普通任务收尾,Provider 实例的行为以 mearl <providerId> 为准";
|
|
327
|
+
readonly summary: "释放浏览器调试控制和会话级临时效果";
|
|
391
328
|
readonly examples: ["browser_release", "browser_release --browser chrome-a"];
|
|
392
329
|
}, {
|
|
393
330
|
readonly name: "browser_launch";
|
|
394
|
-
readonly description: "启动本地 Chrome
|
|
331
|
+
readonly description: "启动本地 Chrome,或通过已注册 Provider 创建浏览器实例";
|
|
395
332
|
readonly params: [{
|
|
396
333
|
readonly name: "name";
|
|
397
334
|
readonly type: "string";
|
|
398
|
-
readonly description: "
|
|
335
|
+
readonly description: "本地实例名称;使用 local Provider 时必填";
|
|
399
336
|
}, {
|
|
400
337
|
readonly name: "provider";
|
|
401
338
|
readonly type: "string";
|
|
402
|
-
readonly description: "运行环境,默认 local;可传
|
|
339
|
+
readonly description: "运行环境,默认 local;可传 mearl --help 中展示的已注册 Provider ID";
|
|
403
340
|
}, {
|
|
404
341
|
readonly name: "providerOptions";
|
|
405
342
|
readonly type: "Record<string, JSON value>";
|
|
406
343
|
readonly description: "所选 Provider 声明的结构化启动参数;不能与顶层启动字段混用";
|
|
407
|
-
}, {
|
|
408
|
-
readonly name: "sessionId";
|
|
409
|
-
readonly type: "string";
|
|
410
|
-
readonly description: "显式接入现有 AgentBay Session;不会创建、初始化或取得其生命周期所有权";
|
|
411
|
-
}, {
|
|
412
|
-
readonly name: "reuse";
|
|
413
|
-
readonly type: "\"never\" | \"prefer\" | \"require\"";
|
|
414
|
-
readonly description: "AgentBay 运行实例复用策略:never 默认不复用;prefer 同名运行实例存在则复用、无记录则创建;require 只复用、不创建";
|
|
415
|
-
}, {
|
|
416
|
-
readonly name: "imageId";
|
|
417
|
-
readonly type: "string";
|
|
418
|
-
readonly description: "AgentBay 镜像别名或具体镜像 ID;默认使用已验证的 Linux Browser Use 内网镜像";
|
|
419
344
|
}, {
|
|
420
345
|
readonly name: "headless";
|
|
421
346
|
readonly type: "boolean";
|
|
422
|
-
readonly description: "本地
|
|
347
|
+
readonly description: "本地 Provider 是否无头运行,默认 true";
|
|
423
348
|
}, {
|
|
424
349
|
readonly name: "userAgentMode";
|
|
425
350
|
readonly type: "\"default\" | \"desktop\"";
|
|
426
|
-
readonly description: "UA 模式:default
|
|
351
|
+
readonly description: "本地 UA 模式:default 使用默认 UA;desktop 使用匹配本机版本的 UA";
|
|
427
352
|
}, {
|
|
428
353
|
readonly name: "persistent";
|
|
429
354
|
readonly type: "boolean";
|
|
430
|
-
readonly description: "
|
|
355
|
+
readonly description: "本地实例关闭后是否保留 Profile,默认 false";
|
|
431
356
|
}, {
|
|
432
357
|
readonly name: "url";
|
|
433
358
|
readonly type: "string";
|
|
@@ -436,35 +361,15 @@ export declare const COMMANDS: readonly [{
|
|
|
436
361
|
readonly name: "executablePath";
|
|
437
362
|
readonly type: "string";
|
|
438
363
|
readonly description: "自定义 Chrome 可执行文件路径";
|
|
439
|
-
}, {
|
|
440
|
-
readonly name: "accountId";
|
|
441
|
-
readonly type: "string | number";
|
|
442
|
-
readonly description: "登录账号列表中的 accountId";
|
|
443
|
-
}, {
|
|
444
|
-
readonly name: "havanaId";
|
|
445
|
-
readonly type: "string | number";
|
|
446
|
-
readonly description: "直接登录 havanaId;需要同时传 site";
|
|
447
|
-
}, {
|
|
448
|
-
readonly name: "site";
|
|
449
|
-
readonly type: "string | number";
|
|
450
|
-
readonly description: "havanaId 对应的站点";
|
|
451
|
-
}, {
|
|
452
|
-
readonly name: "query";
|
|
453
|
-
readonly type: "string";
|
|
454
|
-
readonly description: "搜索、借用并登录匹配的 TDBank 账号";
|
|
455
|
-
}, {
|
|
456
|
-
readonly name: "tabId";
|
|
457
|
-
readonly type: "number";
|
|
458
|
-
readonly description: "CDP 控制浏览器中用于读取 TDBank Cookie 的标签页";
|
|
459
364
|
}, {
|
|
460
365
|
readonly name: "copyCookieDomains";
|
|
461
366
|
readonly type: "string[] | \"mearl-services\" | { presets?: [\"mearl-services\"]; domains?: string[] }";
|
|
462
367
|
readonly description: "从控制浏览器复制 Cookie:可传域名数组、Mearl 登录态预设,或组合预设与额外域名";
|
|
463
368
|
}];
|
|
464
|
-
readonly examples: ["browser_launch --payload '{\"provider\":\"brow\",\"providerOptions\":{}}'", "browser_launch --payload '{\"name\":\"
|
|
369
|
+
readonly examples: ["browser_launch --payload '{\"provider\":\"brow\",\"providerOptions\":{}}'", "browser_launch --payload '{\"name\":\"figma\",\"userAgentMode\":\"desktop\",\"copyCookieDomains\":[\"figma.com\"]}'", "browser_launch --payload '{\"name\":\"with-cookies\",\"copyCookieDomains\":[\"example.com\",\"sub.example.org\"]}'"];
|
|
465
370
|
}, {
|
|
466
371
|
readonly name: "browser_close";
|
|
467
|
-
readonly description: "
|
|
372
|
+
readonly description: "关闭指定托管浏览器,并按 Provider 策略保留或清理持久化数据";
|
|
468
373
|
readonly params: [{
|
|
469
374
|
readonly name: "browser";
|
|
470
375
|
readonly type: "string";
|
|
@@ -473,9 +378,9 @@ export declare const COMMANDS: readonly [{
|
|
|
473
378
|
}, {
|
|
474
379
|
readonly name: "deleteProfile";
|
|
475
380
|
readonly type: "boolean";
|
|
476
|
-
readonly description: "
|
|
381
|
+
readonly description: "强制删除持久化数据,默认 false";
|
|
477
382
|
}];
|
|
478
|
-
readonly examples: ["browser_close --payload '{\"browser\":\"managed:account-a\"}'", "browser_close --payload '{\"browser\":\"
|
|
383
|
+
readonly examples: ["browser_close --payload '{\"browser\":\"managed:account-a\"}'", "browser_close --payload '{\"browser\":\"account-b\",\"deleteProfile\":true}'"];
|
|
479
384
|
}, {
|
|
480
385
|
readonly name: "tab_open";
|
|
481
386
|
readonly description: "打开或按 URL 规则复用 Tab,并等待新页面加载完成";
|
|
@@ -885,15 +790,6 @@ export declare const COMMANDS: readonly [{
|
|
|
885
790
|
readonly description: "目标标签页 ID";
|
|
886
791
|
}];
|
|
887
792
|
readonly examples: ["page_selected_element", "page_selected_element --output ./element.png"];
|
|
888
|
-
}, {
|
|
889
|
-
readonly name: "get_user_info";
|
|
890
|
-
readonly description: "获取当前浏览器登录的阿里员工信息";
|
|
891
|
-
readonly params: [{
|
|
892
|
-
readonly name: "detail";
|
|
893
|
-
readonly type: "boolean";
|
|
894
|
-
readonly description: "是否获取完整用户信息,默认 false(只返回工号)";
|
|
895
|
-
}];
|
|
896
|
-
readonly examples: ["get_user_info", "get_user_info --payload '{\"detail\":true}'"];
|
|
897
793
|
}, {
|
|
898
794
|
readonly name: "record_start";
|
|
899
795
|
readonly description: "开始录制用户操作";
|
|
@@ -1034,7 +930,7 @@ export declare const COMMANDS: readonly [{
|
|
|
1034
930
|
readonly examples: ["set_timezone --payload '{\"tabId\":12345,\"timezone\":\"America/New_York\"}'", "set_timezone --payload '{\"tabId\":12345,\"timezone\":\"\"}'"];
|
|
1035
931
|
}, {
|
|
1036
932
|
readonly name: "get_cookie";
|
|
1037
|
-
readonly description: "
|
|
933
|
+
readonly description: "从目标浏览器读取一个指定非分区 Cookie;拒绝返回 HttpOnly Cookie";
|
|
1038
934
|
readonly params: [{
|
|
1039
935
|
readonly name: "tabId";
|
|
1040
936
|
readonly type: "number";
|
|
@@ -1045,16 +941,20 @@ export declare const COMMANDS: readonly [{
|
|
|
1045
941
|
readonly type: "string";
|
|
1046
942
|
readonly required: true;
|
|
1047
943
|
readonly description: "要读取的 Cookie 名称;不支持列举全部 Cookie";
|
|
944
|
+
}, {
|
|
945
|
+
readonly name: "url";
|
|
946
|
+
readonly type: "string";
|
|
947
|
+
readonly description: "可选 Cookie 查询 URL;省略时使用当前标签页 URL";
|
|
1048
948
|
}, {
|
|
1049
949
|
readonly name: "domain";
|
|
1050
950
|
readonly type: "string";
|
|
1051
|
-
readonly description: "
|
|
951
|
+
readonly description: "可选精确域过滤,只允许 Cookie 查询 URL 的 host 或其父域";
|
|
1052
952
|
}, {
|
|
1053
953
|
readonly name: "path";
|
|
1054
954
|
readonly type: "string";
|
|
1055
955
|
readonly description: "可选精确 path 过滤";
|
|
1056
956
|
}];
|
|
1057
|
-
readonly examples: ["get_cookie --payload '{\"tabId\":12345,\"name\":\"feature_flag\"}'", "get_cookie --payload '{\"tabId\":12345,\"name\":\"edith_switch_br.rx-vehicle-search_home\",\"domain\":\"taobao.com\"}'"];
|
|
957
|
+
readonly examples: ["get_cookie --payload '{\"tabId\":12345,\"name\":\"feature_flag\"}'", "get_cookie --payload '{\"tabId\":12345,\"name\":\"edith_switch_br.rx-vehicle-search_home\",\"domain\":\"taobao.com\"}'", "get_cookie --payload '{\"tabId\":12345,\"name\":\"tracknick\",\"url\":\"https://www.taobao.com/\",\"domain\":\"taobao.com\",\"path\":\"/\"}'"];
|
|
1058
958
|
}, {
|
|
1059
959
|
readonly name: "set_cookie";
|
|
1060
960
|
readonly description: "设置当前标签页域下的一个指定非分区 session Cookie,可选刷新页面";
|