@mearl/client 3.0.0-beta.4 → 3.0.0-beta.7
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 +95 -16
- package/dist/actionTimeouts.js +1 -1
- package/dist/autoUpdate.js +2 -1
- package/dist/capabilityHelp.d.ts +4 -0
- package/dist/capabilityHelp.js +69 -0
- package/dist/check.d.ts +5 -6
- package/dist/check.js +4 -7
- package/dist/cli.js +22 -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 +78 -62
- package/dist/commands.js +67 -49
- package/dist/index.d.ts +6 -2
- package/dist/index.js +10 -4
- package/dist/nativeHost.js +1 -1
- 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 +12 -4
- package/dist/plugins/runtime/pluginCommandWorker.js +8 -6
- 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 +4 -0
- package/dist/plugins/runtime/pluginPageManager.js +0 -4
- package/dist/plugins/runtime/pluginRevision.js +0 -51
- package/dist/plugins/runtime/pluginStateStore.js +3 -8
- package/dist/plugins/runtime/pluginTaskManager.js +4 -8
- package/dist/plugins/sdk/plugin.js +1 -1
- 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 +34 -9
- package/dist/unified.js +11 -1
- package/dist/unifiedConfig.d.ts +4 -0
- package/dist/unifiedConfig.js +11 -0
- package/package.json +13 -11
package/dist/commands.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
/** 容器档案名列表(拼进参数说明,新增档案无需改本文件) */
|
|
3
|
-
const APP_PROFILE_NAME_LIST = APP_PROFILE_NAMES.join('/');
|
|
1
|
+
import { BROWSER_DEVICE_PRESET_NAMES, } from '@mearl/browser-core';
|
|
4
2
|
const DEVICE_PRESET_TYPE = BROWSER_DEVICE_PRESET_NAMES.map(name => JSON.stringify(name)).join(' | ');
|
|
5
3
|
const PAGE_DIAGNOSTICS_PARAM = {
|
|
6
4
|
name: 'diagnostics',
|
|
@@ -30,13 +28,20 @@ const PAGE_OBSERVE_PARAM = {
|
|
|
30
28
|
const PAGE_ACTION_RESULT = [
|
|
31
29
|
'默认返回 { action, observation };action.success 只表示动作成功,业务效果需结合 observation 和目标状态判断。',
|
|
32
30
|
'observe=false 且未开启 diagnostics 时返回裸动作结果(如 { clicked: true }),没有 action/observation;开启 diagnostics 时返回 { action, diagnostics }。',
|
|
33
|
-
'包装结果中的 action.stage=precondition 表示未派发,省略 observation/diagnostics;dispatch-uncertain 表示可能已派发,先查看 action.attempt
|
|
31
|
+
'包装结果中的 action.stage=precondition 表示未派发,省略 observation/diagnostics;dispatch-uncertain 表示可能已派发,先查看 action.attempt 与可用观察或最小快照核验,避免重复提交。CLI 单次调用失败以退出码 1 结束;脚本需检查 action.success。',
|
|
34
32
|
'observation.effects 返回通知、控件和焦点增量,可直接复用 node.ref/selector;changed=true 且 effects 为空不表示失败。',
|
|
35
33
|
'effects.texts 按需返回普通可见文本的 selector/text,不代表可点击控件或业务成功;超限或覆盖不完整时仍提示补快照。',
|
|
36
34
|
'fullSnapshotRecommended/snapshotReasons 提示是否补充快照;openedTabs 返回可继续操作的 tabId 和 ready。navigation 模式的 ready 表示新页面就绪。',
|
|
37
35
|
'显式开启的诊断通道在 diagnostics 中返回动作期间增量,与 observe 独立。',
|
|
38
36
|
];
|
|
39
37
|
export const COMMANDS = [
|
|
38
|
+
{
|
|
39
|
+
name: 'get_capabilities',
|
|
40
|
+
description: '只读查询当前目标浏览器的动作、设备和已安装 App 能力、限制与 Skill/帮助入口;不打开页面或启用模拟',
|
|
41
|
+
params: [{ name: 'app', type: 'string', description: '可选,使用目录中的完整 App ID 查询桥方法、可调设置和默认版本详情' }],
|
|
42
|
+
notes: ['沿用 --browser / --session 路由;不传 app 返回摘要。apps.status=partial 表示目录未完整取得,unsupported 表示目标未提供目录;不能把两者当作未安装。', 'available=false 的 App 当前不可启用;支持某个 action 不代表已有域名权限或真实设备授权。按需读取 usage.skills / usage.documentation,查询不会自动安装或加载 Skill。'],
|
|
43
|
+
examples: ['get_capabilities', `get_capabilities --payload '{"app":"example/app"}'`],
|
|
44
|
+
},
|
|
40
45
|
{
|
|
41
46
|
name: 'browser_control',
|
|
42
47
|
description: '把控制会话交给用户;用户在 Mearl 浏览器管理页交还后重新观察页面',
|
|
@@ -96,7 +101,7 @@ export const COMMANDS = [
|
|
|
96
101
|
},
|
|
97
102
|
{
|
|
98
103
|
name: 'get_requests',
|
|
99
|
-
description: '
|
|
104
|
+
description: '获取最近的网络请求(协议请求或普通 xhr/fetch)',
|
|
100
105
|
params: [
|
|
101
106
|
{
|
|
102
107
|
name: 'tabId',
|
|
@@ -107,8 +112,8 @@ export const COMMANDS = [
|
|
|
107
112
|
{ name: 'count', type: 'number', description: '返回条数,默认 10' },
|
|
108
113
|
{
|
|
109
114
|
name: 'source',
|
|
110
|
-
type: '"
|
|
111
|
-
description: '数据来源,不填时默认
|
|
115
|
+
type: '"protocol" | "requests" | "all"',
|
|
116
|
+
description: '数据来源,不填时默认 all;all 返回全部业务请求',
|
|
112
117
|
},
|
|
113
118
|
{ name: 'filter', type: 'string', description: '按 URL 或 API 名称过滤,支持正则' },
|
|
114
119
|
{ name: 'since', type: 'number', description: '只返回最近 N 秒内的请求' },
|
|
@@ -128,7 +133,7 @@ export const COMMANDS = [
|
|
|
128
133
|
{ name: 'keysOnly', type: 'boolean', description: '只返回数据结构,不返回叶子值' },
|
|
129
134
|
],
|
|
130
135
|
notes: [
|
|
131
|
-
'流式请求开始后即进入缓冲区;页面及 App 桥代发的
|
|
136
|
+
'流式请求开始后即进入缓冲区;页面及 App 桥代发的 协议 SSE 都归入 protocol。无法归属当前页面 target 的 Service Worker 请求不在采集范围内。',
|
|
132
137
|
],
|
|
133
138
|
result: [
|
|
134
139
|
'nextCursor 用于同类查询续读,hasMore 表示还有数据,gap 表示缓冲区淘汰造成缺口;checkpoint cursor 可分别用于三类查询的初始边界。',
|
|
@@ -137,7 +142,7 @@ export const COMMANDS = [
|
|
|
137
142
|
],
|
|
138
143
|
examples: [
|
|
139
144
|
`get_requests --payload '{"tabId":12345,"count":5}'`,
|
|
140
|
-
`get_requests --payload '{"tabId":12345,"source":"
|
|
145
|
+
`get_requests --payload '{"tabId":12345,"source":"protocol","filter":"cart"}'`,
|
|
141
146
|
],
|
|
142
147
|
},
|
|
143
148
|
{
|
|
@@ -244,7 +249,7 @@ export const COMMANDS = [
|
|
|
244
249
|
'大字段可用顶层 @<绝对路径> 文件引用或 --payload-file;文件展开后仍受 Native Messaging 单条消息大小限制。',
|
|
245
250
|
],
|
|
246
251
|
examples: [
|
|
247
|
-
`set_mock --payload '{"tabId":12345,"apiName":"
|
|
252
|
+
`set_mock --payload '{"tabId":12345,"apiName":"cart.query","mockData":{"ret":["SUCCESS::调用成功"]}}'`,
|
|
248
253
|
`set_mock --payload-file ./mock-data.json`,
|
|
249
254
|
],
|
|
250
255
|
},
|
|
@@ -298,7 +303,7 @@ export const COMMANDS = [
|
|
|
298
303
|
],
|
|
299
304
|
notes: [
|
|
300
305
|
'扩展模式规则持久化;CDP 仅支持会话级 modifyHeaders 请求头 set,不支持响应头、initiatorDomains 或其他动作。Provider 是否支持以其能力声明为准。',
|
|
301
|
-
'扩展模式会检查规则请求 URL 和显式来源域名的访问权限;缺失时仍保存规则,返回 warnings 和 missingOrigins,不自动弹窗。可在请求规则页面授权,或按提示调用
|
|
306
|
+
'扩展模式会检查规则请求 URL 和显式来源域名的访问权限;缺失时仍保存规则,返回 warnings 和 missingOrigins,不自动弹窗。可在请求规则页面授权,或按提示调用 request_permission。复杂 URL 表达式无法完整推断域名时会提示手动检查。',
|
|
302
307
|
],
|
|
303
308
|
examples: [
|
|
304
309
|
`set_rule --payload '{"actionType":"block","filter":"^https://example\\\\.com/ads/.*"}'`,
|
|
@@ -364,32 +369,28 @@ export const COMMANDS = [
|
|
|
364
369
|
],
|
|
365
370
|
},
|
|
366
371
|
{
|
|
367
|
-
name: '
|
|
368
|
-
description: '
|
|
372
|
+
name: 'send_protocol_request',
|
|
373
|
+
description: '通过已安装的请求协议能力,使用目标浏览器 Cookie 发送请求',
|
|
369
374
|
params: [
|
|
370
|
-
{ name: '
|
|
371
|
-
{ name: 'data', type: 'object', description: '请求数据' },
|
|
372
|
-
{ name: 'version', type: 'string', description: 'API 版本,默认 1.0' },
|
|
373
|
-
{ name: 'method', type: 'string', description: 'HTTP 方法,默认 GET' },
|
|
374
|
-
{ name: 'appKey', type: 'string', description: '签名使用的 appKey,默认 12574478' },
|
|
375
|
-
{ name: 'env', type: '"prod" | "pre"', description: '请求环境,默认 prod' },
|
|
376
|
-
{ name: 'timeout', type: 'number', description: '超时毫秒数,默认 10000' },
|
|
375
|
+
{ name: 'timeout', type: 'number', description: '宿主超时毫秒数;协议能力负责校验具体参数' },
|
|
377
376
|
],
|
|
378
377
|
notes: [
|
|
379
|
-
'
|
|
380
|
-
'
|
|
381
|
-
],
|
|
382
|
-
result: ['返回 success、response、requestData;业务成功需检查 response.ret。'],
|
|
383
|
-
examples: [
|
|
384
|
-
`send_mtop_request --payload '{"api":"mtop.trade.order.detail","data":{"orderId":"123"}}'`,
|
|
378
|
+
'需要安装提供 request.protocol 的能力包;参数、签名、网关与响应协议由能力包定义。',
|
|
379
|
+
'使用 --payload 传递协议文档声明的参数;核心不设置业务参数默认值。',
|
|
385
380
|
],
|
|
381
|
+
result: ['返回 success、response、requestData;业务结果由协议定义。'],
|
|
382
|
+
examples: [`send_protocol_request --payload '{"operation":"example","data":{}}'`],
|
|
386
383
|
},
|
|
387
384
|
// ── 浏览器 ────────────────────────────────────────────────────────────────
|
|
388
385
|
{
|
|
389
386
|
name: 'browser_list',
|
|
390
387
|
description: '列出所有浏览器及其连接状态、类型和 Provider 托管实例信息',
|
|
391
388
|
summary: '列出本地及远端浏览器与连接状态',
|
|
392
|
-
|
|
389
|
+
params: [
|
|
390
|
+
{ name: 'provider', type: 'string', description: '配合 launchForm,仅查询一个本机已安装 Provider 的启动候选;需 --local' },
|
|
391
|
+
{ name: 'launchForm', type: 'object', description: '现有动态启动表单请求:{variant?,values:{}},不创建或接入实例' },
|
|
392
|
+
],
|
|
393
|
+
examples: ['browser_list', 'browser_list --local'],
|
|
393
394
|
},
|
|
394
395
|
{
|
|
395
396
|
name: 'browser_release',
|
|
@@ -496,6 +497,9 @@ export const COMMANDS = [
|
|
|
496
497
|
name: 'tab_open',
|
|
497
498
|
description: '打开或按 URL 规则复用 Tab,并等待新页面加载完成',
|
|
498
499
|
aliases: ['tab_new', 'new_tab', 'tab_create', 'create_tab'],
|
|
500
|
+
aliasExamples: {
|
|
501
|
+
tab_activate: `tab_open --payload '{"url":"https://example.com","reuse":"require","active":true}'`,
|
|
502
|
+
},
|
|
499
503
|
params: [
|
|
500
504
|
{ name: 'url', type: 'string', required: true, description: '要打开的 URL' },
|
|
501
505
|
{
|
|
@@ -541,7 +545,7 @@ export const COMMANDS = [
|
|
|
541
545
|
{
|
|
542
546
|
name: 'appProfile',
|
|
543
547
|
type: 'string',
|
|
544
|
-
description: '按已安装档案应用 App
|
|
548
|
+
description: '按已安装档案应用 App 环境,ID 与限制见当前动态帮助。需要 iframe WebView 和系统栏时同时传 emulation.deviceShell=true',
|
|
545
549
|
},
|
|
546
550
|
{
|
|
547
551
|
name: 'os',
|
|
@@ -567,9 +571,9 @@ export const COMMANDS = [
|
|
|
567
571
|
`tab_open --payload '{"url":"https://example.com"}'`,
|
|
568
572
|
`tab_open --payload '{"url":"https://example.com/page","reuse":"prefer","match":{"ignoreSearch":true}}'`,
|
|
569
573
|
`tab_open --payload '{"url":"https://m.example.com","emulation":{"preset":"iphone-17-pro"}}'`,
|
|
570
|
-
`tab_open --payload '{"url":"https://example.com/app/home","appProfile":"
|
|
571
|
-
`tab_open --payload '{"url":"https://example.com/app/home","appProfile":"
|
|
572
|
-
`tab_open --payload '{"url":"https://example.com","appProfile":"
|
|
574
|
+
`tab_open --payload '{"url":"https://example.com/app/home","appProfile":"reader"}'`,
|
|
575
|
+
`tab_open --payload '{"url":"https://example.com/app/home","appProfile":"reader","emulation":{"preset":"ipad-mini-a17-pro","orientation":"landscape","deviceShell":true,"splitScreen":true}}'`,
|
|
576
|
+
`tab_open --payload '{"url":"https://example.com","appProfile":"reader","os":"android"}'`,
|
|
573
577
|
`tab_open --payload '{"url":"https://example.com","group":"验证任务"}'`,
|
|
574
578
|
],
|
|
575
579
|
},
|
|
@@ -613,6 +617,9 @@ export const COMMANDS = [
|
|
|
613
617
|
{
|
|
614
618
|
name: 'page_click',
|
|
615
619
|
description: '点击页面元素,支持 CSS/@ref、可见文本或视口坐标定位',
|
|
620
|
+
aliasExamples: {
|
|
621
|
+
page_select: `page_click --payload '{"tabId":12345,"text":"选项文案","role":"option"}'`,
|
|
622
|
+
},
|
|
616
623
|
params: [
|
|
617
624
|
{
|
|
618
625
|
name: 'selector',
|
|
@@ -666,7 +673,8 @@ export const COMMANDS = [
|
|
|
666
673
|
result: PAGE_ACTION_RESULT,
|
|
667
674
|
notes: [
|
|
668
675
|
'selector / text / point 必须且只能提供一个。隐藏页 auto 使用 DOM;只有明确依赖真实用户手势时才激活页面。',
|
|
669
|
-
'
|
|
676
|
+
'auto 对原生 option、checkbox/radio 使用状态感知的 DOM 路径;显式 mouse/touch 保留可信输入。',
|
|
677
|
+
'原生 select 可按 option 文本点击;auto/dom 返回 selectionState.valueBefore/valueAfter/selectedAfter,检查选中状态是否保持。checkbox/radio 返回 controlState.checkedBefore/checkedAfter。',
|
|
670
678
|
],
|
|
671
679
|
examples: [
|
|
672
680
|
`page_click --payload '{"tabId":12345,"text":"提交"}'`,
|
|
@@ -721,6 +729,9 @@ export const COMMANDS = [
|
|
|
721
729
|
{
|
|
722
730
|
name: 'page_type',
|
|
723
731
|
description: '向输入框填写文本,兼容 React 受控组件',
|
|
732
|
+
aliasExamples: {
|
|
733
|
+
page_fill: `page_type --payload '{"tabId":12345,"selector":"@e6","text":"填写内容","clearFirst":true}'`,
|
|
734
|
+
},
|
|
724
735
|
params: [
|
|
725
736
|
{
|
|
726
737
|
name: 'selector',
|
|
@@ -906,6 +917,8 @@ export const COMMANDS = [
|
|
|
906
917
|
description: '按键名称:Enter/Tab/Escape/Backspace 等',
|
|
907
918
|
},
|
|
908
919
|
{ name: 'modifiers', type: 'string[]', description: '修饰键数组:ctrl/alt/shift/meta/cmd' },
|
|
920
|
+
{ name: 'dialogId', type: 'string', description: '原生弹窗回执或 page_snapshot 中的 dialog.id;仅配合 Enter 接受或 Escape 取消' },
|
|
921
|
+
{ name: 'promptText', type: 'string', description: '仅用于 dialogId + Enter 接受原生 prompt 时填写文本' },
|
|
909
922
|
{
|
|
910
923
|
name: 'pressMode',
|
|
911
924
|
type: '"auto" | "dom" | "keyboard"',
|
|
@@ -917,6 +930,7 @@ export const COMMANDS = [
|
|
|
917
930
|
],
|
|
918
931
|
notes: [
|
|
919
932
|
'隐藏页 DOM 模式支持 Tab 焦点移动、原生控件 Enter/Space 激活和输入框 Enter 提交;编辑、选择、方向键和页面滚动等原生行为需可见页与 pressMode=keyboard。',
|
|
933
|
+
'原生 alert/confirm/prompt/beforeunload 弹窗需显式传 dialogId;普通 Enter 不处理弹窗。弹窗处理绕过 DOM 观察,不自动重放被中断的动作;处理后重新读取页面。',
|
|
920
934
|
],
|
|
921
935
|
result: [
|
|
922
936
|
...PAGE_ACTION_RESULT,
|
|
@@ -956,6 +970,7 @@ export const COMMANDS = [
|
|
|
956
970
|
],
|
|
957
971
|
notes: [
|
|
958
972
|
'time / selector / text / condition 必须且只能提供一个;time 范围 0–60000ms。页面交互已有内置观察,仅在需要独立等待条件时使用。',
|
|
973
|
+
'等待后须立即执行已知动作时,用 mearl run 在同一脚本中 await pageWait 后紧接 pageClick,避免模型往返。整体 --timeout 须覆盖等待及后续动作;等待失败不继续点击。',
|
|
959
974
|
],
|
|
960
975
|
examples: [
|
|
961
976
|
`page_wait --payload '{"tabId":12345,"time":1000}'`,
|
|
@@ -968,6 +983,9 @@ export const COMMANDS = [
|
|
|
968
983
|
{
|
|
969
984
|
name: 'page_navigate',
|
|
970
985
|
description: '在当前标签页内导航到 URL、刷新页面,或沿浏览历史后退/前进',
|
|
986
|
+
aliasExamples: {
|
|
987
|
+
page_reload: `page_navigate --payload '{"tabId":12345,"refresh":true}'`,
|
|
988
|
+
},
|
|
971
989
|
params: [
|
|
972
990
|
{
|
|
973
991
|
name: 'url',
|
|
@@ -1167,14 +1185,14 @@ export const COMMANDS = [
|
|
|
1167
1185
|
},
|
|
1168
1186
|
{
|
|
1169
1187
|
name: 'set_app_profile',
|
|
1170
|
-
description: '设置已安装的 App 档案;完整 JSBridge
|
|
1188
|
+
description: '设置已安装的 App 档案;完整 JSBridge 由能力包提供。可同时设置已安装的网络控件,传 emulation 时联动设备模拟',
|
|
1171
1189
|
summary: '设置或清除目标标签页的 App 容器模拟',
|
|
1172
1190
|
params: [
|
|
1173
1191
|
{ name: 'enabled', type: 'boolean', required: true, description: 'true=启用,false=清除' },
|
|
1174
1192
|
{
|
|
1175
1193
|
name: 'profile',
|
|
1176
1194
|
type: 'string',
|
|
1177
|
-
description:
|
|
1195
|
+
description: '已安装的容器档案 ID(enabled=true 时必填);当前动态帮助直接展示目标浏览器目录',
|
|
1178
1196
|
},
|
|
1179
1197
|
{ name: 'os', type: '"ios" | "android"', description: '容器系统,默认 ios' },
|
|
1180
1198
|
{
|
|
@@ -1199,9 +1217,9 @@ export const COMMANDS = [
|
|
|
1199
1217
|
description: '声明式覆盖桥方法,形如 {methods:{api:{behavior|response|noop,silent?}}};不执行配置脚本',
|
|
1200
1218
|
},
|
|
1201
1219
|
{
|
|
1202
|
-
name: '
|
|
1203
|
-
type: '
|
|
1204
|
-
description: '
|
|
1220
|
+
name: 'networkControl',
|
|
1221
|
+
type: 'object | null',
|
|
1222
|
+
description: '可选已安装网络控件 {id,value};null 清除,省略时保持当前设置。仅作用于目标 tab',
|
|
1205
1223
|
},
|
|
1206
1224
|
{
|
|
1207
1225
|
name: 'emulation',
|
|
@@ -1217,15 +1235,15 @@ export const COMMANDS = [
|
|
|
1217
1235
|
'bridgeConfig.methods 按方法声明 behavior / response / noop 三选一,可传 silent;只支持受控行为、固定 JSON 回包或成功空实现,不执行配置脚本。',
|
|
1218
1236
|
],
|
|
1219
1237
|
result: [
|
|
1220
|
-
'返回 enabled、profile、label、userAgent、os、
|
|
1238
|
+
'返回 enabled、profile、label、userAgent、os、networkControl、reloaded;联动设备时额外返回实际 emulation。',
|
|
1221
1239
|
],
|
|
1222
1240
|
examples: [
|
|
1223
|
-
`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"
|
|
1224
|
-
`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"
|
|
1225
|
-
`set_app_profile --payload '{"tabId":12345,"enabled":false,"
|
|
1226
|
-
`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"
|
|
1227
|
-
`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"
|
|
1228
|
-
`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"
|
|
1241
|
+
`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"reader"}'`,
|
|
1242
|
+
`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"reader","networkControl":{"id":"environment","value":"pre"}}'`,
|
|
1243
|
+
`set_app_profile --payload '{"tabId":12345,"enabled":false,"networkControl":null}'`,
|
|
1244
|
+
`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"reader","emulation":{}}'`,
|
|
1245
|
+
`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"wallet","emulation":{"preset":"pixel-11","deviceShell":true}}'`,
|
|
1246
|
+
`set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"reader","emulation":{"preset":"ipad-mini-a17-pro","orientation":"landscape","deviceShell":true,"splitScreen":true}}'`,
|
|
1229
1247
|
`set_app_profile --payload '{"tabId":12345,"enabled":false}'`,
|
|
1230
1248
|
`set_app_profile --payload '{"tabId":12345,"enabled":false,"emulation":{}}'`,
|
|
1231
1249
|
],
|
|
@@ -1280,9 +1298,9 @@ export const COMMANDS = [
|
|
|
1280
1298
|
result: ['找到时 found=true 并返回 value/domain/path;不存在时 found=false。'],
|
|
1281
1299
|
examples: [
|
|
1282
1300
|
`get_cookie --payload '{"tabId":12345,"name":"feature_flag"}'`,
|
|
1283
|
-
`get_cookie --payload '{"url":"https://www.
|
|
1301
|
+
`get_cookie --payload '{"url":"https://www.shop.com/","name":"account_name"}'`,
|
|
1284
1302
|
`get_cookie --payload '{"tabId":12345,"name":"feature_channel","domain":"example.com"}'`,
|
|
1285
|
-
`get_cookie --payload '{"tabId":12345,"name":"
|
|
1303
|
+
`get_cookie --payload '{"tabId":12345,"name":"account_name","url":"https://www.shop.com/","domain":"example.com","path":"/"}'`,
|
|
1286
1304
|
],
|
|
1287
1305
|
},
|
|
1288
1306
|
{
|
|
@@ -1327,7 +1345,7 @@ export const COMMANDS = [
|
|
|
1327
1345
|
result: ['返回 url/name/domain/path/reloaded,指定标签页时包含 tabId;不回显 Cookie 值。'],
|
|
1328
1346
|
examples: [
|
|
1329
1347
|
`set_cookie --payload '{"tabId":12345,"name":"feature_flag","value":"enabled"}'`,
|
|
1330
|
-
`set_cookie --payload '{"url":"https://www.
|
|
1348
|
+
`set_cookie --payload '{"url":"https://www.shop.com/","name":"feature_flag","value":"enabled"}'`,
|
|
1331
1349
|
`set_cookie --payload '{"tabId":12345,"name":"feature_channel","value":"3.6.63","domain":"example.com","reload":true}'`,
|
|
1332
1350
|
],
|
|
1333
1351
|
},
|
|
@@ -1342,7 +1360,7 @@ export const COMMANDS = [
|
|
|
1342
1360
|
examples: [`page_frames --payload '{"tabId":12345}'`],
|
|
1343
1361
|
},
|
|
1344
1362
|
{
|
|
1345
|
-
name: '
|
|
1363
|
+
name: 'request_permission',
|
|
1346
1364
|
description: '申请访问指定域名的权限(必要时弹窗让用户授权)',
|
|
1347
1365
|
params: [
|
|
1348
1366
|
{
|
|
@@ -1357,7 +1375,7 @@ export const COMMANDS = [
|
|
|
1357
1375
|
'弹窗等待用户选择,90 秒超时或关闭按拒绝处理;granted=true 后才重试原请求。',
|
|
1358
1376
|
],
|
|
1359
1377
|
result: ['返回 granted、domain,授权成功时包含 origin。'],
|
|
1360
|
-
examples: [`
|
|
1378
|
+
examples: [`request_permission --payload '{"domain":"example.com"}'`],
|
|
1361
1379
|
},
|
|
1362
1380
|
// ── 组合调用 ────────────────────────────────────────────────────────────────
|
|
1363
1381
|
{
|
package/dist/index.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export { UnifiedClient, UnifiedClient as MearlClient, decodeBrowserTarget, invok
|
|
|
13
13
|
export type { UnifiedClientOptions, UnifiedInvokeOptions, UnifiedInvokeOptions as InvokeOptions, } from './unified.js';
|
|
14
14
|
export type { PluginInvocation, PluginInvokeOptions, PluginProgress, StructuredPluginProgress, } from './plugins/sdk/plugin.js';
|
|
15
15
|
export { APP_PROFILE_NAMES, BROWSER_DEVICE_PRESET_NAMES, BROWSER_ACTIONS, BROWSER_CAPABILITY_ACTIONS, BROWSER_COMMAND_ACTIONS, EXTENSION_BROWSER_ACTIONS, PAGE_ACT_ACTIONS, SEND_REQUEST_MAX_FILES, SEND_REQUEST_MAX_TOTAL_BASE64_FILE_BYTES, SEND_REQUEST_MAX_TOTAL_FILE_BYTES, isBrowserAction, isBrowserCapabilityAction, isBrowserCommandAction, isExtensionBrowserAction, } from '@mearl/browser-core';
|
|
16
|
-
export type { ActionStep, AppProfileName, BrowserAction, BrowserActionMap, BrowserActionRequest, BrowserActionResponse, BrowserCapabilities, BrowserCapabilityAction, BrowserCloseParams, BrowserCommandAction, BrowserInfo, BrowserInfoBase, BrowserJsonValue, BrowserLaunchParams, BrowserProviderOperation, BrowserListResult, BrowserPairingInfo, BrowserReleaseFailure, BrowserReleaseResult, BrowserProviderDefinition, BrowserProviderIdentity, BrowserProviderInputSchema, BrowserProviderListResult, BrowserReference, BrowserDetails, BrowserSource, BrowserStatus, BrowserScreenshotKind, BrowserTransport, CaptureCheckpointParams, CaptureCheckpointResult, BrowserDevicePresetName, BrowserEmulationOptions, ExtensionBrowserAction, GetCookieParams, GetCookieResult, GetEventsParams, GetLogsParams, GetMocksParams, GetRequestsParams, ManagedBrowserInfo, PageClickParams, PageDragEndpoint, PageDragParams, PageDragPoint, PageActAction, PageDiagnosticsOptions, PageDiagnosticsSetting, PageEvalParams, PageFramesParams, PageHoverParams, PageInspectFilter, PageInspectParams, PageNavigateParams, PageObservationWaitOptions, PagePressParams, PageScreenshotParams, PageScrollParams, PageSnapshotParams, PageSnapshotQuery, PageTypeParams, PageUploadParams, PageWaitParams, RegularBrowserInfo,
|
|
16
|
+
export type { ActionStep, AppProfileName, BrowserAction, BrowserActionMap, BrowserActionRequest, BrowserActionResponse, BrowserCapabilities, BrowserCapabilityAction, BrowserCloseParams, BrowserCommandAction, BrowserInfo, BrowserInfoBase, BrowserJsonValue, BrowserLaunchParams, BrowserProviderOperation, BrowserListResult, BrowserListParams, BrowserPairingInfo, BrowserReleaseFailure, BrowserReleaseResult, BrowserProviderDefinition, BrowserProviderIdentity, BrowserProviderInputSchema, BrowserProviderListResult, BrowserReference, BrowserDetails, BrowserSource, BrowserStatus, BrowserScreenshotKind, BrowserTransport, CaptureCheckpointParams, CaptureCheckpointResult, BrowserDevicePresetName, BrowserEmulationOptions, ExtensionBrowserAction, GetCookieParams, GetCookieResult, GetEventsParams, GetLogsParams, GetMocksParams, GetRequestsParams, ManagedBrowserInfo, PageClickParams, PageDragEndpoint, PageDragParams, PageDragPoint, PageActAction, PageDiagnosticsOptions, PageDiagnosticsSetting, PageEvalParams, PageFramesParams, PageHoverParams, PageInspectFilter, PageInspectParams, PageNavigateParams, PageObservationWaitOptions, PagePressParams, PageScreenshotParams, PageScrollParams, PageSnapshotParams, PageSnapshotQuery, PageTypeParams, PageUploadParams, PageWaitParams, RegularBrowserInfo, RequestPermissionParams, RulesResult, RunActionName, RunActionsParams, SelectBrowserParams, SelectBrowserResult, SendRequestFile, SendRequestBinaryBody, SendRequestFormValue, SendProtocolRequestParams, SendRequestParams, SetAppProfileParams, SetCookieParams, SetCookieResult, SetDeviceEmulationParams, SetMockParams, SetRuleParams, SetTimezoneParams, SetTimezoneResult, TabCloseParams, TabOpenParams, } from '@mearl/browser-core';
|
|
17
17
|
import { type UnifiedInvokeOptions } from './unified.js';
|
|
18
18
|
import type * as Protocol from '@mearl/browser-core';
|
|
19
19
|
export declare function tabCheckpoint(params: Protocol.CaptureCheckpointParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'tab_checkpoint'>>;
|
|
@@ -25,8 +25,9 @@ export declare function getEvents(params: Protocol.GetEventsParams, options?: Un
|
|
|
25
25
|
export declare function setMock(params: Protocol.SetMockParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'set_mock'>>;
|
|
26
26
|
export declare function getMocks(params: Protocol.GetMocksParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'get_mocks'>>;
|
|
27
27
|
export declare function sendRequest(params: Protocol.SendRequestParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'send_request'>>;
|
|
28
|
-
export declare function
|
|
28
|
+
export declare function sendProtocolRequest(params: Protocol.SendProtocolRequestParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'send_protocol_request'>>;
|
|
29
29
|
export declare function browserList(options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'browser_list'>>;
|
|
30
|
+
export declare function browserList(params: Protocol.BrowserListParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'browser_list'>>;
|
|
30
31
|
export declare function selectBrowser(params?: Protocol.SelectBrowserParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'browser_select_browser'>>;
|
|
31
32
|
export declare function browserRelease(options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'browser_release'>>;
|
|
32
33
|
export declare function browserRelease(params: Protocol.BrowserReleaseParams, options: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'browser_release'>>;
|
|
@@ -37,6 +38,7 @@ export declare function getRules(options?: UnifiedInvokeOptions): Promise<Protoc
|
|
|
37
38
|
export declare function pageScreenshot(params: Protocol.PageScreenshotParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'page_screenshot'>>;
|
|
38
39
|
export declare function tabOpen(params: Protocol.TabOpenParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'tab_open'>>;
|
|
39
40
|
export declare function tabClose(params: Protocol.TabCloseParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'tab_close'>>;
|
|
41
|
+
export declare function getCapabilities(params?: Protocol.GetCapabilitiesParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'get_capabilities'>>;
|
|
40
42
|
export declare function tabList(options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'tab_list'>>;
|
|
41
43
|
export declare function tabGroup(params: Protocol.TabGroupParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'tab_group'>>;
|
|
42
44
|
export declare function pageClick(params: Protocol.PageClickParams, options?: UnifiedInvokeOptions): Promise<Protocol.BrowserActionResponse<'page_click'>>;
|
|
@@ -69,3 +71,5 @@ export declare function saveArtifact(artifact: Protocol.BrowserArtifact & {
|
|
|
69
71
|
export { PluginStateClient } from './plugins/clients/pluginState.js';
|
|
70
72
|
export { PluginModelClient } from './plugins/clients/pluginModels.js';
|
|
71
73
|
export type * from '@mearl/browser-core';
|
|
74
|
+
export { getStructure as structure, type StructureOptions } from '@mearl/browser-core';
|
|
75
|
+
export type { GetCapabilitiesParams, BrowserCapabilityCatalog, AppCapability, AppProfileUsage } from '@mearl/browser-core';
|
package/dist/index.js
CHANGED
|
@@ -36,11 +36,13 @@ export function getMocks(params, options) {
|
|
|
36
36
|
export function sendRequest(params, options) {
|
|
37
37
|
return invoke('send_request', params, options);
|
|
38
38
|
}
|
|
39
|
-
export function
|
|
40
|
-
return invoke('
|
|
39
|
+
export function sendProtocolRequest(params, options) {
|
|
40
|
+
return invoke('send_protocol_request', params, options);
|
|
41
41
|
}
|
|
42
|
-
export function browserList(options) {
|
|
43
|
-
return
|
|
42
|
+
export function browserList(paramsOrOptions = {}, options) {
|
|
43
|
+
return 'provider' in paramsOrOptions || 'launchForm' in paramsOrOptions
|
|
44
|
+
? invoke('browser_list', paramsOrOptions, options)
|
|
45
|
+
: invoke('browser_list', {}, paramsOrOptions);
|
|
44
46
|
}
|
|
45
47
|
export function selectBrowser(params = {}, options) {
|
|
46
48
|
return invoke('browser_select_browser', params, options);
|
|
@@ -71,6 +73,9 @@ export function tabOpen(params, options) {
|
|
|
71
73
|
export function tabClose(params, options) {
|
|
72
74
|
return invoke('tab_close', params, options);
|
|
73
75
|
}
|
|
76
|
+
export function getCapabilities(params = {}, options) {
|
|
77
|
+
return invoke('get_capabilities', params, options);
|
|
78
|
+
}
|
|
74
79
|
export function tabList(options) {
|
|
75
80
|
return invoke('tab_list', {}, options);
|
|
76
81
|
}
|
|
@@ -146,3 +151,4 @@ export async function saveArtifact(artifact, outputPath, options = {}) {
|
|
|
146
151
|
}
|
|
147
152
|
export { PluginStateClient } from './plugins/clients/pluginState.js';
|
|
148
153
|
export { PluginModelClient } from './plugins/clients/pluginModels.js';
|
|
154
|
+
export { getStructure as structure } from '@mearl/browser-core';
|
package/dist/nativeHost.js
CHANGED
|
@@ -96,7 +96,7 @@ export function inspectNativeHostInstallation(options = {}) {
|
|
|
96
96
|
details: [
|
|
97
97
|
...details,
|
|
98
98
|
`Registration: ${manifestPath}`,
|
|
99
|
-
'Run `mearl-native-host init` with a working Node.js, then reopen the extension. If the runtime package is missing, run `npx
|
|
99
|
+
'Run `mearl-native-host init` with a working Node.js, then reopen the extension. If the runtime package is missing, run `npx @mearl/setup update --local`.',
|
|
100
100
|
],
|
|
101
101
|
});
|
|
102
102
|
}
|
|
@@ -243,7 +243,9 @@ export class PluginHostConnection {
|
|
|
243
243
|
this.connection = undefined;
|
|
244
244
|
});
|
|
245
245
|
}
|
|
246
|
-
|
|
246
|
+
const connection = await this.connection;
|
|
247
|
+
// The handshake protocol defines compatibility; build identity is diagnostic metadata.
|
|
248
|
+
return connection.request(method, input, timeoutMs);
|
|
247
249
|
}
|
|
248
250
|
disconnect() {
|
|
249
251
|
this.generation++;
|
|
@@ -2,6 +2,7 @@ import { closeSync, mkdirSync, openSync, rmSync, statSync, writeFileSync } from
|
|
|
2
2
|
import { CLIENT_VERSION } from '../runtimePaths.js';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { spawn } from 'node:child_process';
|
|
5
|
+
import { npmExecEnvironment } from '@mearl/daemon-core';
|
|
5
6
|
import { findOfficialPlugin, readOfficialPluginCatalog } from './officialPluginCatalog.js';
|
|
6
7
|
import { findPluginRegistration, pluginDirectory } from './pluginRegistry.js';
|
|
7
8
|
const INSTALL_TIMEOUT_MS = 180_000;
|
|
@@ -60,7 +61,7 @@ function appendOutput(current, chunk) {
|
|
|
60
61
|
function installWithSetup(name) {
|
|
61
62
|
return new Promise((resolve, reject) => {
|
|
62
63
|
const command = process.platform === 'win32' ? 'npx.cmd' : 'npx';
|
|
63
|
-
const child = spawn(command, ['-y', '--@mearl:registry=https://registry.npmjs.org', `@mearl/setup@${CLIENT_VERSION}`, 'plugin', 'ensure', name], { stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true });
|
|
64
|
+
const child = spawn(command, ['-y', '--@mearl:registry=https://registry.npmjs.org', `@mearl/setup@${CLIENT_VERSION}`, 'plugin', 'ensure', name], { env: npmExecEnvironment(), stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true });
|
|
64
65
|
let stdout = '';
|
|
65
66
|
let stderr = '';
|
|
66
67
|
let settled = false;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type AppProfileContribution } from '@mearl/browser-core';
|
|
2
2
|
export declare class PluginError extends Error {
|
|
3
3
|
readonly code: string;
|
|
4
|
-
constructor(code: string, message: string);
|
|
4
|
+
constructor(code: string, message: string, options?: ErrorOptions);
|
|
5
5
|
}
|
|
6
6
|
export interface PluginToolboxSandboxPage {
|
|
7
7
|
type: 'sandbox';
|
|
@@ -9,6 +9,7 @@ import { buildPluginPageBundle, PLUGIN_PAGE_CHUNK_BYTES, PLUGIN_PAGE_RUNTIME_HAS
|
|
|
9
9
|
import { pluginFileVersion } from './pluginSource.js';
|
|
10
10
|
const RESERVED_NAMES = new Set([
|
|
11
11
|
'check',
|
|
12
|
+
'run',
|
|
12
13
|
'help',
|
|
13
14
|
'connector_list',
|
|
14
15
|
'capture_checkpoint',
|
|
@@ -17,8 +18,8 @@ const RESERVED_NAMES = new Set([
|
|
|
17
18
|
]);
|
|
18
19
|
export class PluginError extends Error {
|
|
19
20
|
code;
|
|
20
|
-
constructor(code, message) {
|
|
21
|
-
super(`${code}: ${message}
|
|
21
|
+
constructor(code, message, options) {
|
|
22
|
+
super(`${code}: ${message}`, options);
|
|
22
23
|
this.code = code;
|
|
23
24
|
}
|
|
24
25
|
}
|
|
@@ -405,8 +406,15 @@ export function findPluginRegistration(name) {
|
|
|
405
406
|
...(source ? { source } : {}),
|
|
406
407
|
};
|
|
407
408
|
}
|
|
408
|
-
catch {
|
|
409
|
-
|
|
409
|
+
catch (cause) {
|
|
410
|
+
const reason = cause instanceof SyntaxError
|
|
411
|
+
? 'JSON 格式错误'
|
|
412
|
+
: cause instanceof Error
|
|
413
|
+
? cause.message
|
|
414
|
+
: '未知校验错误';
|
|
415
|
+
throw new PluginError('PLUGIN_REGISTRY_INVALID', `无效的插件记录: ${file} (${reason})`, {
|
|
416
|
+
cause,
|
|
417
|
+
});
|
|
410
418
|
}
|
|
411
419
|
}
|
|
412
420
|
export function readPluginPageBundleChunk(name, hash, index) {
|
|
@@ -31,7 +31,7 @@ async function run(message) {
|
|
|
31
31
|
: message.access === 'toolbox'
|
|
32
32
|
? invokeRegisteredToolboxPlugin
|
|
33
33
|
: invokeRegisteredPlugin;
|
|
34
|
-
const declaration = message.describe
|
|
34
|
+
const declaration = message.describe || message.help
|
|
35
35
|
? await loadPlugin(message.entry, {
|
|
36
36
|
options: {},
|
|
37
37
|
progress: () => { },
|
|
@@ -63,11 +63,13 @@ async function run(message) {
|
|
|
63
63
|
const value = migration
|
|
64
64
|
? await migration.runMigration(message.invocation)
|
|
65
65
|
: declaration
|
|
66
|
-
?
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
66
|
+
? message.help
|
|
67
|
+
? declaration.help(message.help.namespace, message.help.command)
|
|
68
|
+
: {
|
|
69
|
+
pageRuntime: declaration.pageRuntime,
|
|
70
|
+
stateStorage: declaration.stateStorage,
|
|
71
|
+
taskRecovery: declaration.taskRecovery,
|
|
72
|
+
}
|
|
71
73
|
: message.model
|
|
72
74
|
? await (await import('@mearl/agent-runtime/codex')).runCodexModel(message.model, {
|
|
73
75
|
signal: controller.signal,
|
|
@@ -6,6 +6,11 @@ export interface PluginExecutorDependencies {
|
|
|
6
6
|
registration?: PluginRegistration;
|
|
7
7
|
}
|
|
8
8
|
export interface PluginExecutorOptions extends PluginInvokeOptions {
|
|
9
|
+
help?: {
|
|
10
|
+
namespace: string;
|
|
11
|
+
command?: string;
|
|
12
|
+
};
|
|
13
|
+
onOutput?: (stream: 'stdout' | 'stderr', chunk: Buffer) => void;
|
|
9
14
|
describe?: boolean;
|
|
10
15
|
model?: PluginModelRequest;
|
|
11
16
|
recovery?: boolean;
|
|
@@ -8,7 +8,7 @@ import { stopPluginProcessTree } from './pluginProcessTree.js';
|
|
|
8
8
|
import { processIdentity } from '@mearl/daemon-core';
|
|
9
9
|
/** Executes registered trusted code in a process whose lifetime belongs to this invocation. */
|
|
10
10
|
export async function executeRegisteredPlugin(plugin, invocation, context, options = {}, dependencies = {}) {
|
|
11
|
-
const { signal, onProgress, source, access = 'public', executionTimeoutMs, cancellationGraceMs = 1000, workerPath, cwd, environment, describe, model, recovery, migration, expectedRecovery, onExecutorStarted, onExecutorStopped, onDiagnostic, ...invokeOptions } = options;
|
|
11
|
+
const { signal, onProgress, source, access = 'public', executionTimeoutMs, cancellationGraceMs = 1000, workerPath, cwd, environment, describe, help, onOutput, model, recovery, migration, expectedRecovery, onExecutorStarted, onExecutorStopped, onDiagnostic, ...invokeOptions } = options;
|
|
12
12
|
for (const [name, value] of [
|
|
13
13
|
['executionTimeoutMs', executionTimeoutMs],
|
|
14
14
|
['cancellationGraceMs', cancellationGraceMs],
|
|
@@ -25,7 +25,7 @@ export async function executeRegisteredPlugin(plugin, invocation, context, optio
|
|
|
25
25
|
const entryVersion = pluginFileVersion(registration.entry);
|
|
26
26
|
return new Promise((resolve, reject) => {
|
|
27
27
|
const child = fork(workerPath ?? PLUGIN_WORKER_PATH, [], {
|
|
28
|
-
stdio: ['ignore', 'ignore', 'pipe', 'ipc'],
|
|
28
|
+
stdio: ['ignore', onOutput ? 'pipe' : 'ignore', 'pipe', 'ipc'],
|
|
29
29
|
serialization: 'advanced',
|
|
30
30
|
execArgv: [],
|
|
31
31
|
detached: process.platform !== 'win32',
|
|
@@ -46,6 +46,18 @@ export async function executeRegisteredPlugin(plugin, invocation, context, optio
|
|
|
46
46
|
child.stderr?.on('data', chunk => {
|
|
47
47
|
stderr = `${stderr}${chunk}`.slice(-65536);
|
|
48
48
|
});
|
|
49
|
+
if (onOutput) {
|
|
50
|
+
for (const stream of ['stdout', 'stderr']) {
|
|
51
|
+
child[stream]?.on('data', chunk => {
|
|
52
|
+
try {
|
|
53
|
+
onOutput(stream, Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
stop(error instanceof Error ? error : new Error(String(error)));
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
49
61
|
const send = (message) => {
|
|
50
62
|
if (!child.connected || exited)
|
|
51
63
|
return;
|
|
@@ -209,6 +221,7 @@ export async function executeRegisteredPlugin(plugin, invocation, context, optio
|
|
|
209
221
|
entryVersion,
|
|
210
222
|
access,
|
|
211
223
|
describe,
|
|
224
|
+
help,
|
|
212
225
|
model,
|
|
213
226
|
recovery,
|
|
214
227
|
migration,
|
|
@@ -13,6 +13,10 @@ export type PluginWorkerRequest = {
|
|
|
13
13
|
access: 'public' | 'toolbox' | 'runtime';
|
|
14
14
|
registration?: PluginRegistration;
|
|
15
15
|
describe?: boolean;
|
|
16
|
+
help?: {
|
|
17
|
+
namespace: string;
|
|
18
|
+
command?: string;
|
|
19
|
+
};
|
|
16
20
|
model?: PluginModelRequest;
|
|
17
21
|
recovery?: boolean;
|
|
18
22
|
migration?: boolean;
|
|
@@ -3,13 +3,14 @@ import { fileURLToPath } from 'node:url';
|
|
|
3
3
|
/** Ownership monitoring runs outside the event loop that executes plugin code. */
|
|
4
4
|
export function supervisePluginExecutor(workerUrl) {
|
|
5
5
|
const child = fork(fileURLToPath(workerUrl), ['--command'], {
|
|
6
|
-
stdio: ['ignore', '
|
|
6
|
+
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
|
|
7
7
|
serialization: 'advanced',
|
|
8
8
|
execArgv: [],
|
|
9
9
|
});
|
|
10
10
|
let ending = false;
|
|
11
11
|
let forwarded = Promise.resolve();
|
|
12
12
|
child.stderr?.on('data', chunk => process.stderr.write(chunk));
|
|
13
|
+
child.stdout?.on('data', chunk => process.stdout.write(chunk));
|
|
13
14
|
const terminate = () => {
|
|
14
15
|
if (process.platform === 'win32') {
|
|
15
16
|
try {
|