@mearl/native-host 3.0.0-beta.0 → 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 +119 -168
- package/README.zh-CN.md +319 -0
- package/dist/THIRD_PARTY_NOTICES.txt +22 -655
- package/dist/agent/chat-visualization.d.ts +3 -0
- package/dist/agent/managed-programs.d.ts +24 -0
- package/dist/agent/manager.d.ts +15 -2
- package/dist/agent/skill-manager.d.ts +8 -1
- package/dist/app-authorization.d.ts +8 -0
- package/dist/app-profile-catalog.d.ts +3 -1
- package/dist/browser-enhancement-gateway.d.ts +24 -0
- package/dist/browser-identity.d.ts +11 -0
- package/dist/browser-registry.d.ts +1 -0
- package/dist/browser-socket-request.d.ts +4 -0
- package/dist/capability-contracts.d.ts +15 -52
- package/dist/capability-hooks.d.ts +42 -0
- package/dist/cdp-backend/buffers.d.ts +11 -11
- package/dist/cdp-backend/capability-handlers.d.ts +1 -0
- package/dist/cdp-backend/cdp-session.d.ts +2 -0
- package/dist/cdp-backend/cdp-utils.d.ts +3 -8
- package/dist/cdp-backend/handlers.d.ts +2 -1
- package/dist/cdp-backend/http-handlers.d.ts +12 -9
- package/dist/cdp-backend/network-control.d.ts +5 -0
- package/dist/cdp-backend/page-dialogs.d.ts +14 -0
- package/dist/cdp-backend/request-cookies.d.ts +8 -0
- package/dist/cdp-backend/response-cookies.d.ts +8 -0
- package/dist/cdp-backend/send-request.d.ts +3 -2
- package/dist/control-session-manager.d.ts +1 -1
- package/dist/index.js +182 -217
- package/dist/install.js +1 -1
- package/dist/native-capability-services.d.ts +5 -2
- package/dist/node-capabilities.d.ts +1 -0
- package/dist/node-capabilities.js +2 -2
- package/dist/page-runtime-store.d.ts +2 -27
- package/dist/plugin-task-host.js +30 -45
- package/dist/plugin-worker.js +23 -38
- package/dist/pluginModelSessionWorker.js +1 -1
- package/dist/preset-auto-update.d.ts +18 -0
- package/dist/preset-components.d.ts +3 -1
- package/dist/provider-app-resources.d.ts +32 -0
- package/dist/provider-control.d.ts +1 -1
- package/dist/provider-enhancements.d.ts +21 -0
- package/package.json +17 -10
- package/dist/alipay-auth-code.d.ts +0 -13
- package/dist/cdp-backend/mtop-environment.d.ts +0 -7
package/README.md
CHANGED
|
@@ -1,67 +1,71 @@
|
|
|
1
1
|
# @mearl/native-host
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[English](README.md) | [简体中文](README.zh-CN.md)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Mearl's Native Messaging Host bridges the Chrome extension and local socket services.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
The extension starts this process through `chrome.runtime.connectNative()`. Hosts interact with browsers through Extension or CDP and serve callers such as `@mearl/client` over local IPC: Unix sockets on macOS/Linux and named pipes on Windows. Cloud Connector uses the same host connection.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Dynamic capabilities
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Hosts provide browser control, device simulation, plugin execution, and default analytics parsing. Node capability packages supply declared hook handlers; see [Node capabilities](../../docs/node-capabilities.md) for resources, activation, and rollback. Setup and web installation share the [installation host](../../docs/preset-installation.md) coordinator.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
## Installation and registration
|
|
14
|
+
|
|
15
|
+
Register Native Messaging Host manifests so browsers can launch this process:
|
|
14
16
|
|
|
15
17
|
```bash
|
|
16
|
-
#
|
|
18
|
+
# Register both Skills and MCP integration modes (default)
|
|
17
19
|
mearl-native-host --init
|
|
18
20
|
|
|
19
|
-
#
|
|
21
|
+
# Register one mode only
|
|
20
22
|
mearl-native-host --init --mode skills
|
|
21
23
|
mearl-native-host --init --mode mcp
|
|
22
24
|
|
|
23
|
-
#
|
|
25
|
+
# Custom extension ID for development
|
|
24
26
|
mearl-native-host --init --extension-id <your-extension-id>
|
|
25
27
|
```
|
|
26
28
|
|
|
27
|
-
> Skills
|
|
29
|
+
> Skills and MCP hosts use the same binary and share one Unix socket, so both can be enabled.
|
|
28
30
|
|
|
29
|
-
|
|
31
|
+
You can also invoke the installer in code:
|
|
30
32
|
|
|
31
33
|
```typescript
|
|
32
34
|
import { installNativeHost } from '@mearl/native-host';
|
|
33
35
|
|
|
34
|
-
await installNativeHost(); //
|
|
36
|
+
await installNativeHost(); // Register both modes by default
|
|
35
37
|
```
|
|
36
38
|
|
|
37
|
-
|
|
39
|
+
The runtime entry, launched by browsers or manually, is exported through a subpath:
|
|
38
40
|
|
|
39
41
|
```typescript
|
|
40
42
|
import '@mearl/native-host/runtime';
|
|
41
43
|
```
|
|
42
44
|
|
|
43
|
-
## CLI
|
|
45
|
+
## CLI options
|
|
44
46
|
|
|
45
47
|
```bash
|
|
46
48
|
mearl-native-host [options]
|
|
47
49
|
|
|
48
|
-
--init [--mode <skills|mcp|both>] [--extension-id <id>]
|
|
49
|
-
--daemon
|
|
50
|
-
--cdp-port <port>
|
|
51
|
-
--cdp-user-data-dir <dir>
|
|
52
|
-
--cdp-endpoint-file <path>
|
|
53
|
-
--skip-browser-registration
|
|
54
|
-
--browser-id <id>
|
|
55
|
-
--browser-name <name>
|
|
56
|
-
--version, -v
|
|
57
|
-
--help, -h
|
|
50
|
+
--init [--mode <skills|mcp|both>] [--extension-id <id>] Register host manifests
|
|
51
|
+
--daemon Standalone CDP daemon
|
|
52
|
+
--cdp-port <port> CDP port
|
|
53
|
+
--cdp-user-data-dir <dir> Chrome profile
|
|
54
|
+
--cdp-endpoint-file <path> File containing private remote CDP WebSocket URL
|
|
55
|
+
--skip-browser-registration Do not expose Provider-private CDP as a separate browser
|
|
56
|
+
--browser-id <id> Browser registration ID
|
|
57
|
+
--browser-name <name> Browser display name
|
|
58
|
+
--version, -v Show version
|
|
59
|
+
--help, -h Show help
|
|
58
60
|
```
|
|
59
61
|
|
|
60
|
-
|
|
62
|
+
Daemon arguments apply only to the current process. Client-started discovery daemons first read the default Chrome profile's `DevToolsActivePort`, then probe local CDP port 9222. Custom ports/browser identities must be supplied on each manual startup. Discovery uses its own instance Socket rather than depending on ownership of a fixed Socket.
|
|
63
|
+
|
|
64
|
+
Chrome authorization mode enabled at `chrome://inspect/#remote-debugging` disables HTTP discovery. If `DevToolsActivePort` is missing/unreadable and `/json/version` returns 404, Mearl connects to `/devtools/browser` WebSocket on the same port and waits for Chrome authorization. Allow the browser prompt. This path reads no browser profile files. Failures retain discovery-file read errors to distinguish filesystem permissions, ports, and authorization issues.
|
|
61
65
|
|
|
62
|
-
|
|
66
|
+
## Architecture
|
|
63
67
|
|
|
64
|
-
|
|
68
|
+
On macOS, extension connections first inspect the Native Messaging host's direct parent application's bundle ID to distinguish EgoLite, Chrome, and Edge, including supported test channels. Results cache per host process. Identification does not guess from page UA, application directory names, or browser versions, so device/App simulation does not change names. Other systems, unknown applications, and read failures retain extension-reported names. Names support display/selection, not page association, ownership, or authorization.
|
|
65
69
|
|
|
66
70
|
```
|
|
67
71
|
Chrome Extension
|
|
@@ -71,48 +75,36 @@ Chrome Extension
|
|
|
71
75
|
@mearl/client / @mearl/cloud-connector
|
|
72
76
|
```
|
|
73
77
|
|
|
74
|
-
`browser_launch`
|
|
78
|
+
`browser_launch` starts a native-host child with independent CDP configuration for each managed Chrome, making concurrent headless/profile instances addressable in the browser registry. External Providers may reuse generic page actions through private remote CDP. Providers still own remote credentials, lifecycle, and file staging.
|
|
75
79
|
|
|
76
|
-
##
|
|
80
|
+
## Sidebar Agent Chat
|
|
77
81
|
|
|
78
|
-
|
|
82
|
+
The extension sidebar calls native-host through Native Messaging, then starts persistent Codex app-server or installed Agent-capability processes according to user selection. Providers support streaming messages, reasoning/tool progress, interruption, and approval, reusing CLI sign-in sessions.
|
|
79
83
|
|
|
80
|
-
|
|
84
|
+
Install and sign into a standalone Codex CLI or Codex App supporting `app-server`. native-host searches the installation-time Node executable directory, common global directories, version managers, `PATH`, and Codex App's bundled runtime, validates compatibility concurrently, and selects the newest semantic version. Automatic selection caches within the process; explicit paths always win:
|
|
81
85
|
|
|
82
86
|
```bash
|
|
83
87
|
MEARL_CODEX_PATH=/absolute/path/to/codex
|
|
84
88
|
```
|
|
85
89
|
|
|
86
|
-
Qoder
|
|
87
|
-
|
|
88
|
-
```bash
|
|
89
|
-
# macOS / Linux
|
|
90
|
-
curl -fsSL https://qoder.com/install | bash
|
|
91
|
-
qodercli
|
|
92
|
-
# 进入交互界面后输入 /login
|
|
93
|
-
|
|
94
|
-
# 可选:指定非标准安装位置
|
|
95
|
-
MEARL_QODER_PATH=/absolute/path/to/qodercli
|
|
96
|
-
```
|
|
90
|
+
The Agent Chat setup screen installs missing Codex or Qoder components through npm under `~/.mearl/agent-programs`. For Qoder, the local Agent adapter comes from [`@mearl/plugin-qoder`](../plugin-qoder/README.md). A Qoder adapter supplied by the selected preset takes precedence. The menu installation leaves the preset selection intact and enables the local Agent only.
|
|
97
91
|
|
|
98
|
-
|
|
92
|
+
## Plugin host capabilities
|
|
99
93
|
|
|
100
|
-
|
|
94
|
+
The plugin host manages commands, tasks, page instances, events, models, and state. Toolbox, CLI, SDK, MCP, and Agent are entry points; tool-page lifetime does not determine background capability lifetime. Protocols evolve with tools without legacy interface adapters.
|
|
101
95
|
|
|
102
|
-
|
|
96
|
+
### Ownership and identity
|
|
103
97
|
|
|
104
|
-
|
|
98
|
+
- Execution environments have persistent `hostId` and per-process `epoch`. hostId lives in the plugin registry directory and identifies environments without granting permissions.
|
|
99
|
+
- Each environment's user-level execution service owns tasks/executors. Browser Native Hosts adapt connections and targets. Browser targets and model execution locations are independently selected and pinned after launch, unaffected by default-browser changes.
|
|
100
|
+
- Commands have `invocationId`, source, plugin, and optional parent invocation. Trusted entries construct context; business input cannot replace it. Nested calls inherit host/source and receive new invocation IDs.
|
|
101
|
+
- Installation IDs, logical names, and immutable code revisions are separate. Tasks/page instances pin revisions; updates affect new execution only. Active work completes, drains, or stops by policy. Complete source snapshots include local dependencies; entry metadata cannot substitute for revisions.
|
|
105
102
|
|
|
106
|
-
|
|
107
|
-
- 最终由每个执行环境的用户级执行服务持有任务和执行器;浏览器 Native Host 负责连接与目标适配。浏览器目标与模型执行位置独立选择,启动后固定,不随默认浏览器变化。
|
|
108
|
-
- 每次命令拥有 `invocationId`、来源、插件及可选父调用。可信入口构造上下文,业务 input 无法替换。嵌套插件调用继承宿主和来源,产生新的调用 ID。
|
|
109
|
-
- 注册安装 ID、逻辑名称与不可变代码 revision 分开。任务和页面实例固定 revision;更新仅影响新执行,活动执行按完成、排空或停止策略处理。完整源码快照需要覆盖本地依赖,入口文件元数据不能代替代码 revision。
|
|
103
|
+
### Command executors
|
|
110
104
|
|
|
111
|
-
|
|
105
|
+
Handlers receive `(input, context)` with `identity`, `signal`, `invoke`, and `progress`, expiring after execution. JS plugins are trusted native code. Executor isolation enables scheduling and termination, not an OS permission sandbox.
|
|
112
106
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
`executeRegisteredPlugin` 为每次调用建立监督进程与业务子进程,Python 入口通过业务执行器转接到 Python 子进程。监督进程独立观察宿主连接,业务代码阻塞也不影响拥有者断线清理。浏览器与 Agent 调用由父宿主处理,工作目录和环境继承当前执行宿主。公开调用与工具页面命令白名单分别校验,来源标签不参与授权。Python 注册信息和执行终态均须经宿主 ACK 后才退出,宿主按进程 exit 结算并释放父端管道,后代继承 stdio 不阻塞完成;已确认终态后仍未退出的 Python 进程有 1 秒退出宽限,随后强制停止,最终仍须监督进程确认全树清理。
|
|
107
|
+
`executeRegisteredPlugin` creates a supervisor and business child for each call; Python entries bridge through the business executor to Python children. Supervisors independently watch host connections, so blocked business code cannot prevent owner-disconnect cleanup. Parent hosts handle browser/Agent calls. cwd/environment inherit from the execution host. Public commands and tool-page allowlists validate separately; source labels grant no authorization. Python registration and terminal results require host ACK before exit. Hosts settle on process exit and release parent pipes, so descendant-inherited stdio cannot block completion. Python processes surviving acknowledged terminal results get one second to exit before forced termination; supervisors must still confirm full-tree cleanup.
|
|
116
108
|
|
|
117
109
|
```typescript
|
|
118
110
|
await executeRegisteredPlugin('example', { command: 'read', input }, hostContext, {
|
|
@@ -122,27 +114,27 @@ await executeRegisteredPlugin('example', { command: 'read', input }, hostContext
|
|
|
122
114
|
});
|
|
123
115
|
```
|
|
124
116
|
|
|
125
|
-
|
|
117
|
+
Wait timeouts, execution deadlines, caller disconnects, and cancellation are separate. Cancellation notifies executors, then terminates after a grace period; stopped status requires confirmed exit. Already received successful results take precedence over later cancellation. Stops return pending host-action names for external reconciliation. Returning without awaiting host calls fails explicitly.
|
|
126
118
|
|
|
127
|
-
|
|
119
|
+
Executors retain process ownership after submitting results; parent hosts clean up after receipt: POSIX process groups are reaped, and Windows runs `taskkill /T` while supervisors remain alive. Independent supervisors handle owner disconnects. Unconfirmed cleanup reports `PLUGIN_EXECUTOR_CLEANUP_FAILED`. Local termination cannot undo operations submitted to external services.
|
|
128
120
|
|
|
129
|
-
|
|
121
|
+
Results submit completely through a separate JSON channel, limited to 64 MiB with explicit overflow failure. Diagnostics may truncate, but final business results cannot be reconstructed from truncated events. Task results persist as separate JSON resources; Native Messaging transfers Base64 chunks of at most 192 KiB raw bytes, with total-length and SHA-256 verification.
|
|
130
122
|
|
|
131
|
-
###
|
|
123
|
+
### Tasks and model execution
|
|
132
124
|
|
|
133
|
-
|
|
125
|
+
Task services provide `start/get/list/events/subscribe/wait/cancel/result`, unified statuses, and increasing event sequences. States distinguish queued, running, cancelling, succeeded, failed, cancelled, and interrupted. Records/terminal states persist; progress is bounded. Unfinished generations become interrupted after restart without redoing external operations. Parent/child model tasks share cancellation and terminal cleanup. Commands may declare checkpoints and explicit recovery.
|
|
134
126
|
|
|
135
|
-
|
|
127
|
+
User-level services use exclusive ownership and execution leases; multiple browser processes do not concurrently write one task store. Services own checkpoints; plugins declare recovery entries and revision-migration requirements. Long results use owned, checksummed, expiring resources with lossless chunked reads.
|
|
136
128
|
|
|
137
|
-
|
|
129
|
+
Services partition by plugin registry directory and listen on local Unix sockets/Windows named pipes. Sockets/data files are current-user-only. Leases record PID, OS process creation identity, protocol version, hostId, and epoch. Startup locks prevent duplicate launches; stop waits for executor cleanup and lease release. Protocol mismatches require stopping the old service rather than silently connecting.
|
|
138
130
|
|
|
139
|
-
|
|
131
|
+
Task acceptance pins cwd, environment, installation ID, source revision, and browser route. Environment is child-only and never persisted. Source and relative resources become content-hashed read-only snapshots. Static JS import/require must target Node built-ins or snapshot-relative files; external packages must be bundled. Escaping/missing dependencies reject before acceptance. Snapshots exclude node_modules and do not freeze system programs, Python packages, or dynamically resolved external dependencies. Named plugin calls remain host dependencies resolved at call time. Source changes or reinstall after removal create new installation IDs.
|
|
140
132
|
|
|
141
|
-
|
|
133
|
+
Default concurrency is 4 with 128 queued tasks. Limits: input 256 KiB, individual progress 64 KiB, history 256 entries/512 KiB. Events include cursors, gap indicators, and latest task snapshots. Lists bound pages/bytes and return nextCursor. Terminal tasks/results remain seven days, cleaned hourly while resident along with unreferenced revisions.
|
|
142
134
|
|
|
143
|
-
CLI/SDK/MCP
|
|
135
|
+
CLI/SDK/MCP can query local tasks. Tool pages see only their own plugin's toolbox/runtime tasks, not public-entry tasks. Toolbox browser calls bind original Native Host connections and survive tool-page closure. Lost browser connections interrupt calls explicitly without switching windows; purely local work is independent. Public background browser tasks require explicit targets, resolved to stable browserId before acceptance. Execution cannot override browser/connector/session/transport/local.
|
|
144
136
|
|
|
145
|
-
|
|
137
|
+
Explicit idempotencyKey deduplicates within installation/entry scope; changed input, revision, routing, environment, or deadline conflicts. Toolbox coalesces identical active requests on the same Native Host. Repeating an action after completion creates a new task. Wait timeout/unsubscribe stops observation only; execution cancellation requires cancel.
|
|
146
138
|
|
|
147
139
|
```typescript
|
|
148
140
|
const tasks = new PluginTaskClient();
|
|
@@ -152,19 +144,19 @@ try {
|
|
|
152
144
|
} finally { tasks.disconnect(); }
|
|
153
145
|
```
|
|
154
146
|
|
|
155
|
-
|
|
147
|
+
Tasks execute on the entry point's local service, with hostId-bearing IDs. Foreign-host IDs reject without broadcast queries. Plugins expose business commands and relevant progress/cancel/recovery actions. CLI/MCP use those entries without generic task, model, state, page-instance, or host-diagnostic tools.
|
|
156
148
|
|
|
157
|
-
|
|
149
|
+
Models persist as `kind: model` tasks sharing events, cancellation, lossless results, and retention. Commands default to concurrency 4, models 2, each with 128 queued, so commands waiting on child models do not block model scheduling. `app.model(request)` / `context.model(request)` create child tasks; parent cancellation/end first cleans children. Synchronous entries propagate signals too. Model deadlines default to 120 seconds. Executors own independent Provider processes and confirm tree termination before terminal cancellation.
|
|
158
150
|
|
|
159
|
-
`capabilities`
|
|
151
|
+
`capabilities` reports actually supported modes, permissions, structured output, streaming, and cancellation. Codex currently supports only explicit `{ provider: 'codex', mode: 'agent', permissions: 'read-only' }`. Each call uses a temporary app-server session with configured MCP, Apps, search, plugins, and related extensions disabled; sandboxes forbid writes/network and approval requests fail immediately. Read-only Agent file access remains, so tool-free execution is not promised. `mode: 'generate'` rejects explicitly without fallback. Interactive sidebar sessions remain independent.
|
|
160
152
|
|
|
161
|
-
|
|
153
|
+
Requests are limited to 256 KiB; `outputSchema` to 64 KiB, passed through [Codex app-server](https://developers.openai.com/codex/app-server/) `turn/start`. Hosts accept only successful turns' original final messages, parse JSON, then mark tasks successful. Providers enforce outputSchema; plugins validate final structure/business constraints. willRetry errors do not end execution early; terminal errors retain causes and stable codes. Optional `model.delta` diagnostics cannot be concatenated into final results. Final text is limited to 32 MiB, returning `{ text, output?, provider, mode, model? }`; plugins validate additional business constraints.
|
|
162
154
|
|
|
163
|
-
SDK
|
|
155
|
+
SDK uses `PluginModelClient.capabilities/list/start/run`; toolbox uses `host.model.capabilities/list/start` and `waitTask`. `PluginModelClient.run` signals cancel execution and await cleanup, unlike task `wait`, which stops observation only.
|
|
164
156
|
|
|
165
|
-
###
|
|
157
|
+
### Checkpoints and explicit recovery
|
|
166
158
|
|
|
167
|
-
|
|
159
|
+
Command entries can declare `taskRecovery` and register matching `app.recoveryCommand()` handlers. These run only in host-created recovery attempts, never through public commands, toolbox allowlists, or nested invocation.
|
|
168
160
|
|
|
169
161
|
```javascript
|
|
170
162
|
export const taskRecovery = { version: 1, commands: {
|
|
@@ -185,13 +177,13 @@ export default app => {
|
|
|
185
177
|
};
|
|
186
178
|
```
|
|
187
179
|
|
|
188
|
-
`context.checkpoint(data, expectedSequence)`
|
|
180
|
+
`context.checkpoint(data, expectedSequence)` is available only in active managed public commands with service routing and no page-instance binding. Children may checkpoint, but explicit recovery accepts eligible roots only. Payloads are limited to 64 KiB. Hosts check JSON/CAS sequences and assign increasing checkpoint numbers; schemas describe format/version identity, while plugins validate data. Data, versions, canonical host schemaHash, task snapshots, and checkpoint events share one atomic record. Stale writes conflict explicitly. Checkpoints neither prove external completion nor share state-transaction commits. Recovery handlers close external-submit/checkpoint failure windows by querying operations or using stable idempotency keys.
|
|
189
181
|
|
|
190
|
-
SDK
|
|
182
|
+
SDK methods are `PluginTaskClient.checkpoint(taskId)` / `resume(taskId, { environment?, revision? })`. resume accepts only failed, cancelled, or interrupted root commands. It creates a new taskId and execution generation with `resumedFrom`, leaving the original terminal. A source task has at most one direct successor; duplicate requests return that attempt, while different configuration conflicts. To recover a failed new attempt, resume its new taskId.
|
|
191
183
|
|
|
192
|
-
|
|
184
|
+
Recovery defaults to `revision: 'original'`, retaining the original installation, source snapshot, input, cwd, routing, and execution time limit. Before acceptance, ownership and all source hashes are revalidated. Missing or corrupt snapshots are rejected without falling back to current code. The original environment is not persisted. By default the SDK explicitly submits the calling process's current environment, or callers can supply environment; the service environment is not substituted. `context.recovery` includes fromTaskId, fromRevision, the original sourceCheckpoint format reference, and accepted checkpoint. The new attempt inherits data but starts its checkpoint sequence at 0; resumedFrom preserves the original revision/version/sequence. Hidden recovery handlers receive original input without requiring compliance with the current CLI's required arguments and must handle historical input themselves.
|
|
193
185
|
|
|
194
|
-
|
|
186
|
+
Explicit `resume(taskId, { revision: 'current' })` pins the registered source snapshot when the first request arrives. Matching format versions and canonical schemas are accepted directly. Changing a schema without increasing checkpointVersion is rejected. Cross-version recovery supports only a target-declared single-step migration:
|
|
195
187
|
|
|
196
188
|
```javascript
|
|
197
189
|
export const taskRecovery = { version: 1, commands: {
|
|
@@ -207,35 +199,33 @@ export default app => {
|
|
|
207
199
|
};
|
|
208
200
|
```
|
|
209
201
|
|
|
210
|
-
migrateFrom
|
|
211
|
-
|
|
212
|
-
同一源任务的并发恢复按 revision 选择与环境指纹合并,不同意图冲突;已提交后继的重试先核验请求指纹,不重复转换。迁移在独立受管理进程执行,10 秒期限,与声明解析共享最多 8 个进程预算,无等待队列,服务关闭会取消并等待清理。转换和原执行树均确认停止,且安装和双端代码快照再次核验后才接纳新任务。迁移没有宿主 API、模型、state、页面或嵌套插件调用权限;JS/Python 仍是可信本机代码,具备直接文件和网络访问能力,不构成 OS 沙箱。迁移必须是可重复的纯 JSON 转换:提交前崩溃可能再次执行,不承诺转换恰好执行一次。
|
|
202
|
+
migrateFrom allows up to 16 distinct versions below the target. Historical schemas must match checkpoint host hashes and retained declarations. Dynamic declaration drift rejects recovery even with unchanged source. Migration/recovery recheck target signatures before hidden handlers; normal checkpoint writes validate executing declarations; Python validates full metadata before each ready ACK. Migration returns new checkpoint data. Hosts validate JSON, the 64 KiB limit, and target identity, then atomically save data/provenance in the unique successor, leaving original tasks/checkpoints unchanged. Missing migrations, mismatched formats, conversion failures, and unconfirmed cleanup reject acceptance.
|
|
213
203
|
|
|
214
|
-
|
|
204
|
+
Concurrent recovery of one source task coalesces by revision choice and environment fingerprint; different intents conflict. Retries of committed successors verify request fingerprints without rerunning conversion. Migration runs in an independent managed process with a 10-second limit, sharing an eight-process budget with declaration parsing and no wait queue. Service shutdown cancels it and waits for cleanup. Acceptance requires confirmed termination of both conversion and original execution trees, plus revalidation of installation and both source snapshots. Migration has no host APIs, models, state, pages, or nested plugin calls. JS/Python remains trusted native code with direct file/network access, not an OS sandbox. Migration must be repeatable pure JSON conversion: crashes before commit may rerun it, with no exactly-once guarantee.
|
|
215
205
|
|
|
216
|
-
|
|
206
|
+
Recovery currently supports root commands with public entries and stable service-owned routes only. Toolbox/Native Host caller routes, page bindings, models, and child tasks explicitly reject recovery because their lifecycle cannot be inferred from an old task. Before acceptance, the host recursively checks supervising processes, OS creation identities, and POSIX groups for the task and all descendants. Running execution or unconfirmed cleanup rejects recovery; uncertain ownership records do not expire away. Windows also rejects recovery after service crashes without full process-tree termination proof. Recovery handlers can explicitly request models as new executions.
|
|
217
207
|
|
|
218
|
-
|
|
208
|
+
### Page runtimes and events
|
|
219
209
|
|
|
220
|
-
|
|
210
|
+
Page instances bind plugin revision, browser source, tab, frame, document, and instance ID. Business frame selectors resolve at attach time, then the target is fixed. Switching business WebViews invalidates old instances and creates new ones. Extension uses native documentId; pure CDP uses the default execution context's uniqueId for document identity, executes plugin code in isolated worlds, and passes events through validated CDP bindings, including cross-origin iframes. Chromium without uniqueId uses connection-local document identities; reconnecting invalidates old instances for activation rules to rebuild. External Providers must declare `page_runtime` or fail explicitly.
|
|
221
211
|
|
|
222
|
-
CDP
|
|
212
|
+
`PluginPageRuntimeHost` in `browser-core` shares instance lifecycle, event acknowledgment/retransmission, activation rules, leases, and chunked transport. Extension and CDP implement only document resolution, script execution, ports, and storage adapters. CDP sessions are isolated by browser endpoint identity; host restarts preserve session identity, while browser restarts clear session rules but retain persistent rules. Only endpoint digests are stored. CDP inherits connection permissions, while the common host still checks declared plugin URL scopes.
|
|
223
213
|
|
|
224
|
-
|
|
214
|
+
The CDP session layer persists target-to-virtual-tabId mappings by browser endpoint identity and restores them before page discovery and plugin reconciliation. Page storage persists independently by storage key; lease updates write only lease records. Document resolution also returns its target, and execution waits only for that target.
|
|
225
215
|
|
|
226
|
-
|
|
216
|
+
After native-host cleanup or transient disconnects, document instances retain ownership for a 30-second lease from the last successful validation. Unverifiable document operations return `PLUGIN_PAGE_UNAVAILABLE`, without performing page actions or treating failed reconciliation as absent instances. Reconnection must verify the original browser, document, and instance. Accepted events whose tasks have not started can stay queued; dispatched operations are not replayed. Explicit navigation, unloading, or invalidation cleans up immediately. Extended disconnects expire leases and old instances; enabled activation rules can create replacements after recovery.
|
|
227
217
|
|
|
228
|
-
CDP
|
|
229
|
-
|
|
230
|
-
|
|
218
|
+
CDP page-session files are reclaimed when one connection identifier changes browser identity, a controlled browser explicitly closes, or process exit is confirmed. Persistent activation rules remain.
|
|
219
|
+
Session files without verifiable browser ownership remain until full uninstall. `cdp-targets` tab-ID counters persist across browser lifecycles to prevent stale requests from targeting new tabs.
|
|
220
|
+
Controlled-browser logs rotate before launch at 5 MiB with one backup. Logs without browser records remain for seven days and are cleaned during host startup, browser queries, or launch.
|
|
231
221
|
|
|
232
|
-
|
|
222
|
+
The host provides `attach/get/list/send/detach` independently of toolbox declarations. Closing a tool page unsubscribes UI only. Document refresh rebuilds according to policy; SPA navigation notifies instances; plugin deactivation removes events and resources. Instance validity is checked on dequeue, before key host calls, and before writes.
|
|
233
223
|
|
|
234
|
-
|
|
224
|
+
Runtime event declarations specify event, payload schema, command, and serial, pending-coalescing, or bounded-concurrency policy. Hosts validate real sources and bound payloads and queues. Events are numbered by instance and connection generation. Receipt acknowledgment is separate from business completion, and retransmission deduplication from business retry. Cache gaps require resynchronization; document invalidation discards old events. Exactly-once execution across failures is not guaranteed.
|
|
235
225
|
|
|
236
|
-
|
|
226
|
+
Page instances are shared by plugin installation and real target document. Concurrent attach from CLI, toolbox, and automatic activation waits for one initialization. Toolbox can access only its own plugin. `pageRuntime` is independent of toolbox declarations; JS entries export function source and URL scope, and `app.runtimeCommand()` registers background initialization and event handlers. Public/toolbox commands cannot call these directly. Registration code is read in managed, terminable child processes.
|
|
237
227
|
|
|
238
|
-
Python
|
|
228
|
+
Python entries may export the same `pageRuntime` dictionary, with `code` containing a browser JavaScript function string. `app.runtimeCommand()` supports direct registration and decorators. Python `app.page()` and instance-bound `context.page.send/get` synchronously bridge to the same page service. Runtime-only markers participate in descriptor validation and actual Python handler selection; public/toolbox commands cannot execute them directly. Ordinary `app.command` handlers also used for page events remain public. Every Python run checks the full descriptor, including page declarations and command visibility, before its ready ACK.
|
|
239
229
|
|
|
240
230
|
```javascript
|
|
241
231
|
export const pageRuntime = {
|
|
@@ -256,113 +246,74 @@ export default app => {
|
|
|
256
246
|
};
|
|
257
247
|
```
|
|
258
248
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
事件负载最多 32 KiB,页面待确认队列 64 条;后台每事件默认待处理 32 条(最多 64),每实例活动事件最多 128,有限并发最多 8。历史最多 256 条及 384 KiB,游标缺口明确返回。Native Messaging 的请求与结果各按 192 KiB 分块并校验 SHA-256,单条页面业务消息/结果最多 24 MiB;浏览器与工具箱回复资源各有 32 MiB 总预算及 30 秒过期。
|
|
262
|
-
|
|
263
|
-
SDK 使用 `PluginPageClient`。工具箱调用 `host.page.*`,或 `window.mearl.subscribe('page', { instanceId, cursor? }, listener)` 观察后台事件;`events` 接受 `cursor` 与 `waitMs`(0–25000),无新事件时可等待变化;工具箱订阅先读取快照,随后使用长轮询,退订只结束观察。内部 `page_runtime` 是文档适配协议,业务插件使用 `app.page()`。设计稿叠加已迁移,保存事件无需 Popup 转发。
|
|
264
|
-
|
|
265
|
-
激活通过 `app.page('activation', { enabled: true, matches, persistence: 'session' | 'persistent', frame, input })` 显式配置;实际范围是用户规则与声明范围的交集;自动激活实例在注入、SPA 导航及日常校验时复查该交集,离开范围即失效,手动挂载遵循插件声明范围。关闭规则清理实例,在途挂载由规则代次校验阻止。扩展 worker 重启后先与执行服务握手,核验 hostId、service epoch、安装、revision、browserSessionId、documentId 和 instanceId;同一所有者按服务端已接收位置续传未确认事件,确认位置只前进。连接 epoch 变化不改变业务事件序号。桥接暂时不可用时保留队列等待对账,租约过期后失效。
|
|
249
|
+
Page-function `host.emit(name, payload)` returns receipt acknowledgment; query instance events for processing results. `context.page.send/get` always binds the current instance. Ordinary and compound page actions from runtime tasks are rejected. Each dequeue, host call, and result commit rechecks the document. Runtime transport preserves control-session ownership, pause, and release checks, processing messages and callbacks in parallel. Instances and event policies own ordering; waiting for business messages does not block same-document validation or cancellation. Page `receive(message, { signal, requestId })` supplies cooperative per-message cancellation. Task cancellation propagates to that document request; plugins should check signal after asynchronous waits. Cancellation does not forcibly stop page JS, so external operations still need reconciliation. Background renewal defaults to concurrent checks every 10 seconds, with eight-second per-instance validation and 30-second browser leases. Renewal updates memory only; a separate timer saves lightweight leases every five seconds. Full code and pending events persist only on relevant state changes. Invalidation cancels queued/running tasks and releases page resources.
|
|
266
250
|
|
|
267
|
-
|
|
251
|
+
Event schemas describe formats; background handlers validate payloads, while hosts check bindings, document ownership, sizes, and scheduling. Payloads are limited to 32 KiB; page pending-ack queues to 64. Background pending defaults to 32 per event (maximum 64), active events to 128 per instance, concurrency to 8. History holds 256 entries/384 KiB with explicit cursor gaps. Native Messaging chunks requests/results at 192 KiB with SHA-256 checks. Page messages/results allow 24 MiB; browser/toolbox reply resources each share 32 MiB and expire after 30 seconds.
|
|
268
252
|
|
|
269
|
-
|
|
253
|
+
SDK uses `PluginPageClient`; toolbox uses `host.page.*` or `window.mearl.subscribe('page', { instanceId, cursor? }, listener)`. `events` accepts `cursor` and `waitMs` (0–25000). Toolbox reads an initial snapshot then long-polls; unsubscribe stops observation only. Internal `page_runtime` adapts documents; plugins use `app.page()`. Design overlays save assets through page events.
|
|
270
254
|
|
|
271
|
-
|
|
255
|
+
Explicitly configure activation through `app.page('activation', { enabled: true, matches, persistence: 'session' | 'persistent', frame, input })`. Effective scope is the intersection of user rules and declarations. Automatic instances recheck it at injection, SPA navigation, and regular validation, invalidating when outside scope. Manual attachment follows declarations. Disabling rules cleans instances; rule generations block in-flight stale attaches. After extension worker restart, handshake with the execution service verifies hostId, service epoch, installation, revision, browserSessionId, documentId, and instanceId. The same owner resumes unacknowledged events from the service's received position, which only advances. Connection epochs do not change business event sequences. Temporary bridge outages retain queues for reconciliation until lease expiry.
|
|
272
256
|
|
|
273
|
-
|
|
257
|
+
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.
|
|
274
258
|
|
|
275
|
-
|
|
259
|
+
Service epoch changes, missing instances, or regressed receipt positions invalidate old instances and queues without replaying events into a new service. Existing activation rules can create new instances; manual instances require attach again. Rules bind installation IDs, so uninstalling or changing source does not transfer authorization to same-name replacements. Injection serializes handoff in an isolated script world, awaiting old handler dispose before creating a new instance so old overlays cannot remove new DOM.
|
|
276
260
|
|
|
277
|
-
|
|
261
|
+
### State and activation
|
|
278
262
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
命令使用 `app.state(collection, operation, input)`,或通过自动绑定当前页面实例的 `context.state(...)` 调用。SDK `PluginStateClient` 与工具箱 `host.state.*` 使用同一服务。设计稿叠加的素材和设置使用 browser-session memory,素材通过有界分块读写。用户显式导出的图片不属于缓存。
|
|
282
|
-
|
|
283
|
-
插件声明可用 URL 范围与激活入口,用户规则决定是否启用、匹配范围和跨重启保留。激活维护页面实例,业务命令由显式调用或事件触发。扩展、浏览器和执行服务分别重启时,通过握手对账实例及任务,防止重复恢复。
|
|
284
|
-
|
|
285
|
-
### 实施进度和验收
|
|
286
|
-
|
|
287
|
-
| 阶段 | 交付 | 状态 |
|
|
288
|
-
| --- | --- | --- |
|
|
289
|
-
| 执行基础 | 环境和调用身份、独立上下文、受管理执行器、后台命令接入、一次性 Agent 原始结果 | 已实现 |
|
|
290
|
-
| 执行服务 | 用户级服务、租约、安装与 revision 快照、持久任务和大结果、SDK/CLI/MCP 任务入口 | 已实现 |
|
|
291
|
-
| 页面能力 | 固定目标、运行实例、后台事件、激活规则及对应工具迁移 | 已实现(扩展与 CDP 共用宿主) |
|
|
292
|
-
| 模型和状态 | Provider 能力声明、受管理模型任务、结构化结果、事务状态、现有工具迁移 | 已实现(Codex 只读 Agent) |
|
|
293
|
-
| 故障恢复 | 原 revision 的检查点恢复、新 attempt、执行树核验、扩展/服务重启对账与激活重建 | 已实现(上述作用域) |
|
|
294
|
-
| 子调用归属 | 独立子任务与 revision、专属服务、权限与文档约束、等待名额和取消树 | 已实现 |
|
|
295
|
-
| 诊断和接口收口 | 有界元数据导出、SDK/CLI/MCP/工具箱/Python 对齐、错误语义及文档 | 已实现 |
|
|
296
|
-
|
|
297
|
-
工具箱后台入口统一为 host.task.*,迭代管理、标签管理和图片压缩已同步迁移。普通同步命令仍在调用进程执行,后台命令使用执行器。工具箱分块资源和业务状态不能依赖某次后台命令进程继续存活。
|
|
298
|
-
|
|
299
|
-
验收覆盖并发身份与服务初始化、上下文隔离、嵌套调用、入口限制、JS 阻塞终止、Python 上下文及取消、取消和完成竞态、挂起宿主调用、大文本和结构化结果、服务崩溃恢复、调用方断线、源码更新、事件缺口及结果校验。页面验收覆盖同文档并发初始化、连接代次与去重、事件合并、源码固定、导航取消、后台重启重发、激活停用竞态及双向资源完整性。模型与状态验收补充真实子进程中的大 Unicode 结果、结构化失败、独立队列、父子取消、Python 调用、CAS/TTL/迁移和页面失效写入竞态。恢复验收补充真实服务 SIGKILL、原 handler 不重放、并发 resume 去重、源码损坏、Python 恢复、子执行器未停、ACK 与对账交错、慢 dispose 和安装更换。真实 Chrome 已验证约 500 KB Unicode 文本双向分块、页面事件到实例状态的完整链路,以及执行服务 SIGKILL 后由激活规则重建新 epoch/实例并继续处理新事件。跨 revision 验收覆盖历史 schema 身份、显式单步迁移、版本固定、并发去重、输入兼容、宿主调用拦截和服务关闭清理。其他 Provider 和跨执行环境恢复保留在后续阶段。
|
|
300
|
-
|
|
301
|
-
### 真实端到端验收
|
|
302
|
-
|
|
303
|
-
根目录提供显式运行的验收脚本(不随单元测试访问真实模型):
|
|
304
|
-
|
|
305
|
-
```bash
|
|
306
|
-
pnpm build
|
|
307
|
-
pnpm verify:plugin-host:live \
|
|
308
|
-
--browser <全局浏览器ID> \
|
|
309
|
-
--model <当前账号支持的模型> \
|
|
310
|
-
--codex /absolute/path/to/codex \
|
|
311
|
-
--output /tmp/mearl-host-live-report.json
|
|
312
|
-
```
|
|
263
|
+
Schemas are format metadata; hosts do not evaluate JSON Schema keywords. Plugins validate state writes, event payloads, checkpoints, and migrations. Plugins export `stateStorage = { version: 1, collections: { ... } }`. Collections declare `scope` (installation/host/browser-session/instance), `storage` (persistent/cache/memory), `schemaVersion`, JSON Schema, and optional `maxEntries/maxBytes/ttlMs`. Browser-session/instance accept only cache/memory; memory supports only these scopes and lives in execution-host memory, allocated on demand with a host-wide 128 MiB/512-namespace limit. Restart clears it; instance end releases it. Browser-session state survives refresh but separates browser sessions. Real active pages determine scopes, never forged business fields. Instance end cleans dedicated caches; other caches default to one-day TTL, maximum seven days, reclaimed on reads, maintenance, and quotas. Settings, caches, tasks, and binary assets are separate.
|
|
313
264
|
|
|
314
|
-
|
|
265
|
+
If a namespace already has state, switching between memory and disk requires a new collection name or scope. Cross-medium migration is unsupported.
|
|
315
266
|
|
|
316
|
-
|
|
267
|
+
`get/list/transact` serialize in the user-level task service. Values, CAS versions, schema versions, TTLs, and the latest 64 idempotency receipts persist in one atomic record. Each put/delete requires the opaque `expectedVersion` obtained by reading. Collection versions increase monotonically and are never reused after deletion or expiry. Multi-key transactions allow 128 operations and 512 KiB; single values 256 KiB. Collections default to 1024 entries / 8 MiB, with disk state limited to 64 MiB per plugin. memory uses the host-wide limit above. list is bounded and paginated; callers use `expectedRevision` to detect changes between pages.
|
|
317
268
|
|
|
318
|
-
|
|
269
|
+
Changing schema/storage requires increasing `schemaVersion`. Migration transactions supply `migrateFromVersion` and `expectedRevision`. Plugins validate and transform retained values; hosts check versions/transaction constraints and atomically commit. Old revisions cannot write new schemas. Synchronous handlers verify load-time declaration signatures against update races. Replacement installations never inherit old namespaces.
|
|
319
270
|
|
|
320
|
-
|
|
271
|
+
Commands use `app.state(collection, operation, input)` or current-instance-bound `context.state(...)`. SDK `PluginStateClient` and toolbox `host.state.*` share the service. Design overlay assets/settings use browser-session memory with bounded chunked asset access. Explicitly exported user images are not cache.
|
|
321
272
|
|
|
322
|
-
|
|
273
|
+
Plugins declare available URL scopes and activation entries. User rules control enablement, matching, and cross-restart persistence. Activation maintains page instances; explicit invocation or events trigger business commands. Extension, browser, and execution-service restarts reconcile instances and tasks through handshakes to prevent duplicate recovery.
|
|
323
274
|
|
|
324
|
-
|
|
275
|
+
Toolbox background commands use `host.task.*`. Ordinary synchronous commands run in calling processes; background commands use managed executors. Long-lived resources persist through state, files, or resource channels.
|
|
325
276
|
|
|
326
|
-
|
|
277
|
+
When user-initiated toolbox attach lacks target-site permission, the host permission dialog is reused; approval retries only undispatched resolve. Heartbeats, instance messages, and background events never prompt or replay potentially effective operations. Extension reload is a host operation independent of the current page's domain grant.
|
|
327
278
|
|
|
328
|
-
###
|
|
279
|
+
### Cross-plugin calls
|
|
329
280
|
|
|
330
|
-
|
|
281
|
+
Managed `app.invoke(name, { command, input })` creates an independent child task pinned to the child installation/revision with its own state/model/page/checkpoint ownership. Children can call only public commands, without hidden toolbox/runtime permissions. Cycles and depth over 16 fail explicitly. Parent cancellation, expiry, or completion cancels and awaits the child tree. Children cannot change browser routes. Page-bound calls inherit document constraints and must explicitly attach their own instances under their own pageRuntime, never borrowing parent instances or controlling other documents. Children can checkpoint, but explicit resume remains eligible-root-only.
|
|
331
282
|
|
|
332
|
-
###
|
|
283
|
+
### Unified diagnostics
|
|
333
284
|
|
|
334
|
-
`PluginTaskClient.diagnose()`
|
|
285
|
+
`PluginTaskClient.diagnose()` and toolbox `host.task.diagnose` read one metadata report. taskId/plugin/instanceId filters intersect; caller scope filters before expanding parent/child/recovery relationships. Toolbox stays restricted to its plugin, including relationships. Diagnostics start no models, send no browser requests, and change no page bindings.
|
|
335
286
|
|
|
336
|
-
|
|
287
|
+
Reports link hostId/epoch, task/parent/resume, invocation, installation/revision, and document/instance. Model records include runtime choice, base configuration sources, observed authentication types, requested/configured/actually rerouted models, and acknowledged thread/turn limits. Base config/read does not establish final thread configuration. Missing notifications/history retain unknown/incomplete, without inferring accounts, credentials, or outcomes. Unavailable executable versions are omitted.
|
|
337
288
|
|
|
338
|
-
|
|
289
|
+
Defaults exclude input, prompts, progress/checkpoint/result bodies, full URLs, environment, and credentials. Errors include code only; executable paths retain basenames only. Explicit includeErrorMessages/includeLocalPaths permits bounded messages/local paths, never error details/metadata/stack. CLI exports use 0600 permissions. Limits: 256 KiB, 128 tasks, 64 pages, latest eight non-progress events per task; scans cap at 2048 directory entries, 512 records, and 16 MiB. coverage distinguishes incomplete scans from output omissions; history.gap reports retained-history gaps.
|
|
339
290
|
|
|
340
|
-
|
|
291
|
+
Executor states distinguish unstarted, currently observed alive, positively confirmed whole-tree stopped, and unknown. Terminal task status does not imply stopped execution. Page service-snapshot is the service's current record; historical-binding is execution-time identity. Neither guarantees the browser remains at that document.
|
|
341
292
|
|
|
342
|
-
###
|
|
293
|
+
### Public interfaces
|
|
343
294
|
|
|
344
|
-
|
|
|
295
|
+
| Capability | SDK | CLI | MCP | Toolbox |
|
|
345
296
|
| --- | --- | --- | --- | --- |
|
|
346
|
-
|
|
|
347
|
-
|
|
|
348
|
-
|
|
|
349
|
-
|
|
|
350
|
-
|
|
|
297
|
+
| Persistent tasks, results, cancellation, checkpoint recovery | PluginTaskClient | Plugin-defined business commands | plugin_invoke | host.task.start/get/list/events/result/cancel (SDK initiates checkpoint recovery) |
|
|
298
|
+
| Diagnostic export | tasks.diagnose | — | — | host.task.diagnose |
|
|
299
|
+
| Fixed-document runtimes and activation | PluginPageClient | Plugin business commands | plugin_invoke | host.page.* |
|
|
300
|
+
| Transactional state | PluginStateClient | Plugin business commands | plugin_invoke | host.state.* |
|
|
301
|
+
| Managed models | PluginModelClient | Plugin business commands | plugin_invoke | host.model.* |
|
|
351
302
|
|
|
352
|
-
|
|
303
|
+
JS/Python plugins compose these capabilities with context state/model/checkpoint and app.invoke. Synchronous commands run in calling processes; managed cross-plugin calls use separate child executors. Do not keep long-lived page resources in command processes. Wait timeouts stop observation; execution deadlines/cancel terminate trees. Commands/models have separate slots; parents waiting for children release slots and reacquire before continuing, with at most 32 waiting parents. In-memory active-child indexes let finalization cancel/wait only its children without scanning retained history; restart recovery still validates persisted trees.
|
|
353
304
|
|
|
354
|
-
##
|
|
305
|
+
## Build and validation
|
|
355
306
|
|
|
356
307
|
```bash
|
|
357
|
-
pnpm build # esbuild
|
|
358
|
-
pnpm typecheck #
|
|
308
|
+
pnpm build # esbuild into dist/, inlining browser-core / daemon-core
|
|
309
|
+
pnpm typecheck # Type checking only
|
|
359
310
|
```
|
|
360
311
|
|
|
361
312
|
## License
|
|
362
313
|
|
|
363
|
-
|
|
314
|
+
Apache-2.0
|
|
364
315
|
|
|
365
|
-
|
|
316
|
+
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.
|
|
366
317
|
|
|
367
318
|
|
|
368
|
-
|
|
319
|
+
`PluginHost` assembles `tasks/state/pages/models`, shutdown ordering, and diagnostics. Task schedulers own execution, parent/child calls, cancellation, and recovery, accessing state/pages through injected services. Models remain tasks with independent scheduling quotas and host-shared catalogs. Hosts explicitly wire page-instance state-scope resolution. `PluginHostConnection` shares RPC transport; Native Host caches connections separately by plugin, interaction channel, and source so sharing cannot change permission prompts.
|