@mearl/client 3.0.0-beta.1 → 3.0.0-beta.10
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 +333 -246
- package/README.zh-CN.md +612 -0
- package/dist/actionTimeouts.js +0 -3
- package/dist/autoUpdate.js +3 -1
- package/dist/bin.js +12 -5
- package/dist/capabilityHelp.d.ts +4 -0
- package/dist/capabilityHelp.js +68 -0
- package/dist/check.d.ts +5 -6
- package/dist/check.js +2 -5
- package/dist/cli.js +29 -56
- package/dist/commandHelp.d.ts +3 -0
- package/dist/commandHelp.js +79 -0
- package/dist/commandSuggestions.d.ts +3 -0
- package/dist/commandSuggestions.js +16 -5
- package/dist/commands.d.ts +70 -65
- package/dist/commands.js +60 -55
- package/dist/guide.d.ts +46 -0
- package/dist/guide.js +80 -0
- package/dist/guides/api-browser-setup.md +93 -0
- package/dist/guides/api-page-automation.md +140 -0
- package/dist/guides/api-page-debugging.md +39 -0
- package/dist/guides/api-page-environment.md +37 -0
- package/dist/guides/api-request-debugging.md +54 -0
- package/dist/guides/browser-tool-cooperation.md +23 -0
- package/dist/guides/core.md +60 -0
- package/dist/guides/related-skills.md +51 -0
- package/dist/guides/scripting.md +21 -0
- package/dist/guides/troubleshooting.md +170 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +8 -5
- package/dist/plugins/clients/pluginHostConnection.d.ts +2 -0
- package/dist/plugins/clients/pluginHostConnection.js +3 -1
- package/dist/plugins/officialPluginInstaller.js +2 -1
- package/dist/plugins/pluginRegistry.d.ts +1 -1
- package/dist/plugins/pluginRegistry.js +21 -7
- package/dist/plugins/runtime/pluginCommandWorker.js +8 -6
- package/dist/plugins/runtime/pluginDiagnostics.js +1 -1
- package/dist/plugins/runtime/pluginExecutor.d.ts +5 -0
- package/dist/plugins/runtime/pluginExecutor.js +15 -2
- package/dist/plugins/runtime/pluginExecutorProtocol.d.ts +4 -0
- package/dist/plugins/runtime/pluginExecutorSupervisor.js +2 -1
- package/dist/plugins/runtime/pluginHostServer.js +5 -1
- package/dist/plugins/runtime/pluginPageManager.js +2 -6
- package/dist/plugins/runtime/pluginRevision.js +0 -51
- package/dist/plugins/runtime/pluginStateManager.js +1 -1
- package/dist/plugins/runtime/pluginStateStore.js +3 -8
- package/dist/plugins/runtime/pluginTaskManager.js +5 -9
- package/dist/plugins/sdk/plugin.d.ts +9 -0
- package/dist/plugins/sdk/plugin.js +22 -9
- package/dist/plugins/sdk/pluginModelDefinition.js +0 -6
- package/dist/plugins/sdk/pluginPageDefinition.d.ts +0 -1
- package/dist/plugins/sdk/pluginPageDefinition.js +2 -18
- package/dist/plugins/sdk/pluginRecoveryDefinition.js +0 -3
- package/dist/plugins/sdk/pluginStateDefinition.d.ts +0 -1
- package/dist/plugins/sdk/pluginStateDefinition.js +0 -11
- package/dist/runtimePaths.d.ts +1 -0
- package/dist/runtimePaths.js +1 -0
- package/dist/script.d.ts +30 -0
- package/dist/script.js +261 -0
- package/dist/scriptCli.d.ts +1 -0
- package/dist/scriptCli.js +94 -0
- package/dist/scriptErrors.d.ts +8 -0
- package/dist/scriptErrors.js +21 -0
- package/dist/scriptWorker.d.ts +1 -0
- package/dist/scriptWorker.js +50 -0
- package/dist/sdkMethods.d.ts +3 -0
- package/dist/sdkMethods.js +9 -0
- package/dist/socket.js +33 -8
- package/dist/unified.js +11 -1
- package/dist/unifiedConfig.d.ts +4 -0
- package/dist/unifiedConfig.js +11 -0
- package/package.json +14 -12
package/README.md
CHANGED
|
@@ -1,25 +1,31 @@
|
|
|
1
1
|
# @mearl/client
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[English](README.md) | [简体中文](README.zh-CN.md)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
CLI, TypeScript SDK, and scripting entry points share browser routing and plugin runtimes. `@mearl/setup` manages installation and runtime connections.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Run `mearl guide` for the core workflow in this version; `mearl guide --list` lists topics. For example, `mearl guide run` covers SDK composition and `mearl guide environment` covers devices/Apps. Guides read bundled npm resources without browser connections, plugin loading, installation, or automatic updates. Use `mearl <action> --help` for arguments and existing catalogs for installed target capabilities.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Guide content is maintained only in this package's `guides/`, copied to `dist/guides/` at build time, and checked by `pnpm check:skills`. CLI output converts local document links into guide commands. `skills/mearl/` distributes only a compact `SKILL.md`, without guide copies. MCP-only clients unable to run CLI use current tool descriptions/schemas. Organization-specific distributions supply installation, authentication, and business guidance through separate Skills.
|
|
10
|
+
|
|
11
|
+
A unified browser SDK and CLI discovering browsers on this machine and all connectors under configured cloud-server instances. Global `browserId` from `browser_list` selects local Socket or cloud WebSocket routing automatically.
|
|
12
|
+
|
|
13
|
+
Use type-safe named methods such as `getRequests` and `sendRequest`, or the flexible low-level `invoke(action, payload)`.
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
10
16
|
|
|
11
17
|
```bash
|
|
12
|
-
npm install @mearl/client
|
|
13
|
-
#
|
|
14
|
-
pnpm add @mearl/client
|
|
18
|
+
npm install @mearl/client@beta
|
|
19
|
+
# Or
|
|
20
|
+
pnpm add @mearl/client@beta
|
|
15
21
|
```
|
|
16
22
|
|
|
17
|
-
## SDK
|
|
23
|
+
## SDK usage
|
|
18
24
|
|
|
19
25
|
```typescript
|
|
20
26
|
import * as client from '@mearl/client';
|
|
21
27
|
|
|
22
|
-
//
|
|
28
|
+
// Type-safe named methods
|
|
23
29
|
const requests = await client.getRequests({ tabId: 12345, count: 5 });
|
|
24
30
|
const result = await client.sendRequest({
|
|
25
31
|
url: 'https://api.example.com',
|
|
@@ -27,45 +33,45 @@ const result = await client.sendRequest({
|
|
|
27
33
|
withCookies: true,
|
|
28
34
|
});
|
|
29
35
|
|
|
30
|
-
//
|
|
36
|
+
// Flexible low-level invocation
|
|
31
37
|
const data = await client.invoke('send_request', { url: '...' });
|
|
32
38
|
|
|
33
|
-
// browser_list
|
|
39
|
+
// browser_list aggregates local and all remote connectors by default
|
|
34
40
|
const browsers = await client.browserList();
|
|
35
41
|
await client.getLogs({ tabId: 12345 }, { browser: browsers.browsers[0].browserId });
|
|
36
42
|
```
|
|
37
43
|
|
|
38
|
-
## CLI
|
|
44
|
+
## CLI usage
|
|
39
45
|
|
|
40
|
-
|
|
46
|
+
Installation provides the `mearl` command:
|
|
41
47
|
|
|
42
48
|
```bash
|
|
43
|
-
#
|
|
49
|
+
# Get the five latest requests
|
|
44
50
|
mearl get_requests --payload '{"tabId":12345,"count":5}'
|
|
45
51
|
|
|
46
|
-
#
|
|
52
|
+
# Proxy an HTTP request
|
|
47
53
|
mearl send_request --payload '{"url":"https://api.example.com","method":"GET"}'
|
|
48
54
|
|
|
49
|
-
#
|
|
55
|
+
# Upload a local file with multipart/form-data
|
|
50
56
|
mearl send_request --payload '{"url":"https://api.example.com/upload","method":"POST","formData":{"folder":"assets"},"files":[{"fieldName":"file","filePath":"/absolute/path/image.png"}]}'
|
|
51
57
|
|
|
52
|
-
#
|
|
58
|
+
# Save a screenshot; tabId comes from tab_open or tab_list
|
|
53
59
|
mearl page_screenshot --payload '{"tabId":12345}' --output ./screenshot.png
|
|
54
60
|
|
|
55
|
-
#
|
|
61
|
+
# Read large parameters from a file; mock-data.json must include tabId
|
|
56
62
|
mearl set_mock --payload-file ./mock-data.json
|
|
57
63
|
|
|
58
|
-
#
|
|
64
|
+
# Check the environment
|
|
59
65
|
mearl check
|
|
60
66
|
mearl check --local --json
|
|
61
67
|
|
|
62
|
-
#
|
|
63
|
-
npx @mearl/setup update --local
|
|
68
|
+
# Update the local environment
|
|
69
|
+
npx @mearl/setup@beta update --local
|
|
64
70
|
|
|
65
|
-
#
|
|
71
|
+
# Show action help
|
|
66
72
|
mearl <action> --help
|
|
67
73
|
|
|
68
|
-
#
|
|
74
|
+
# Launch isolated headless Chrome instances
|
|
69
75
|
mearl browser_launch --payload '{"name":"browser-a","url":"https://example.com"}'
|
|
70
76
|
mearl browser_launch --payload '{"name":"browser-b","persistent":true}'
|
|
71
77
|
mearl browser_launch --payload '{"name":"cookie-copy","copyCookieDomains":["example.com"]}'
|
|
@@ -74,47 +80,120 @@ mearl browser_list
|
|
|
74
80
|
mearl browser_release
|
|
75
81
|
```
|
|
76
82
|
|
|
77
|
-
###
|
|
83
|
+
### Agent scripts
|
|
84
|
+
|
|
85
|
+
`mearl run` reads JavaScript from stdin or `--file <path>`, injects the `mearl` SDK, and supports top-level `await`, conditions, loops, and data processing without task-directory dependencies:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
mearl run --session new <<'JS'
|
|
89
|
+
const tab = await mearl.tabOpen({ url: 'https://example.com', reuse: 'prefer' });
|
|
90
|
+
console.log({ tabId: tab.tabId, session: mearl.session });
|
|
91
|
+
console.log(await mearl.pageSnapshot({ tabId: tab.tabId, mode: 'viewport' }));
|
|
92
|
+
JS
|
|
93
|
+
|
|
94
|
+
mearl run --session '<sessionId>' --file /absolute/path/next-step.mjs
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Method names match the SDK, such as `mearl.pageClick(params, options?)`, `mearl.getRequests(params, options?)`,
|
|
98
|
+
and `mearl.tabList(options?)`. Use `mearl.invoke(action, payload, options?)` for generic calls.
|
|
99
|
+
Arguments/results match ordinary actions; consult `mearl <action> --help`. Action failures still use `action.success`,
|
|
100
|
+
`stage`, and `attempt`; scripts decide subsequent logic. Print needed results with `console.log` and diagnostics with `console.error`.
|
|
101
|
+
Returned data is not printed automatically. `run_actions` fits tight sequences without decisions; scripts fit workflows whose results code can evaluate.
|
|
102
|
+
When a model must interpret the page, print minimal observations and continue in the next round.
|
|
103
|
+
|
|
104
|
+
Scripts query command definitions through `help` and print returned text as needed. CLI `--help` shares arguments, results, constraints, and examples.
|
|
105
|
+
|
|
106
|
+
```javascript
|
|
107
|
+
console.log(await mearl.help()); // Methods and registered plugins
|
|
108
|
+
console.log(await mearl.help('pageClick')); // Also accepts page_click
|
|
109
|
+
console.log(await mearl.help({ plugin: 'notes', command: 'search' }));
|
|
110
|
+
|
|
111
|
+
const result = await mearl.invokePlugin('notes', { command: 'search', input: { query: 'project' } });
|
|
112
|
+
console.log(mearl.structure(result));
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
`structure(value, options?)` synchronously extracts an existing result's structure, replacing leaves with types. Defaults: depth 5, 50 keys per object,
|
|
116
|
+
one sample per array, 2000 total nodes. Adjust with `maxDepth`, `maxKeys`, `arraySamples`, and `maxNodes`.
|
|
117
|
+
Output includes array lengths/samples and marks cycles, accessors, and limits. Samples need not cover all optional fields or heterogeneous elements;
|
|
118
|
+
command help defines business meaning. The ordinary SDK also exports `structure`, sharing extraction logic with request `keysOnly`.
|
|
119
|
+
`keysOnly` follows the same default key/node limits and marks truncation.
|
|
120
|
+
Plugin help loads registration in isolated processes without executing the queried business command.
|
|
121
|
+
|
|
122
|
+
Compose registered Skill commands using names and inputs from plugin `--help`:
|
|
123
|
+
|
|
124
|
+
```javascript
|
|
125
|
+
const result = await mearl.invokePlugin('notes', {
|
|
126
|
+
command: 'search',
|
|
127
|
+
input: { query: 'project' },
|
|
128
|
+
});
|
|
129
|
+
console.log(result);
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Browser APIs and plugin calls inherit script `--browser`, `--session`, `--connector`, `--local`, and `--cdp`;
|
|
133
|
+
individual `options` may override them. `--server` selects cloud-server. After `--session new` establishes a session,
|
|
134
|
+
later calls use its returned ID automatically; `mearl.session` and CLI stderr report session information.
|
|
135
|
+
First await a session-establishing browser call before concurrency or Skill commands. Script completion disconnects SDK connections but retains control sessions;
|
|
136
|
+
explicitly call `mearl.browserRelease` according to task lifetime. JavaScript variables reset each round; continue with returned `sessionId` and `tabId`.
|
|
78
137
|
|
|
79
|
-
|
|
138
|
+
Scripts run in separate Node.js processes inheriting caller cwd/environment with host Node.js permissions;
|
|
139
|
+
they are not security sandboxes. Load modules through dynamic imports such as `await import('node:fs/promises')`.
|
|
140
|
+
`--file` also executes as a script function without static `import` / `export`. Prefer absolute file URLs for local modules.
|
|
141
|
+
`window` / `document` exist only in page expressions through `mearl.pageEval`. Plugin registries, local files, and authentication belong to the CLI host.
|
|
80
142
|
|
|
81
|
-
|
|
143
|
+
`--timeout <seconds>` limits the complete script, default 60 seconds. API `options.timeoutSec` limits individual calls.
|
|
144
|
+
Combined stdout/stderr allows 256 KiB; source allows 1 MiB. Await every SDK call. Missing await, timeout, cancellation, or script exceptions exit 1;
|
|
145
|
+
input errors exit 2. Cancellation/timeouts stop scripts and process groups and propagate signals to pending Skill calls. Dispatched browser/business operations may still take effect;
|
|
146
|
+
use `pendingActions` / `mayHaveLateEffects` to determine reconciliation needs, without directly rerunning the entire script.
|
|
147
|
+
Skill commands use existing isolated executors; their stdout/stderr counts toward the script limit. Exception diagnostics are also bounded.
|
|
148
|
+
Result `success` means normal script completion only. Code must check action and business outcomes.
|
|
82
149
|
|
|
83
|
-
|
|
150
|
+
SDK hosts can import `executeScript(code, options)` from `@mearl/client/script`, returning
|
|
151
|
+
`{ success, stdout, stderr, session?, error?, executionStopped, mayHaveLateEffects, pendingActions }`。
|
|
152
|
+
It supports `signal` cancellation and `executionTimeoutSec`, sharing executors with CLI/MCP.
|
|
153
|
+
|
|
154
|
+
### Control sessions and files
|
|
155
|
+
|
|
156
|
+
For multi-step tasks, use `--session new` on the first `tab_open` or `page_snapshot`. The response adds `session` alongside ordinary results; later `sessionId` routes automatically without separate creation/query actions. Sessions bind one browser/transport and associate pages on first use, tracking reused and created pages separately. One session controls a page at a time; sessionless calls cannot bypass ownership. Sessions do not isolate Cookies/storage.
|
|
157
|
+
|
|
158
|
+
`sessionId` is a short ID such as `s_aB3d_E-f`. The resident control host keeps sessions/browser/transport mappings in memory. New CLI processes internally query local/remote hosts for routing, without caller-managed routing or mapping files. Control-host exit invalidates sessions.
|
|
159
|
+
|
|
160
|
+
Calls may omit `--session`; existing actions, `run_actions`, and upload `filePaths` remain available. With active sessions, sessionless calls cannot manipulate owned pages, release/close browsers, or modify shared settings. Opening pages/closing browsers inside sessionless batches requires separate calls. CDP mocks are tab-scoped and must be configured per tab.
|
|
84
161
|
|
|
85
162
|
```bash
|
|
86
163
|
mearl tab_open --session new --payload '{"url":"https://example.com"}'
|
|
87
164
|
mearl page_snapshot --session '<sessionId>' --payload '{"tabId":12345}'
|
|
88
|
-
mearl browser_control --session '<sessionId>' --payload '{"operation":"handoff","reason":"
|
|
165
|
+
mearl browser_control --session '<sessionId>' --payload '{"operation":"handoff","reason":"Please scan the QR code"}'
|
|
89
166
|
mearl page_download --session '<sessionId>' --payload '{"tabId":12345,"trigger":{"selector":"#export"}}' --output /absolute/path/report.csv
|
|
90
167
|
mearl page_upload --session '<sessionId>' --payload '{"tabId":12345,"selector":"input[type=file]","files":[{"filePath":"/absolute/path/report.csv"}]}'
|
|
91
168
|
mearl browser_release --session '<sessionId>' --payload '{"closeCreatedTabs":true,"keepTabIds":[12345]}'
|
|
92
169
|
```
|
|
93
170
|
|
|
94
|
-
|
|
171
|
+
Users take over, return, or end sessions in Popup browser management. Handoff stops queued stale requests and later batch steps; dispatched actions may still apply. Take a fresh snapshot after return. CDP-only environments can use the same `browser_control` with `operation:"resume"` after explicit user confirmation. Sessions survive CLI connections, expire on host exit, and are not idle-cleaned while users work.
|
|
95
172
|
|
|
96
|
-
|
|
173
|
+
New extension background tabs join a collapsed `Mearl` group; foreground tabs join the expanded `Mearl · 待操作` group. Both reuse one existing window and merge same-name managed groups. Subsequent opened tabs enter that window and inherit source-group expansion. Closing the work window selects another existing window without creating one. Explicit `tab_open.group` overrides grouping; reused ordinary pages retain windows/groups. Handoff moves only managed session pages into the pending group; return moves those still pending into `Mearl`. Groups remain expanded if users view other grouped pages or the window has no other visible page.
|
|
97
174
|
|
|
98
|
-
|
|
175
|
+
Session release affects only that session and keeps pages/environments by default. `closeCreatedTabs` closes only created pages; `keepTabIds` retains results. Reused user pages always remain. `preserveEnvironment:false` clears those pages' environment. Active sessions block browser-wide release/close.
|
|
99
176
|
|
|
100
|
-
|
|
177
|
+
`page_download` listens before clicking and returns a browser artifact. CLI `--output` or SDK `saveArtifact(artifact, absolutePath, { session })` exports in 256 KiB chunks. `page_upload.files` accepts caller absolute `{filePath}` or browser `{artifactId}`; `filePaths` remains browser-host paths. Files are limited to 256 MiB. Caller-saved outputs are independent of temporary artifacts. Session release cleans temporary artifacts; `keepArtifactIds` retains selected ones. Sessionless artifacts expire after one idle hour; host exit clears staging.
|
|
101
178
|
|
|
102
|
-
|
|
179
|
+
Extension downloads require matching page referrers or an explicit expected `url`; unowned downloads are not guessed from recent files. CDP uses temporary directories only for managed browsers; shared browsers retain defaults and fail explicitly if Chrome provides no completed path. Timeouts may follow triggered downloads: inspect state before continuing. Session/download adapters support Extension/CDP; external action-handling Providers reject unsupported capabilities explicitly.
|
|
103
180
|
|
|
104
|
-
|
|
105
|
-
|
|
181
|
+
### External browser Providers
|
|
182
|
+
|
|
183
|
+
Provider browsers appear beside Extension/CDP browsers in `browser_list` and use the same
|
|
184
|
+
global `browserId` routing. `@mearl/setup` manages installation, updates, and removal:
|
|
106
185
|
|
|
107
186
|
```bash
|
|
108
187
|
npx @mearl/setup provider install @example/mearl-provider-device
|
|
109
188
|
|
|
110
|
-
#
|
|
189
|
+
# Inspect this Provider version's capabilities, arguments, and workflow
|
|
111
190
|
mearl example-device --help
|
|
112
191
|
|
|
113
|
-
# Provider
|
|
192
|
+
# Provider launch arguments use providerOptions
|
|
114
193
|
mearl browser_launch --payload '{"provider":"example-device","providerOptions":{}}'
|
|
115
194
|
mearl browser_list
|
|
116
195
|
|
|
117
|
-
#
|
|
196
|
+
# Use global Browser IDs returned by browser_list for later operations
|
|
118
197
|
mearl tab_list --browser '<browserId>'
|
|
119
198
|
mearl page_snapshot --payload '{"tabId":12345}' --browser '<browserId>'
|
|
120
199
|
|
|
@@ -122,58 +201,62 @@ npx @mearl/setup provider update brow
|
|
|
122
201
|
npx @mearl/setup provider uninstall brow
|
|
123
202
|
```
|
|
124
203
|
|
|
125
|
-
`
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
204
|
+
Creating a `pairing` instance with `browser_launch` returns `pairing.url` and an optional pairing code. Agents should render the URL directly as
|
|
205
|
+
a QR code, then confirm the same Browser ID becomes `connected` before page operations. Until the device connects,
|
|
206
|
+
it cannot become the default target. Use `browser_close` to delete the Provider instance. Each Provider
|
|
207
|
+
receives only explicitly supported actions; screenshot support distinguishes native captures, reconstructed images, and unsupported.
|
|
129
208
|
|
|
130
|
-
|
|
131
|
-
|
|
209
|
+
Unknown or misspelled actions return up to three candidates and examples based on available commands/common aliases,
|
|
210
|
+
without connecting to browsers or executing suggestions. For example, `mearl tab new` prefers `mearl tab_open`.
|
|
132
211
|
|
|
133
|
-
|
|
212
|
+
**Common options:**
|
|
134
213
|
|
|
135
|
-
|
|
|
214
|
+
| Option | Description |
|
|
136
215
|
| ------------------------ | ------------------------ |
|
|
137
|
-
| `--payload <json>`
|
|
138
|
-
| `--payload-file <path>`
|
|
139
|
-
| `--timeout <seconds>`
|
|
140
|
-
| `--compact`
|
|
141
|
-
| `--output <path>`
|
|
142
|
-
| `--browser <id
|
|
143
|
-
|
|
144
|
-
CLI
|
|
145
|
-
|
|
146
|
-
`browser_control`
|
|
147
|
-
stdout
|
|
148
|
-
|
|
149
|
-
`get_requests`
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
`
|
|
155
|
-
|
|
156
|
-
|
|
216
|
+
| `--payload <json>` | JSON arguments |
|
|
217
|
+
| `--payload-file <path>` | Read JSON from a file |
|
|
218
|
+
| `--timeout <seconds>` | Request timeout |
|
|
219
|
+
| `--compact` | Force compact stdout |
|
|
220
|
+
| `--output <path>` | Save output, such as screenshots |
|
|
221
|
+
| `--browser <id\|name>` | Target browser |
|
|
222
|
+
|
|
223
|
+
CLI, SDK, and MCP share return structures. Snapshot `@eN` refs are directly actionable; internal mappings remain runtime-local.
|
|
224
|
+
Ordinary `session` includes session ID, browser, transport, state, and generation. Query tabs with `tab_list`;
|
|
225
|
+
`browser_control` handoff also returns session `tabs`. `run_actions` steps preserve individual action results.
|
|
226
|
+
stdout defaults to compact JSON in pipes/redirection and pretty output in interactive terminals. `--compact` forces compact layout without changing values. Snapshots collapse unnamed, stateless groups without refs while preserving control states and text.
|
|
227
|
+
|
|
228
|
+
With nonempty `fields`, `get_requests` omits request/response bodies by default, returning extracted fields and metadata;
|
|
229
|
+
pass `includeBody:true` for full bodies too. Omitted bodies exclude `postData` / `responseBody`;
|
|
230
|
+
without field selection, bodies are returned by default.
|
|
231
|
+
|
|
232
|
+
`send_request` includes ordinary Cookies matching the full target URL and CHIPS Cookies for its first-party site. For example, `https://app.example.com/` uses the `https://example.com` partition independently of open pages. Sites use schemes and the public suffix list including private suffixes, excluding other sites/schemes, cross-site ancestors, and opaque partitions. Same-name Cookies on different paths remain; parent-site host-only Cookies are not added. Third-party partitions embedded elsewhere, page signatures, or complete page identities require requests through the target page's `page_eval`.
|
|
233
|
+
Response `Set-Cookie` updates the original browser for later calls; `withCookies:false` disables both automatic inclusion and writeback. Chrome handles extension response Cookies. CDP Node requests write back through the original browser connection before returning, supporting HttpOnly, default paths, expiry, and deletion. CDP responses with `Set-Cookie` include `cookieSync: { updatedCount, rejectedCount, failedCount }` without values. Partitioned Cookies with unknown partitions count as rejected. Sync failures cannot undo completed HTTP operations: inspect state rather than resending business requests. Ordinary/streaming Protocol requests use the same refresh mechanism.
|
|
234
|
+
Extension temporary credentials match only the original full request URL; Chrome selects redirect Cookies for the new URL. CDP Node requests, including Protocol streams, do not automatically follow redirects, preventing original Cookies/signatures from reaching other addresses.
|
|
235
|
+
|
|
236
|
+
Mearl aggregates local and configured cloud-server browsers by default, routing automatically with global
|
|
237
|
+
`browserId` from `browser_list`. The overrides below restrict hosts/connections or troubleshoot transport, so default help omits them:
|
|
238
|
+
|
|
239
|
+
| Option | Description |
|
|
157
240
|
| ------------------------ | ------------------------------------- |
|
|
158
|
-
| `--connector <id
|
|
159
|
-
| `--local`
|
|
160
|
-
| `--cdp`
|
|
161
|
-
| `--server <url>`
|
|
162
|
-
|
|
163
|
-
`browser_list --help`
|
|
164
|
-
`mearl check --help
|
|
165
|
-
client
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
`npx @mearl/setup update
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
client
|
|
172
|
-
`@mearl/setup update --yes --skip-skill`
|
|
173
|
-
|
|
174
|
-
`~/.mearl/cli-auto-update-state.json
|
|
175
|
-
|
|
176
|
-
|
|
241
|
+
| `--connector <id\|name>` | Restrict to one remote machine |
|
|
242
|
+
| `--local` | Current machine only |
|
|
243
|
+
| `--cdp` | Force local CDP; list only CDP browsers and imply `--local` |
|
|
244
|
+
| `--server <url>` | Override the automatically read cloud-server URL |
|
|
245
|
+
|
|
246
|
+
`browser_list --help` and `browser_launch --help` show scenario-specific host options. For connection/transport troubleshooting, use
|
|
247
|
+
`mearl check --help`. `mearl check` checks connection/browser status. `mearl check --updates` also concurrently queries
|
|
248
|
+
latest client, native-host, cloud-connector, and extension releases. Release queries wait about 1.5 seconds at most;
|
|
249
|
+
unreachable sources report unconfirmed updates without affecting browser checks. `--json` returns machine-readable results,
|
|
250
|
+
including updates when combined with `--updates`. Available updates show appropriate commands: client/native-host use
|
|
251
|
+
`npx @mearl/setup@beta update`; setup-managed extensions use `npx @mearl/setup extension`.
|
|
252
|
+
|
|
253
|
+
By default, globally installed `mearl` launches an independent background updater after the first use each day to query releases and compare
|
|
254
|
+
installed client, native-host, cloud-server, and MCP server versions. When needed, it invokes
|
|
255
|
+
`@mearl/setup update --yes --skip-skill` for outdated environments and their shared client, including standalone CLI installations.
|
|
256
|
+
The current command waits for neither network nor installation. Outcomes persist in
|
|
257
|
+
`~/.mearl/cli-auto-update-state.json`. Project dependencies and temporary `npx` copies are not modified automatically.
|
|
258
|
+
The browser extension retains its separate update entry.
|
|
259
|
+
Configure the interval or disable updates in `~/.mearl/config.json`:
|
|
177
260
|
|
|
178
261
|
```json
|
|
179
262
|
{ "cliAutoUpdate": { "intervalDays": 7 } }
|
|
@@ -183,14 +266,14 @@ client、native-host、cloud-server 和 MCP server 的已安装版本。发现
|
|
|
183
266
|
{ "cliAutoUpdate": false }
|
|
184
267
|
```
|
|
185
268
|
|
|
186
|
-
|
|
269
|
+
Intervals use local calendar days. Run `mearl check --updates` for immediate release checks.
|
|
187
270
|
|
|
188
|
-
## Skill
|
|
271
|
+
## Skill plugins
|
|
189
272
|
|
|
190
|
-
|
|
273
|
+
Install a Skill and automatically register commands, or register an existing entry:
|
|
191
274
|
|
|
192
275
|
```bash
|
|
193
|
-
npx @mearl/setup plugin install https://github.com/
|
|
276
|
+
npx @mearl/setup plugin install https://github.com/mearlhq/mearl --skill browser-tab-manager --yes
|
|
194
277
|
npx @mearl/setup plugin /absolute/path/to/browser-tab-manager
|
|
195
278
|
npx @mearl/setup plugin uninstall tabs
|
|
196
279
|
mearl tabs summary
|
|
@@ -199,28 +282,30 @@ mearl tabs --help
|
|
|
199
282
|
mearl tabs --version
|
|
200
283
|
```
|
|
201
284
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
285
|
+
If a plugin and Provider share a name, `mearl <name> --help` shows Provider launch/lifecycle guidance first,
|
|
286
|
+
then appends registered plugin commands. `mearl <name> <command> --help` retains detailed command help.
|
|
287
|
+
Providers/plugins install, update, and uninstall independently. Help aggregation starts no Providers and executes no business commands.
|
|
288
|
+
|
|
289
|
+
Directories default to `scripts/main.mjs` or `scripts/main.py`, preferring JavaScript if both exist. JavaScript default-exports `register(app)`; Python exports a `register(app)` function. Both may declare short `name`/`description` metadata and use `app.command(signature, handler, description?)`
|
|
290
|
+
to register actions, `app.invoke(action, payload, options?)` for current-browser context, and `app.progress(message)` for progress. JS may pass `{ message, data }` with JSON-serializable stage/object metadata for tools; CLI shows only `message`. Python `app.invoke` is synchronous; handlers may be ordinary functions or `async def`. Python requires `python3 >= 3.9`, optionally selected by `MEARL_PYTHON`; Mearl neither installs Python nor runs pip. Cross-plugin payloads use `{ command, input }`, inheriting host options and rejecting cycles. CLI prints final results only unless
|
|
291
|
+
`--verbose` writes progress to stderr. Handlers return text/JSON; hosts manage `--output`, connections, and errors. User-invoked writes execute directly; business modules validate targets, state, idempotency, and outcomes.
|
|
292
|
+
Names prefer explicit registration, then entry `name`, then Skill directory. Normal registration needs only a path.
|
|
293
|
+
setup supplies missing client/native-host versions or upgrades those older than itself. Its Skills installer handles arguments using global shared installation.
|
|
205
294
|
|
|
206
|
-
|
|
207
|
-
注册动作、`app.invoke(action, payload, options?)` 复用当前浏览器上下文,并用 `app.progress(message)` 报告可选进度。JavaScript 插件还可传入 `{ message, data }`,让工具页通过可 JSON 序列化的 `data` 获取稳定的阶段、对象 ID 等机器信息;CLI 仍只显示 `message`。Python 的 `app.invoke` 是同步调用,handler 可以是普通函数或 `async def`。Python 插件要求 `python3 >= 3.9`,可用 `MEARL_PYTHON` 指定解释器路径;Mearl 不安装 Python 或执行 `pip install`。调用另一个插件时,payload 使用 `{ command, input }` envelope;嵌套调用继承宿主选项并拒绝循环依赖。CLI 默认只输出最终结果,传入
|
|
208
|
-
`--verbose` 时才把进度写入 stderr。handler 返回文本或 JSON,宿主统一处理 `--output`、连接和错误。写命令在用户调用后直接执行,业务模块负责目标、状态、幂等和结果校验。
|
|
209
|
-
注册名优先使用显式名称,其次读取入口的 `name` metadata,最后回退到 skill 目录名;常规注册只传路径。
|
|
210
|
-
setup 会补齐缺失或低于自身版本的 client、native-host;安装参数由 setup 的 Skills 安装器处理,并固定全局共享安装。
|
|
295
|
+
JavaScript entries may export `setup({ runCommand })` to prepare Skill-owned dependencies. Both setup installation paths await this hook before registration; failures stop registration. Help, entry loading and ordinary calls do not execute it. Skills check their own dependencies on first use. Runtime code and resources belong inside the Skill.
|
|
211
296
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
297
|
+
For isolated checks, run `mearl <name> --version`. It resolves registration and loads the entry without browser connections;
|
|
298
|
+
exit 0 means registered/loadable. stdout shows the adjacent `SKILL.md` version or `unknown` without metadata.
|
|
299
|
+
Missing registration/entry or loading errors exit 2 with `PLUGIN_*`. Ordinary calls can handle these directly without a precheck.
|
|
215
300
|
|
|
216
|
-
|
|
217
|
-
`--name=value
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
301
|
+
Plugins accept positional arguments, string business options, or `--payload` with command/input. Prefer
|
|
302
|
+
`--name=value`; `--name value` is also supported. Fields match handler input independent of order. One field cannot use both
|
|
303
|
+
positional and business options; `--payload` cannot mix with either. JSON preserves field types. File/body inputs follow each
|
|
304
|
+
Skill's contract. Host options such as `browser`, `timeout`, and `output` keep their meaning. Same-name business fields, numbers,
|
|
305
|
+
booleans, objects, and arrays use `--payload`. Plugins do not use built-in actions' `--payload-file` entry.
|
|
306
|
+
Business option names begin with a letter and contain letters, digits, or underscores, preserving underscores.
|
|
222
307
|
|
|
223
|
-
|
|
308
|
+
Registered plugins are also SDK-callable; instance `client.invokePlugin` reuses connections/default browsers:
|
|
224
309
|
|
|
225
310
|
```typescript
|
|
226
311
|
import { invokePlugin } from '@mearl/client';
|
|
@@ -232,16 +317,16 @@ const result = await invokePlugin(
|
|
|
232
317
|
);
|
|
233
318
|
```
|
|
234
319
|
|
|
235
|
-
MCP
|
|
320
|
+
MCP uses fixed `plugin_invoke` with `plugin`, `command`, and `input`. SDK/MCP use registered plugins. The installation-host-managed catalog may trigger setup matching the client version and one retry; other unregistered names return `PLUGIN_NOT_REGISTERED`.
|
|
236
321
|
|
|
237
|
-
|
|
322
|
+
Long commands use auto-starting local persistent task services isolated by registry directory. CLI/SDK/MCP/toolbox share records; caller exit does not cancel execution. Restart marks unfinished work `interrupted` without replay. Background tasks pin accepted source snapshots, cwd, and environment. Bundle third-party JS dependencies into Skills and keep state outside source directories. Snapshots pin source/relative resources without pre-resolving JS dependencies; executors report missing dependencies/syntax errors on load.
|
|
238
323
|
|
|
239
324
|
```ts
|
|
240
325
|
import { PluginTaskClient } from '@mearl/client';
|
|
241
326
|
|
|
242
327
|
const tasks = new PluginTaskClient();
|
|
243
328
|
try {
|
|
244
|
-
const accepted = await tasks.start('example', { command: '
|
|
329
|
+
const accepted = await tasks.start('example', { command: 'search', input: {} }, {
|
|
245
330
|
executionTimeoutMs: 120000,
|
|
246
331
|
idempotencyKey: 'document-123',
|
|
247
332
|
});
|
|
@@ -252,37 +337,39 @@ try {
|
|
|
252
337
|
}
|
|
253
338
|
```
|
|
254
339
|
|
|
255
|
-
`wait`
|
|
340
|
+
`wait` timeout or signal abort ends waiting only; `cancel(taskId)` cancels execution. Browser tasks require explicit `browser`, resolved to fixed IDs before acceptance. `get/list` return snapshots/result references; `list` has bounded pagination/`nextCursor`; `events` provides cursors, gaps, and snapshots; `subscribe` wraps long polling. `result(taskId)` losslessly reads and verifies chunks up to 64 MiB. Terminal records/results remain seven days.
|
|
341
|
+
|
|
342
|
+
Handshakes and `tasks.status()` return `version/buildId`; build IDs identify running code, while protocol versions determine compatibility. With matching protocols, different/missing version/build IDs do not interrupt tasks, models, pages, or state. To switch builds, confirm no active tasks/page operations, call `tasks.stopHost()`, and let the next business call start the current build. Reregistration does not restart services. After local client/host changes, root `pnpm build` generates matching fingerprints and both artifacts; `tsc --watch` alone does not.
|
|
256
343
|
|
|
257
|
-
|
|
344
|
+
SDK `PluginTaskClient` and toolbox `host.task.*` expose tasks. Plugins provide business commands through `mearl <plugin> <command>` or MCP `plugin_invoke`; there are no separate global task/model/state/page/diagnostic CLI/MCP tools. Toolbox-only plugins are absent from CLI lists; invoking their name shows where to open the tool. Tool pages use `window.mearl.waitTask(taskId)`, `readTaskResult(taskId)`, and `listTasks()` only for their own toolbox tasks.
|
|
258
345
|
|
|
259
|
-
`tasks.diagnose({ taskId?, plugin?, instanceId?, includeErrorMessages?, includeLocalPaths? })`
|
|
346
|
+
`tasks.diagnose({ taskId?, plugin?, instanceId?, includeErrorMessages?, includeLocalPaths? })` reads bounded diagnostics within caller scope. Defaults exclude input, prompts, progress/checkpoint/result bodies, full URLs, environment, credentials, errors, and local paths. Error messages/paths may be explicitly included. coverage/history gaps describe collection and retention limits.
|
|
260
347
|
|
|
261
|
-
|
|
262
|
-
`plugin uninstall <name>`
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
`PLUGIN_NOT_REGISTERED`
|
|
266
|
-
|
|
267
|
-
|
|
348
|
+
Records at `~/.mearl/plugins/<name>.json` save entry paths/optional descriptions. In-place business-code edits apply directly; path/description changes require registration again.
|
|
349
|
+
`plugin uninstall <name>` globally removes Skills under `~/.agents/skills` through the Skills installer,
|
|
350
|
+
then clears registrations, including tracking cleanup when entry directories were manually deleted.
|
|
351
|
+
Manual paths unregister without source deletion.
|
|
352
|
+
`PLUGIN_NOT_REGISTERED` means no registration. `PLUGIN_ENTRY_MISSING` shows the stale path and a cleanup
|
|
353
|
+
command with the actual plugin name. Other failures retain their specific cause.
|
|
354
|
+
The following sections describe toolbox, page, state, and task contracts.
|
|
268
355
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
356
|
+
Plugins may export `toolbox`, appearing in extension Popup after registration. Resources live within the Skill directory. Registration
|
|
357
|
+
inlines local CSS, JavaScript, and images referenced by entry HTML into an immutable page bundle, without HTTP services
|
|
358
|
+
or requiring builds for ordinary HTML/CSS/JS pages.
|
|
272
359
|
|
|
273
|
-
|
|
274
|
-
`SKILL.md`
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
360
|
+
Right-click tools to enable/disable their Skills individually. Disabled status appears beside titles; tool pages/commands remain usable. Disabling renames
|
|
361
|
+
`SKILL.md` to `SKILL.md.mearl-disabled`, restored on enablement, affecting every Agent sharing that directory.
|
|
362
|
+
Symlink installs affect source directories. Existing sessions may retain loaded Skills until Agent restart/new sessions.
|
|
363
|
+
Toolbox updates/reinstalls preserve disabled state; external installers do not. Duplicate manifests require conflict resolution first.
|
|
364
|
+
Independent copies of same-name Skills disable separately. Plugins without Skill manifests show no toggle.
|
|
278
365
|
|
|
279
|
-
|
|
366
|
+
Example toolbox metadata:
|
|
280
367
|
|
|
281
368
|
```javascript
|
|
282
369
|
export const toolbox = {
|
|
283
370
|
version: 1,
|
|
284
|
-
title: '
|
|
285
|
-
description: '
|
|
371
|
+
title: 'Iteration Management',
|
|
372
|
+
description: 'Track changes and release status across repositories',
|
|
286
373
|
icon: 'git-branch',
|
|
287
374
|
locales: {
|
|
288
375
|
en: {
|
|
@@ -310,146 +397,146 @@ export default function register(app) {
|
|
|
310
397
|
}
|
|
311
398
|
```
|
|
312
399
|
|
|
313
|
-
`app.command(signature, handler, description?, examples?)`
|
|
400
|
+
`app.command(signature, handler, description?, examples?)` registers business commands for CLI, SDK, and Agent.
|
|
314
401
|
|
|
315
|
-
`toolbox.icon`
|
|
402
|
+
`toolbox.icon` supports the following strings, shared by tool lists, switch menus, and website catalogs:
|
|
316
403
|
|
|
317
404
|
```js
|
|
318
|
-
icon: 'git-branch' //
|
|
319
|
-
icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 4h16v16H4z"/></svg>' //
|
|
405
|
+
icon: 'git-branch' // Built-in icon, at most 40 characters, follows theme
|
|
406
|
+
icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 4h16v16H4z"/></svg>' // Monochrome SVG follows theme and interaction
|
|
320
407
|
icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="#2563eb" d="M4 4h16v16H4z"/></svg>'
|
|
321
|
-
icon: 'https://example.com/tool-icon.svg' // HTTP(S)
|
|
408
|
+
icon: 'https://example.com/tool-icon.svg' // HTTP(S) image URL, including SVG and PNG
|
|
322
409
|
icon: 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%2F%3E'
|
|
323
410
|
```
|
|
324
411
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
`app.toolboxCommand(signature, handler, description?, examples?)`
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
Python
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
Agent
|
|
337
|
-
18rem
|
|
338
|
-
`inline`
|
|
339
|
-
`key
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
developer instructions
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
`window.mearl.invoke(command, input?)`
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
Preact
|
|
351
|
-
`window.mearl.ui.version`
|
|
352
|
-
|
|
353
|
-
`--mearl-text-primary
|
|
354
|
-
`--mearl-accent
|
|
355
|
-
`--mearl-action-primary-hover
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
Node
|
|
362
|
-
|
|
363
|
-
##
|
|
364
|
-
|
|
365
|
-
|
|
|
412
|
+
Icon strings allow 32768 characters. SVG using `currentColor` renders as a monochrome mask, inheriting built-in theme/hover/selection colors; prefer `fill="none" stroke="currentColor"` for outlines. Explicitly colored SVGs, multicolor data URLs, and remote images retain colors. SVG never injects into extension DOM. Remote images omit referrers; credentialed URLs are rejected. Unknown names/load failures show generic icons. Relative file paths are unsupported.
|
|
413
|
+
|
|
414
|
+
`app.toolboxCommand(signature, handler, description?, examples?)` registers tool-page-only commands with the same parameter/handler contract;
|
|
415
|
+
they do not appear in CLI help and cannot be called by CLI (including JSON), SDK, MCP, or cross-plugin `app.invoke`.
|
|
416
|
+
Tool pages use `window.mearl.invoke(command, input)` or `window.mearl.invoke('host.task.start', { command, input })`. Both command types must be explicitly listed in `toolbox.page.commands`.
|
|
417
|
+
Registered toolboxCommands absent from that allowlist fail plugin loading. Use them for chunked uploads/reads and temporary page-resource release;
|
|
418
|
+
use `app.command` for complete operations independently useful to Agents, such as queries, import, compression, or comparison.
|
|
419
|
+
Python also supports `app.toolboxCommand(...)` and `@app.toolboxCommand(..., description="...")` decorators.
|
|
420
|
+
|
|
421
|
+
Declaring `agent` lets tools delegate tasks to the conversational Agent. `layout` defaults to `drawer`, with a host-provided top entry.
|
|
422
|
+
Pages may select `drawer` / `workspace` / `inline` per interaction through `setAgentPanelVisible` or `runAgentTask`.
|
|
423
|
+
Agent conversations persist in Codex history. Workbenches with a fixed
|
|
424
|
+
18rem left navigation can default to `workspace`, switch Agent through navigation, and fill the remaining main area; detail pages can still open right drawers.
|
|
425
|
+
`inline` embeds the Agent in a card/section, requiring an `anchor` element and stable
|
|
426
|
+
`key`. Hosts track anchor scrolling/resizing. `key` also isolates conversations and drafts by business object in drawer/workspace layouts;
|
|
427
|
+
`setAgentPanelVisible` may pass absolute `cwd` to bind newly created conversations to a directory.
|
|
428
|
+
`context` supplies background information without showing it as a chat message. On the first user message and session creation,
|
|
429
|
+
it is delivered as developer instructions.
|
|
430
|
+
|
|
431
|
+
`await window.mearl.ready()` returns `{ locale, theme, title, fontSize }`. Use
|
|
432
|
+
`window.mearl.invoke(command, input?)` for same-plugin allowlisted commands. Pages run in sandbox iframes without extension
|
|
433
|
+
APIs or network access by default. Native Host validates identity, command allowlists, and message size. Page bundles use
|
|
434
|
+
content-hash caches and chunked transfer without increasing Popup startup cost. Module scripts must first bundle into one file without
|
|
435
|
+
`import`. React/Vue projects may use built `index.html` as `entry`; registration performs final packaging.
|
|
436
|
+
For build-free components/state, declare `page.runtime: 'preact'`. After integrity checks, extensions inject pinned
|
|
437
|
+
Preact, Hooks, and HTM. Read `html`, `render`, `useState`, etc. from `window.mearl.ui`.
|
|
438
|
+
`window.mearl.ui.version` is diagnostic only; plugins cannot select runtime versions.
|
|
439
|
+
Hosts synchronize theme/font size and inject semantic variables including `--mearl-bg-primary`, `--mearl-bg-secondary`,
|
|
440
|
+
`--mearl-text-primary`, `--mearl-text-secondary`, `--mearl-border`, `--mearl-bg-hover`, and
|
|
441
|
+
`--mearl-accent`. Primary buttons use `--mearl-action-primary`,
|
|
442
|
+
`--mearl-action-primary-hover`, and `--mearl-action-primary-text` to match extension controls.
|
|
443
|
+
|
|
444
|
+
Toolboxes serve people; CLI serves Agents. Reuse business operations and consistent results without requiring shared intermediate state. Drafts, selections, previews, and other UI state default to browser memory. Use browser storage only for concrete refresh/reopen recovery needs. Sandboxes cannot assume localStorage, IndexedDB, or chrome.storage; use host capabilities. Node state is for business records, tasks continuing after close, safe retry receipts, or message-limited resource staging, with explicit lifetimes/cleanup.
|
|
445
|
+
|
|
446
|
+
Skill plugins can provide custom requests/data processing. CLI uses `mearl <plugin> <command>`; plugins reuse operations with `app.invoke(plugin, { command, input })`. Skill contracts define names, authentication, fields, and uploads.
|
|
447
|
+
|
|
448
|
+
Node plugins execute on the CLI/SDK/MCP Server host, never forwarded with browsers/connectors. File paths belong to that host. Browser operations require explicit targets. Installation hosts may provide on-demand installation through capability catalogs.
|
|
449
|
+
|
|
450
|
+
## Supported actions
|
|
451
|
+
|
|
452
|
+
| Category | Actions |
|
|
366
453
|
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
|
367
|
-
| API
|
|
368
|
-
|
|
|
369
|
-
|
|
|
370
|
-
|
|
|
371
|
-
|
|
|
372
|
-
|
|
|
373
|
-
|
|
|
374
|
-
|
|
|
375
|
-
|
|
|
376
|
-
|
|
|
454
|
+
| API debugging | `tab_checkpoint` `get_requests` `get_logs` `get_events` |
|
|
455
|
+
| Mocks and rules | `set_mock` `get_mocks` `set_rule` `get_rules` |
|
|
456
|
+
| Network requests | `send_request` `request_permission` |
|
|
457
|
+
| Tabs | `tab_open` `tab_list` `tab_close` |
|
|
458
|
+
| Page observation | `page_snapshot` `page_inspect` `page_screenshot` `page_frames` |
|
|
459
|
+
| Page actions | `page_click` `page_drag` `page_type` `page_hover` `page_scroll` `page_press` `page_wait` `page_navigate` `page_upload` `page_eval` |
|
|
460
|
+
| Page runtimes | `page_runtime` (internal document adapter; plugins use `app.page`) |
|
|
461
|
+
| Composition | `run_actions` |
|
|
462
|
+
| Environment and Cookies | `set_device_emulation` `set_app_profile` `set_timezone` `get_cookie` `set_cookie` |
|
|
463
|
+
| Browsers | `browser_list` `browser_launch` `browser_release` `browser_close` |
|
|
377
464
|
|
|
378
|
-
|
|
465
|
+
Interactive actions (`page_click` / `page_drag` / `page_type` / `page_hover` / `page_scroll` / `page_press` / `page_upload`) wait for asynchronous stability by default and return `{ action, observation }`. Pre-dispatch argument/ref/target failures return `action.stage: "precondition"`, omitting meaningless observation/diagnostics. Potentially dispatched input with confirmation timeout returns `action.stage: "dispatch-uncertain"` and observations for reconciliation. Known targets, hits, coordinates, dispatch modes, and input sequences appear in `action.attempt` as diagnostic evidence, not proof of effect. CLI failures exit 1. `observe: false` performs bare actions; `diagnostics: true` collects new error logs/business requests during the action, with analytics optionally enabled through `diagnostics.events`. `page_eval` defaults to bare execution and permits observation/diagnostics.
|
|
379
466
|
|
|
380
|
-
`tab_open active:true`
|
|
467
|
+
`tab_open active:true` requests activation. Extension do-not-disturb defaults on: HTTP(S) pages get background-focus emulation before first navigation without switching tabs/windows. Disabling it activates/restores windows. `activation.mode` distinguishes `background` / `foreground`; emulated visibilityState does not prove foreground. Handoff, release, and disconnect disable focus emulation regardless of preserveEnvironment. After return, reactivate the same URL with `reuse:"require", active:true` if needed. Sessionless tasks finish with browser_release. Pure CDP/external Providers follow their own activation support. Stability observation waits for bounded-duration CSS animations within budget. Selector/ref clicks first scroll targets clipped by nested containers, failing explicitly only if still clipped.
|
|
381
468
|
|
|
382
|
-
`page_click`
|
|
469
|
+
Default `page_click` auto uses DOM fallback on hidden pages, supporting selectors, text, refs, and coordinates and returning `dispatchMode: "dom"`, `fallbackReason: "page-hidden"`. Ordinary background tasks need no activation for clicks. Only sites rejecting untrusted events require visible pages and forced `mouse` / `touch`.
|
|
383
470
|
|
|
384
|
-
`observation.effects.interactives`
|
|
471
|
+
`observation.effects.interactives` marks controls `recreated` when frameworks replace DOM nodes without content changes. It retains selectors/refs/semantics but omits unchanged values/states. Actual value/state changes still return full differences.
|
|
385
472
|
|
|
386
|
-
`observation.effects.texts`
|
|
473
|
+
Optional `observation.effects.texts` returns current visible leaf text as `{ selector, text }`, including counters/amounts outside controls. Limits: eight entries, 160 characters each; repeated node changes retain final values. Nonempty text Range rectangles must be entirely within viewport/ancestor clipping and pass hit testing. CSS-masked text is excluded; empty text uses element boxes. These are neither interactive controls nor business-success signals. Complex/unreadable content and budget overflow retain snapshot fallback without changing navigation waits.
|
|
387
474
|
|
|
388
|
-
`page_press.pressMode`
|
|
475
|
+
`page_press.pressMode` accepts `auto` / `dom` / `keyboard`. Default auto uses DOM key events on hidden pages, reporting `dispatchMode`, `fallbackReason`, and simulated `defaultAction`. Use visible pages and keyboard for native editing, selection, or scrolling.
|
|
389
476
|
|
|
390
|
-
`page_snapshot`
|
|
477
|
+
`page_snapshot` defaults to full AX Tree. Use `mode: "viewport"` for long lists, `"interactive"` for viewport controls, or explicit `"dom"` when AX is empty/sparse. DOM returns rendered text, native controls, explicit roles, and high-confidence clickable nodes with actionable `@ref`, without inferring arbitrary business semantics. Scope with `rootSelector` or `rootRef` (optionally ancestorDepth), and search text/roles with query. interactive lacking AX control semantics falls back only to AX viewport with `fallbackMode: "viewport"`, never automatically switching sources. `maxNodes` / `maxChars` truncation preserves both beginning and end.
|
|
391
478
|
|
|
392
|
-
`page_inspect`
|
|
479
|
+
`page_inspect` uses CSS, snapshot `@ref`, or DevTools `$0` to return counts, bounding boxes, selected computed styles, center occlusion, horizontal/vertical overflow pixels, and nearest scroll containers. Omit selectors with `filter: "horizontal-overflow"` / `"vertical-overflow"` / `"scrollable"` for page-wide diagnosis. For text, first get `matches` / `matchCount` and refs through `page_snapshot.query`, then inspect refs without custom page_eval.
|
|
393
480
|
|
|
394
|
-
|
|
481
|
+
Disambiguate repeated text through `page_click.scope` CSS/ref subtrees. Extension coordinates in containers/iframes use `coordinateSpace: "active-frame"`; CSS/text queries accept frameId. Results distinguish requested semantics, resolved DOM, dispatch node, trusted hit, and coordinates through `requestedTarget`, `resolvedTarget`, `dispatchTarget`, `hitTarget`, and `coordinates`. Nested-clipped selector/ref targets scroll into view automatically; only remaining overflow clipping requires explicit handling. `page_scroll.containerPolicy: "nearest"` selects the nearest scrollable ancestor. Without selector, scrolling first chooses an inner container hit at representative viewport positions, then document scrolling or the topmost largest-visible container.
|
|
395
482
|
|
|
396
|
-
`browser_list`
|
|
397
|
-
`regular` / `managed
|
|
398
|
-
`stopped
|
|
399
|
-
|
|
400
|
-
`browser_list --cdp`
|
|
401
|
-
|
|
402
|
-
`check --cdp`
|
|
483
|
+
`browser_list` lists ordinary, Provider, and managed browsers. `type` distinguishes
|
|
484
|
+
`regular` / `managed`; `status` distinguishes `connected` / `pairing` / `running_disconnected` /
|
|
485
|
+
`stopped`. Only connected browsers are ordinary operation targets. Without a connected local extension browser,
|
|
486
|
+
browser_list automatically probes default CDP, even with Provider pairing records, without requiring --cdp.
|
|
487
|
+
`browser_list --cdp` actively probes if no ordinary CDP browser is registered and returns CDP browsers only;
|
|
488
|
+
connected extension browsers do not prevent this probe. With `MEARL_SOCKET_PATH`, inventory requests use that instance Socket.
|
|
489
|
+
`check --cdp` likewise checks only those CDP browsers.
|
|
403
490
|
|
|
404
|
-
`browser_release`
|
|
405
|
-
debugger/CDP
|
|
406
|
-
|
|
407
|
-
`browser_list
|
|
408
|
-
`browserAccess.url`
|
|
491
|
+
Call `browser_release` only on explicit user requests to end debugging, detach, or clean session resources. It releases
|
|
492
|
+
debugger/CDP control and temporary session state while keeping browsers/tabs. Providers declare managed-instance launch, close, persistence,
|
|
493
|
+
access, and sign-in synchronization semantics; run `mearl <providerId>`. Access URLs are excluded from
|
|
494
|
+
`browser_list`; explicitly run `mearl check --browser <id|name>` when needed and treat returned
|
|
495
|
+
`browserAccess.url` as sensitive.
|
|
409
496
|
|
|
410
|
-
##
|
|
497
|
+
## Architecture
|
|
411
498
|
|
|
412
499
|
```
|
|
413
500
|
@mearl/client (CLI / SDK)
|
|
414
|
-
├─
|
|
415
|
-
├─
|
|
501
|
+
├─ Local → @mearl/native-host → Chrome Extension / CDP
|
|
502
|
+
├─ Local → @mearl/provider runtime → External Provider
|
|
416
503
|
└─ WebSocket → @mearl/cloud-server → @mearl/cloud-connector
|
|
417
504
|
├─ @mearl/native-host → Chrome Extension / CDP
|
|
418
505
|
└─ @mearl/provider runtime → External Provider
|
|
419
506
|
```
|
|
420
507
|
|
|
421
|
-
|
|
508
|
+
Infrastructure must avoid recursive routing: `@mearl/cloud-connector` directly connects to local native-host through `@mearl/client/local`. Ordinary Agent, CLI, and MCP integrations use the package root.
|
|
422
509
|
|
|
423
|
-
|
|
510
|
+
Plugin code is organized by responsibility in `src/plugins/`:
|
|
424
511
|
|
|
425
|
-
|
|
|
512
|
+
| Directory | Responsibility |
|
|
426
513
|
| --- | --- |
|
|
427
|
-
| `sdk/` |
|
|
428
|
-
| `clients/` |
|
|
429
|
-
| `runtime/` |
|
|
430
|
-
|
|
|
514
|
+
| `sdk/` | Plugin declarations, command interfaces, and page/model/state/recovery validation |
|
|
515
|
+
| `clients/` | Service connections and task/model/page/state clients |
|
|
516
|
+
| `runtime/` | Service assembly, scheduling, storage, snapshots, executors, and cleanup |
|
|
517
|
+
| Plugin directory root | Registration, resource packaging, official plugin installation, and shared client/server protocol |
|
|
431
518
|
|
|
432
|
-
|
|
519
|
+
Tests live in nearby `__tests__/`. Public exports use `@mearl/client` and `@mearl/client/plugin`; root `plugin.ts` is the public entry. Process entries `plugin-worker.ts`, `plugin-task-host.ts`, and `pluginModelSessionWorker.ts` remain in the `src/` root. `runtimePaths.ts` locates package versions and entries consistently for per-file compilation and Native Host bundling. `browser-core` still synchronizes generated protocol into `src/generated/`.
|
|
433
520
|
|
|
434
|
-
##
|
|
521
|
+
## Build
|
|
435
522
|
|
|
436
523
|
```bash
|
|
437
|
-
pnpm build # tsc
|
|
524
|
+
pnpm build # Compile with tsc into dist/ and make cli.js executable
|
|
438
525
|
pnpm dev # tsc --watch
|
|
439
|
-
pnpm typecheck #
|
|
526
|
+
pnpm typecheck # Type checking only
|
|
440
527
|
```
|
|
441
528
|
|
|
442
529
|
## License
|
|
443
530
|
|
|
444
531
|
Apache-2.0
|
|
445
532
|
|
|
446
|
-
###
|
|
533
|
+
### Plugin page instances
|
|
447
534
|
|
|
448
|
-
`PluginPageClient`
|
|
535
|
+
`PluginPageClient` manages attach/get/list/send/detach/events/activation through local plugin services. Plugins declare independent `pageRuntime` and use `app.page()`. Hosts syntax-check code expressions with Node's compiler without executing them. Browser evaluation must produce self-contained functions; nonfunctions/external-reference errors appear at page runtime. Extension/pure CDP share instances, events, activation, and document runtimes. documentId binds instances; same-plugin/same-document entries share initialization. Navigation invalidates instances; activation rules rebuild them. `frame` accepts `main`, `business`, or `page_frames` IDs (numeric Extension, string CDP). External Providers must declare `page_runtime`.
|
|
449
536
|
|
|
450
|
-
|
|
537
|
+
Explicit manual `attach` reusing an automatic instance changes ownership to manual while preserving initialization and running tasks. Later narrowing automatic scopes does not remove it.
|
|
451
538
|
|
|
452
|
-
|
|
539
|
+
To change matching scope independently, pass `enabled: true, matchPatch: { add?: string[], remove?: string[] }`, mutually exclusive with `matches`. Hosts atomically add/remove scopes to avoid concurrent overwrites. Removing the final scope disables automatic activation while retaining manually attached instances. `persistence: 'persistent'` survives browser restarts. Initialization handlers can read current plugin preferences instead of copying volatile settings into rule input.
|
|
453
540
|
|
|
454
541
|
```typescript
|
|
455
542
|
const pages = new PluginPageClient();
|
|
@@ -459,13 +546,13 @@ try {
|
|
|
459
546
|
} finally { pages.disconnect(); }
|
|
460
547
|
```
|
|
461
548
|
|
|
462
|
-
|
|
549
|
+
Background events declare schemas and serial, latest-coalescing, or bounded-concurrency policies. app.runtimeCommand handlers use `context.page` for fixed documents. Document-bound tasks may read their plugin's activation rules with `app.page('activation')` but cannot modify them. Messages/results allow 24 MiB each with automatic chunks/checks; events allow 32 KiB. Toolbox uses `host.page.*`; UI history subscription is independent of execution. See [plugin host capabilities](../../docs/plugin-runtime.md#page-runtimes-and-events).
|
|
463
550
|
|
|
464
|
-
Python
|
|
551
|
+
Python exports the same `pageRuntime` dictionary, with `code` as browser-side JavaScript function strings. Register initialization/events through app.runtimeCommand or decorators. `app.page(operation, payload)`, `context.page.send(message)`, and `context.page.get()` are synchronous; the latter two require instance-bound handlers. JS/Python `context.page.send(message, {timeoutSec: 120})` sets per-response timeouts above 0 and at most 300 seconds (Python uses dictionaries). `app.page("send", {instanceId, message, timeoutSec})` and SDK `pages.send(plugin, instanceId, message, {timeoutSec})` also support it. Other requests are unaffected. Cancellation/detach still interrupts immediately; transport failures cancel the page request. Runtime-only commands remain hidden and inaccessible through CLI/toolbox; ordinary `app.command` event handlers remain publicly callable.
|
|
465
552
|
|
|
466
|
-
###
|
|
553
|
+
### Model tasks and declared state
|
|
467
554
|
|
|
468
|
-
`PluginModelClient`
|
|
555
|
+
`PluginModelClient` uses local Codex without browsers. Model/command tasks share querying, cancellation, and lossless results with separate scheduling. Query `capabilities()` first; only explicit read-only Agent mode is supported, and strictly tool-free generation fails.
|
|
469
556
|
|
|
470
557
|
```typescript
|
|
471
558
|
import { PluginModelClient, PluginStateClient } from '@mearl/client';
|
|
@@ -479,9 +566,9 @@ try {
|
|
|
479
566
|
} finally { models.disconnect(); }
|
|
480
567
|
```
|
|
481
568
|
|
|
482
|
-
`start`
|
|
569
|
+
`start` returns persistent taskId; `run` signals cancel execution and await cleanup. `app.model(request, { onProgress })` / `context.model(request, { onProgress })` subscribe to that call's `model.delta`, isolated across concurrent calls; Python uses `context.model(request, on_progress=callback)`. Incremental `data` contains `delta/index/partial` and optional `itemId/phase`. Isolate messages, skip commentary, and fall back to final results on sequence gaps. Deltas are temporary display only; final results come from successful turns' complete messages. outputSchema passes to Providers; hosts parse JSON; plugins validate structure/business constraints. Retract temporary output on failure; never cache it or infer success. Use `PluginModelClient`/context for catalogs/execution; toolbox uses `host.model.capabilities/list/start` and `waitTask`.
|
|
483
570
|
|
|
484
|
-
|
|
571
|
+
Declare collections in plugin entries, then access them from command contexts:
|
|
485
572
|
|
|
486
573
|
```javascript
|
|
487
574
|
export const stateStorage = { version: 1, collections: {
|
|
@@ -495,31 +582,31 @@ export default app => app.command('save', async (input, context) => {
|
|
|
495
582
|
});
|
|
496
583
|
```
|
|
497
584
|
|
|
498
|
-
SDK `PluginStateClient.get/getMany/list/transact`
|
|
585
|
+
SDK `PluginStateClient.get/getMany/list/transact` and toolbox `host.state.*` share collections. Writes require CAS; conflicts require reread/merge/retry. `schemaVersion` upgrades use explicit migrations. Browser-session/instance scopes support `cache` or `memory` with host-verified page identities. `memory` resides only in the execution host, sharing CAS/schema/TTL/chunk limits. Browser-session scope survives document refresh and isolates new sessions; host restart clears it. Host-wide memory allows 128 MiB/512 namespaces on demand; `maxBytes` per collection allows 128 MiB. Instance end releases memory. See [plugin host capabilities](../../docs/plugin-runtime.md#state-and-activation) for quotas/TTL. Binary assets still use files/resource channels.
|
|
499
586
|
|
|
500
|
-
###
|
|
587
|
+
### Explicit task recovery
|
|
501
588
|
|
|
502
|
-
|
|
589
|
+
Plugins declare `taskRecovery` with per-command checkpointVersion/schema and register `app.recoveryCommand(command, handler)`. `context.checkpoint(data, expectedSequence)` saves up to 64 KiB. Data, version, host schemaHash, sequence, and events atomically commit with tasks using CAS. Schemas establish identity/format compatibility; plugins validate checkpoint/migration structures.
|
|
503
590
|
|
|
504
|
-
`tasks.checkpoint(taskId)`
|
|
591
|
+
`tasks.checkpoint(taskId)` reads checkpoints. `tasks.resume(taskId, { environment?, revision? })` creates new attempts for terminal root commands, retaining old terminal tasks and original installation, snapshot, input, directory, and route. Default environment comes freshly from the caller; old environments are not persisted. Recovery handlers read `context.recovery` and check external state first. Hosts neither replay original handlers nor guarantee atomic external submissions/checkpoints.
|
|
505
592
|
|
|
506
|
-
|
|
593
|
+
Use `tasks.checkpoint(taskId)` / `tasks.resume(taskId)`. Only public/service roots qualify; models, children, page bindings, and caller routing reject recovery, and original trees must be confirmed stopped. Original code is the default; explicit `revision: 'current'` pins request-time snapshots. Same-version schemas must match. Cross-version targets declare `taskRecovery` `migrateFrom: [{ version, schema }]` and hidden `app.checkpointMigration(command, handler)`, returning target checkpoint data. Hosts verify historical schemaHash, forbid host/nested-plugin APIs during migration, and manage processes with 10-second deadlines. Conversion must be retryable and side-effect-free; trusted code is not an OS sandbox. Concurrent recovery coalesces into one conversion/successor; original tasks/data remain. See [checkpoints and explicit recovery](../../docs/plugin-runtime.md#checkpoints-and-explicit-recovery).
|
|
507
594
|
|
|
508
|
-
|
|
595
|
+
Plugin CLI failures return nonzero and stderr JSON `{ "error": { "code", "message" } }`, preserving SDK/MCP codes without arbitrary exception extras. `PLUGIN_TASK_WAIT_TIMEOUT` stops observation only; `PLUGIN_EXECUTION_CANCELLED` / `PLUGIN_EXECUTION_DEADLINE` indicate cancellation/deadline; `PLUGIN_PAGE_TARGET_CHANGED` / `PLUGIN_PAGE_INVALIDATED` require new instances; `PLUGIN_STATE_CONFLICT` requires fresh CAS reads; `PLUGIN_MODEL_CAPABILITY_UNSUPPORTED` means unsupported capabilities; `PLUGIN_INVOCATION_CYCLE` / `PLUGIN_INVOCATION_DEPTH` reject cycles/depth. Unconfirmed process-tree termination retains failure records and rejects recovery.
|
|
509
596
|
|
|
510
|
-
|
|
597
|
+
Explicit toolbox page attach requests missing site permissions and continues after user confirmation. Background page runtimes never prompt automatically.
|
|
511
598
|
|
|
512
|
-
|
|
599
|
+
Query models through SDK `PluginModelClient.list()` or toolbox `host.model.list`. Entries include supported `reasoningEfforts` and `defaultReasoningEffort` where available; UI restricts choices accordingly. Hosts coalesce discovery, immediately return existing catalogs, and refresh stale data in background. Failures retain usable catalogs with short backoff and create no inference sessions. Batch state reads use `get-many` and `keys` (SDK `getMany`, toolbox `host.state.getMany`) for up to 128 `keys` at one revision, including missing keys' CAS versions, limited to 1 MiB.
|
|
513
600
|
|
|
514
601
|
|
|
515
|
-
|
|
602
|
+
`PluginHost` assembles tasks, state, pages, and model catalogs with shutdown/diagnostics. `PluginTaskManager` receives explicit dependencies and owns execution trees; page/state services do not mutate schedulers. `PluginHostConnection` manages RPC, discovery, handshake, reconnection, and bridging. Share connections through Task/Model/State constructor `connection` options or Page's second constructor argument. Creators close injected connections; client `disconnect()` closes only owned connections. Connections bind one caller scope and cannot cross plugins, interaction channels, or sources.
|
|
516
603
|
|
|
517
|
-
|
|
604
|
+
Continuous background model calls may specify `conversation` (1–80 letters, digits, or `:_-`). Same-name reuse is limited to the current page instance or current host-managed command. Plugin, revision, model, instructions, environment, and ownership isolate sessions. Omission creates independent calls. Detach/command end releases conversations; cancel/failure/timeout destroys them. Idle expiry is five minutes; temporary sessions restart every 32 turns to bound history. Conversations are memory-only with no new global CLI/MCP commands.
|
|
518
605
|
|
|
519
|
-
##
|
|
606
|
+
## Managed plugin catalog
|
|
520
607
|
|
|
521
|
-
|
|
608
|
+
Installation hosts use client/plugin replaceOfficialPluginCatalog(revision, plugins) to save selected-preset catalogs. revision is the exact manifest digest; entries contain description, skill, installer installArgs, and optional setup grouping. Atomic replacement saves .official-catalog.json in the registry directory; catalogs default empty. Hosts own source/preset trust checks; catalogs alone do not install.
|
|
522
609
|
|
|
523
|
-
findOfficialPlugin/listOfficialPluginNames
|
|
610
|
+
findOfficialPlugin/listOfficialPluginNames reread current catalogs and reuse setup for missing plugins. readOfficialPluginCatalog reports corruption to installation status; ordinary plugin/browser commands ignore corrupt optional catalogs without affecting registered capabilities. Compatibility export OFFICIAL_PLUGINS reflects the most recently read catalog in the process.
|
|
524
611
|
|
|
525
|
-
|
|
612
|
+
Extension update checks default to config.json from GitHub's latest stable release. Distribution hosts may set MEARL_EXTENSION_CONFIG_URL to an endpoint returning version or latestVersion. Until extension metadata is uploaded, update data is unavailable; source versions are not published extension versions. Check failures affect notifications only.
|