@mearl/client 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.
Files changed (74) hide show
  1. package/README.md +333 -255
  2. package/README.zh-CN.md +612 -0
  3. package/dist/actionTimeouts.js +0 -3
  4. package/dist/autoUpdate.js +3 -1
  5. package/dist/bin.js +12 -5
  6. package/dist/capabilityHelp.d.ts +4 -0
  7. package/dist/capabilityHelp.js +68 -0
  8. package/dist/check.d.ts +5 -6
  9. package/dist/check.js +2 -5
  10. package/dist/cli.js +29 -56
  11. package/dist/commandHelp.d.ts +3 -0
  12. package/dist/commandHelp.js +79 -0
  13. package/dist/commandSuggestions.d.ts +3 -0
  14. package/dist/commandSuggestions.js +16 -5
  15. package/dist/commands.d.ts +70 -65
  16. package/dist/commands.js +60 -55
  17. package/dist/guide.d.ts +46 -0
  18. package/dist/guide.js +80 -0
  19. package/dist/guides/api-browser-setup.md +93 -0
  20. package/dist/guides/api-page-automation.md +140 -0
  21. package/dist/guides/api-page-debugging.md +39 -0
  22. package/dist/guides/api-page-environment.md +37 -0
  23. package/dist/guides/api-request-debugging.md +54 -0
  24. package/dist/guides/browser-tool-cooperation.md +23 -0
  25. package/dist/guides/core.md +60 -0
  26. package/dist/guides/related-skills.md +51 -0
  27. package/dist/guides/scripting.md +21 -0
  28. package/dist/guides/troubleshooting.md +170 -0
  29. package/dist/index.d.ts +5 -2
  30. package/dist/index.js +8 -5
  31. package/dist/nativeHost.d.ts +2 -2
  32. package/dist/nativeHost.js +2 -4
  33. package/dist/plugins/clients/pluginHostConnection.d.ts +2 -0
  34. package/dist/plugins/clients/pluginHostConnection.js +3 -1
  35. package/dist/plugins/officialPluginInstaller.js +2 -1
  36. package/dist/plugins/pluginRegistry.d.ts +1 -1
  37. package/dist/plugins/pluginRegistry.js +21 -7
  38. package/dist/plugins/runtime/pluginCommandWorker.js +8 -6
  39. package/dist/plugins/runtime/pluginDiagnostics.js +1 -1
  40. package/dist/plugins/runtime/pluginExecutor.d.ts +5 -0
  41. package/dist/plugins/runtime/pluginExecutor.js +15 -2
  42. package/dist/plugins/runtime/pluginExecutorProtocol.d.ts +4 -0
  43. package/dist/plugins/runtime/pluginExecutorSupervisor.js +2 -1
  44. package/dist/plugins/runtime/pluginHostServer.js +5 -1
  45. package/dist/plugins/runtime/pluginPageManager.js +2 -6
  46. package/dist/plugins/runtime/pluginRevision.js +0 -51
  47. package/dist/plugins/runtime/pluginStateManager.js +1 -1
  48. package/dist/plugins/runtime/pluginStateStore.js +3 -8
  49. package/dist/plugins/runtime/pluginTaskManager.js +5 -9
  50. package/dist/plugins/sdk/plugin.d.ts +9 -0
  51. package/dist/plugins/sdk/plugin.js +22 -9
  52. package/dist/plugins/sdk/pluginModelDefinition.js +0 -6
  53. package/dist/plugins/sdk/pluginPageDefinition.d.ts +0 -1
  54. package/dist/plugins/sdk/pluginPageDefinition.js +2 -18
  55. package/dist/plugins/sdk/pluginRecoveryDefinition.js +0 -3
  56. package/dist/plugins/sdk/pluginStateDefinition.d.ts +0 -1
  57. package/dist/plugins/sdk/pluginStateDefinition.js +0 -11
  58. package/dist/runtimePaths.d.ts +1 -0
  59. package/dist/runtimePaths.js +1 -0
  60. package/dist/script.d.ts +30 -0
  61. package/dist/script.js +261 -0
  62. package/dist/scriptCli.d.ts +1 -0
  63. package/dist/scriptCli.js +94 -0
  64. package/dist/scriptErrors.d.ts +8 -0
  65. package/dist/scriptErrors.js +21 -0
  66. package/dist/scriptWorker.d.ts +1 -0
  67. package/dist/scriptWorker.js +50 -0
  68. package/dist/sdkMethods.d.ts +3 -0
  69. package/dist/sdkMethods.js +9 -0
  70. package/dist/socket.js +33 -8
  71. package/dist/unified.js +11 -1
  72. package/dist/unifiedConfig.d.ts +4 -0
  73. package/dist/unifiedConfig.js +11 -0
  74. package/package.json +18 -11
package/dist/commands.js CHANGED
@@ -1,6 +1,4 @@
1
- import { APP_PROFILE_NAMES, BROWSER_DEVICE_PRESET_NAMES, } from '@mearl/browser-core';
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 与可用观察或最小快照核验,避免重复提交。失败以退出码 1 结束。',
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: '获取最近的网络请求(mtop 或普通 xhr/fetch)',
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: '"mtop" | "requests" | "all"',
111
- description: '数据来源,不填时默认 mtop;all 返回全部业务请求',
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 桥代发的 MTop SSE 都归入 mtop。无法归属当前页面 target 的 Service Worker 请求不在采集范围内。',
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":"mtop","filter":"cart"}'`,
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":"mtop.cart.query","mockData":{"ret":["SUCCESS::调用成功"]}}'`,
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,不自动弹窗。可在请求规则页面授权,或按提示调用 request_domain_permission。复杂 URL 表达式无法完整推断域名时会提示手动检查。',
306
+ '扩展模式会检查规则请求 URL 和显式来源域名的访问权限;缺失时仍保存规则,返回 warnings 和 missingOrigins,不自动弹窗。可在请求规则页面授权,或按提示调用 request_permission。复杂 URL 表达式无法完整推断域名时会提示手动检查。',
302
307
  ],
303
308
  examples: [
304
309
  `set_rule --payload '{"actionType":"block","filter":"^https://example\\\\.com/ads/.*"}'`,
@@ -363,33 +368,16 @@ export const COMMANDS = [
363
368
  `send_request --payload '{"url":"https://api.example.com/upload","method":"POST","bodyFile":{"filePath":"/absolute/path/image.png","contentType":"image/png"}}'`,
364
369
  ],
365
370
  },
366
- {
367
- name: 'send_mtop_request',
368
- description: '使用目标浏览器 Cookie 发起 mtop 请求,自动处理签名和 token',
369
- params: [
370
- { name: 'api', type: 'string', required: true, description: 'mtop API 名称' },
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' },
377
- ],
378
- notes: [
379
- '需要目标浏览器有对应登录态;Mearl 自动处理签名,不依赖页面脚本。api 以 mopen. 开头时使用 mopen 协议。',
380
- 'env=prod 使用 h5api.m.taobao.com,pre 使用 h5api.wapa.taobao.com。',
381
- ],
382
- result: ['返回 success、response、requestData;业务成功需检查 response.ret。'],
383
- examples: [
384
- `send_mtop_request --payload '{"api":"mtop.trade.order.detail","data":{"orderId":"123"}}'`,
385
- ],
386
- },
387
371
  // ── 浏览器 ────────────────────────────────────────────────────────────────
388
372
  {
389
373
  name: 'browser_list',
390
374
  description: '列出所有浏览器及其连接状态、类型和 Provider 托管实例信息',
391
375
  summary: '列出本地及远端浏览器与连接状态',
392
- examples: ['browser_list'],
376
+ params: [
377
+ { name: 'provider', type: 'string', description: '配合 launchForm,仅查询一个本机已安装 Provider 的启动候选;需 --local' },
378
+ { name: 'launchForm', type: 'object', description: '现有动态启动表单请求:{variant?,values:{}},不创建或接入实例' },
379
+ ],
380
+ examples: ['browser_list', 'browser_list --local'],
393
381
  },
394
382
  {
395
383
  name: 'browser_release',
@@ -496,6 +484,9 @@ export const COMMANDS = [
496
484
  name: 'tab_open',
497
485
  description: '打开或按 URL 规则复用 Tab,并等待新页面加载完成',
498
486
  aliases: ['tab_new', 'new_tab', 'tab_create', 'create_tab'],
487
+ aliasExamples: {
488
+ tab_activate: `tab_open --payload '{"url":"https://example.com","reuse":"require","active":true}'`,
489
+ },
499
490
  params: [
500
491
  { name: 'url', type: 'string', required: true, description: '要打开的 URL' },
501
492
  {
@@ -541,7 +532,7 @@ export const COMMANDS = [
541
532
  {
542
533
  name: 'appProfile',
543
534
  type: 'string',
544
- description: '按已安装档案应用 App 环境;内置基础档案只提供 UA/版本,完整桥由能力包提供。需要 iframe WebView 和系统栏时同时传 emulation.deviceShell=true',
535
+ description: '按已安装档案应用 App 环境,ID 与限制见当前动态帮助。需要 iframe WebView 和系统栏时同时传 emulation.deviceShell=true',
545
536
  },
546
537
  {
547
538
  name: 'os',
@@ -567,9 +558,9 @@ export const COMMANDS = [
567
558
  `tab_open --payload '{"url":"https://example.com"}'`,
568
559
  `tab_open --payload '{"url":"https://example.com/page","reuse":"prefer","match":{"ignoreSearch":true}}'`,
569
560
  `tab_open --payload '{"url":"https://m.example.com","emulation":{"preset":"iphone-17-pro"}}'`,
570
- `tab_open --payload '{"url":"https://example.com/app/home","appProfile":"fliggy"}'`,
571
- `tab_open --payload '{"url":"https://example.com/app/home","appProfile":"fliggy","emulation":{"preset":"ipad-mini-a17-pro","orientation":"landscape","deviceShell":true,"splitScreen":true}}'`,
572
- `tab_open --payload '{"url":"https://example.com","appProfile":"fliggy","os":"android"}'`,
561
+ `tab_open --payload '{"url":"https://example.com/app/home","appProfile":"reader"}'`,
562
+ `tab_open --payload '{"url":"https://example.com/app/home","appProfile":"reader","emulation":{"preset":"ipad-mini-a17-pro","orientation":"landscape","deviceShell":true,"splitScreen":true}}'`,
563
+ `tab_open --payload '{"url":"https://example.com","appProfile":"reader","os":"android"}'`,
573
564
  `tab_open --payload '{"url":"https://example.com","group":"验证任务"}'`,
574
565
  ],
575
566
  },
@@ -613,6 +604,9 @@ export const COMMANDS = [
613
604
  {
614
605
  name: 'page_click',
615
606
  description: '点击页面元素,支持 CSS/@ref、可见文本或视口坐标定位',
607
+ aliasExamples: {
608
+ page_select: `page_click --payload '{"tabId":12345,"text":"选项文案","role":"option"}'`,
609
+ },
616
610
  params: [
617
611
  {
618
612
  name: 'selector',
@@ -666,7 +660,8 @@ export const COMMANDS = [
666
660
  result: PAGE_ACTION_RESULT,
667
661
  notes: [
668
662
  'selector / text / point 必须且只能提供一个。隐藏页 auto 使用 DOM;只有明确依赖真实用户手势时才激活页面。',
669
- '原生 select 可按 option 文本点击;checkbox/radio 返回 controlState.checkedBefore/checkedAfter。',
663
+ 'auto 对原生 option、checkbox/radio 使用状态感知的 DOM 路径;显式 mouse/touch 保留可信输入。',
664
+ '原生 select 可按 option 文本点击;auto/dom 返回 selectionState.valueBefore/valueAfter/selectedAfter,检查选中状态是否保持。checkbox/radio 返回 controlState.checkedBefore/checkedAfter。',
670
665
  ],
671
666
  examples: [
672
667
  `page_click --payload '{"tabId":12345,"text":"提交"}'`,
@@ -721,6 +716,9 @@ export const COMMANDS = [
721
716
  {
722
717
  name: 'page_type',
723
718
  description: '向输入框填写文本,兼容 React 受控组件',
719
+ aliasExamples: {
720
+ page_fill: `page_type --payload '{"tabId":12345,"selector":"@e6","text":"填写内容","clearFirst":true}'`,
721
+ },
724
722
  params: [
725
723
  {
726
724
  name: 'selector',
@@ -906,6 +904,8 @@ export const COMMANDS = [
906
904
  description: '按键名称:Enter/Tab/Escape/Backspace 等',
907
905
  },
908
906
  { name: 'modifiers', type: 'string[]', description: '修饰键数组:ctrl/alt/shift/meta/cmd' },
907
+ { name: 'dialogId', type: 'string', description: '原生弹窗回执或 page_snapshot 中的 dialog.id;仅配合 Enter 接受或 Escape 取消' },
908
+ { name: 'promptText', type: 'string', description: '仅用于 dialogId + Enter 接受原生 prompt 时填写文本' },
909
909
  {
910
910
  name: 'pressMode',
911
911
  type: '"auto" | "dom" | "keyboard"',
@@ -917,6 +917,7 @@ export const COMMANDS = [
917
917
  ],
918
918
  notes: [
919
919
  '隐藏页 DOM 模式支持 Tab 焦点移动、原生控件 Enter/Space 激活和输入框 Enter 提交;编辑、选择、方向键和页面滚动等原生行为需可见页与 pressMode=keyboard。',
920
+ '原生 alert/confirm/prompt/beforeunload 弹窗需显式传 dialogId;普通 Enter 不处理弹窗。弹窗处理绕过 DOM 观察,不自动重放被中断的动作;处理后重新读取页面。',
920
921
  ],
921
922
  result: [
922
923
  ...PAGE_ACTION_RESULT,
@@ -956,6 +957,7 @@ export const COMMANDS = [
956
957
  ],
957
958
  notes: [
958
959
  'time / selector / text / condition 必须且只能提供一个;time 范围 0–60000ms。页面交互已有内置观察,仅在需要独立等待条件时使用。',
960
+ '等待后须立即执行已知动作时,用 mearl run 在同一脚本中 await pageWait 后紧接 pageClick,避免模型往返。整体 --timeout 须覆盖等待及后续动作;等待失败不继续点击。',
959
961
  ],
960
962
  examples: [
961
963
  `page_wait --payload '{"tabId":12345,"time":1000}'`,
@@ -968,6 +970,9 @@ export const COMMANDS = [
968
970
  {
969
971
  name: 'page_navigate',
970
972
  description: '在当前标签页内导航到 URL、刷新页面,或沿浏览历史后退/前进',
973
+ aliasExamples: {
974
+ page_reload: `page_navigate --payload '{"tabId":12345,"refresh":true}'`,
975
+ },
971
976
  params: [
972
977
  {
973
978
  name: 'url',
@@ -1167,14 +1172,14 @@ export const COMMANDS = [
1167
1172
  },
1168
1173
  {
1169
1174
  name: 'set_app_profile',
1170
- description: '设置已安装的 App 档案;完整 JSBridge 由能力包提供。可同时设置 MTop 页面接口环境,传 emulation 时联动设备模拟',
1175
+ description: '设置已安装的 App 档案;完整 JSBridge 由能力包提供。可同时设置已安装的网络控件,传 emulation 时联动设备模拟',
1171
1176
  summary: '设置或清除目标标签页的 App 容器模拟',
1172
1177
  params: [
1173
1178
  { name: 'enabled', type: 'boolean', required: true, description: 'true=启用,false=清除' },
1174
1179
  {
1175
1180
  name: 'profile',
1176
1181
  type: 'string',
1177
- description: `容器档案名(enabled=true 时必填);内置 ${APP_PROFILE_NAME_LIST}`,
1182
+ description: '已安装的容器档案 ID(enabled=true 时必填);当前动态帮助直接展示目标浏览器目录',
1178
1183
  },
1179
1184
  { name: 'os', type: '"ios" | "android"', description: '容器系统,默认 ios' },
1180
1185
  {
@@ -1199,9 +1204,9 @@ export const COMMANDS = [
1199
1204
  description: '声明式覆盖桥方法,形如 {methods:{api:{behavior|response|noop,silent?}}};不执行配置脚本',
1200
1205
  },
1201
1206
  {
1202
- name: 'mtopEnv',
1203
- type: '"default" | "prod" | "pre"',
1204
- description: '可选 MTop 页面接口环境;default 关闭环境改写,省略时保持当前设置。仅作用于目标 tab',
1207
+ name: 'networkControl',
1208
+ type: 'object | null',
1209
+ description: '可选已安装网络控件 {id,value};null 清除,省略时保持当前设置。仅作用于目标 tab',
1205
1210
  },
1206
1211
  {
1207
1212
  name: 'emulation',
@@ -1217,15 +1222,15 @@ export const COMMANDS = [
1217
1222
  'bridgeConfig.methods 按方法声明 behavior / response / noop 三选一,可传 silent;只支持受控行为、固定 JSON 回包或成功空实现,不执行配置脚本。',
1218
1223
  ],
1219
1224
  result: [
1220
- '返回 enabled、profile、label、userAgent、os、mtopEnv、reloaded;联动设备时额外返回实际 emulation。',
1225
+ '返回 enabled、profile、label、userAgent、os、networkControl、reloaded;联动设备时额外返回实际 emulation。',
1221
1226
  ],
1222
1227
  examples: [
1223
- `set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"fliggy"}'`,
1224
- `set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"fliggy","mtopEnv":"pre"}'`,
1225
- `set_app_profile --payload '{"tabId":12345,"enabled":false,"mtopEnv":"prod"}'`,
1226
- `set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"fliggy","emulation":{}}'`,
1227
- `set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"alipay","emulation":{"preset":"pixel-11","deviceShell":true}}'`,
1228
- `set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"fliggy","emulation":{"preset":"ipad-mini-a17-pro","orientation":"landscape","deviceShell":true,"splitScreen":true}}'`,
1228
+ `set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"reader"}'`,
1229
+ `set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"reader","networkControl":{"id":"environment","value":"pre"}}'`,
1230
+ `set_app_profile --payload '{"tabId":12345,"enabled":false,"networkControl":null}'`,
1231
+ `set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"reader","emulation":{}}'`,
1232
+ `set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"wallet","emulation":{"preset":"pixel-11","deviceShell":true}}'`,
1233
+ `set_app_profile --payload '{"tabId":12345,"enabled":true,"profile":"reader","emulation":{"preset":"ipad-mini-a17-pro","orientation":"landscape","deviceShell":true,"splitScreen":true}}'`,
1229
1234
  `set_app_profile --payload '{"tabId":12345,"enabled":false}'`,
1230
1235
  `set_app_profile --payload '{"tabId":12345,"enabled":false,"emulation":{}}'`,
1231
1236
  ],
@@ -1280,9 +1285,9 @@ export const COMMANDS = [
1280
1285
  result: ['找到时 found=true 并返回 value/domain/path;不存在时 found=false。'],
1281
1286
  examples: [
1282
1287
  `get_cookie --payload '{"tabId":12345,"name":"feature_flag"}'`,
1283
- `get_cookie --payload '{"url":"https://www.taobao.com/","name":"tracknick"}'`,
1288
+ `get_cookie --payload '{"url":"https://www.shop.com/","name":"account_name"}'`,
1284
1289
  `get_cookie --payload '{"tabId":12345,"name":"feature_channel","domain":"example.com"}'`,
1285
- `get_cookie --payload '{"tabId":12345,"name":"tracknick","url":"https://www.taobao.com/","domain":"example.com","path":"/"}'`,
1290
+ `get_cookie --payload '{"tabId":12345,"name":"account_name","url":"https://www.shop.com/","domain":"example.com","path":"/"}'`,
1286
1291
  ],
1287
1292
  },
1288
1293
  {
@@ -1327,7 +1332,7 @@ export const COMMANDS = [
1327
1332
  result: ['返回 url/name/domain/path/reloaded,指定标签页时包含 tabId;不回显 Cookie 值。'],
1328
1333
  examples: [
1329
1334
  `set_cookie --payload '{"tabId":12345,"name":"feature_flag","value":"enabled"}'`,
1330
- `set_cookie --payload '{"url":"https://www.taobao.com/","name":"feature_flag","value":"enabled"}'`,
1335
+ `set_cookie --payload '{"url":"https://www.shop.com/","name":"feature_flag","value":"enabled"}'`,
1331
1336
  `set_cookie --payload '{"tabId":12345,"name":"feature_channel","value":"3.6.63","domain":"example.com","reload":true}'`,
1332
1337
  ],
1333
1338
  },
@@ -1342,7 +1347,7 @@ export const COMMANDS = [
1342
1347
  examples: [`page_frames --payload '{"tabId":12345}'`],
1343
1348
  },
1344
1349
  {
1345
- name: 'request_domain_permission',
1350
+ name: 'request_permission',
1346
1351
  description: '申请访问指定域名的权限(必要时弹窗让用户授权)',
1347
1352
  params: [
1348
1353
  {
@@ -1357,7 +1362,7 @@ export const COMMANDS = [
1357
1362
  '弹窗等待用户选择,90 秒超时或关闭按拒绝处理;granted=true 后才重试原请求。',
1358
1363
  ],
1359
1364
  result: ['返回 granted、domain,授权成功时包含 origin。'],
1360
- examples: [`request_domain_permission --payload '{"domain":"example.com"}'`],
1365
+ examples: [`request_permission --payload '{"domain":"example.com"}'`],
1361
1366
  },
1362
1367
  // ── 组合调用 ────────────────────────────────────────────────────────────────
1363
1368
  {
@@ -0,0 +1,46 @@
1
+ /** One catalog drives CLI navigation and the build-time resource copy. */
2
+ export declare const GUIDE_TOPICS: readonly [{
3
+ readonly id: "core";
4
+ readonly file: "core.md";
5
+ readonly title: "核心工作流与按需导航";
6
+ }, {
7
+ readonly id: "automation";
8
+ readonly file: "api-page-automation.md";
9
+ readonly title: "控件、文件、弹窗与结果判读";
10
+ }, {
11
+ readonly id: "run";
12
+ readonly file: "scripting.md";
13
+ readonly title: "SDK、代码组合、超时与不确定结果";
14
+ }, {
15
+ readonly id: "debugging";
16
+ readonly file: "api-page-debugging.md";
17
+ readonly title: "布局、遮挡、iframe 与视觉验证";
18
+ }, {
19
+ readonly id: "environment";
20
+ readonly file: "api-page-environment.md";
21
+ readonly title: "设备、App、时区与 Cookie";
22
+ }, {
23
+ readonly id: "diagnostics";
24
+ readonly file: "api-request-debugging.md";
25
+ readonly title: "接口、日志、埋点、权限与 Mock";
26
+ }, {
27
+ readonly id: "browsers";
28
+ readonly file: "api-browser-setup.md";
29
+ readonly title: "目标、会话、远端与 Provider";
30
+ }, {
31
+ readonly id: "cooperation";
32
+ readonly file: "browser-tool-cooperation.md";
33
+ readonly title: "与其他浏览器工具协作";
34
+ }, {
35
+ readonly id: "skills";
36
+ readonly file: "related-skills.md";
37
+ readonly title: "专用 Skill 使用与安装";
38
+ }, {
39
+ readonly id: "troubleshooting";
40
+ readonly file: "troubleshooting.md";
41
+ readonly title: "安装、连接与环境排查";
42
+ }];
43
+ export declare function renderGuideLinks(source: string, commandName?: string): string;
44
+ /** Only packaged files are read; unknown IDs never become filesystem paths. */
45
+ export declare function readGuide(id: string, commandName?: string, version?: string): Promise<string>;
46
+ export declare function runGuideCli(args: string[], commandName?: string, version?: string): Promise<number>;
package/dist/guide.js ADDED
@@ -0,0 +1,80 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { CLIENT_VERSION } from './runtimePaths.js';
3
+ /** One catalog drives CLI navigation and the build-time resource copy. */
4
+ export const GUIDE_TOPICS = [
5
+ { id: 'core', file: 'core.md', title: '核心工作流与按需导航' },
6
+ { id: 'automation', file: 'api-page-automation.md', title: '控件、文件、弹窗与结果判读' },
7
+ { id: 'run', file: 'scripting.md', title: 'SDK、代码组合、超时与不确定结果' },
8
+ { id: 'debugging', file: 'api-page-debugging.md', title: '布局、遮挡、iframe 与视觉验证' },
9
+ { id: 'environment', file: 'api-page-environment.md', title: '设备、App、时区与 Cookie' },
10
+ { id: 'diagnostics', file: 'api-request-debugging.md', title: '接口、日志、埋点、权限与 Mock' },
11
+ { id: 'browsers', file: 'api-browser-setup.md', title: '目标、会话、远端与 Provider' },
12
+ { id: 'cooperation', file: 'browser-tool-cooperation.md', title: '与其他浏览器工具协作' },
13
+ { id: 'skills', file: 'related-skills.md', title: '专用 Skill 使用与安装' },
14
+ { id: 'troubleshooting', file: 'troubleshooting.md', title: '安装、连接与环境排查' },
15
+ ];
16
+ export function renderGuideLinks(source, commandName = 'mearl') {
17
+ return source.replace(/\[([^\]\n]+)\]\(([^)\s]+)\)/g, (original, label, href) => {
18
+ if (/^[a-z][a-z0-9+.-]*:/i.test(href) || href.startsWith('#'))
19
+ return original;
20
+ const [file, section] = href.replace(/^\.\//, '').split('#');
21
+ const topic = GUIDE_TOPICS.find(topic => topic.file === file);
22
+ if (!topic)
23
+ throw new Error(`指南包含未打包的本地链接:${href}`);
24
+ return `${label}(\`${commandName} guide ${topic.id}\`${section ? `,小节 \`${section}\`` : ''})`;
25
+ });
26
+ }
27
+ /** Only packaged files are read; unknown IDs never become filesystem paths. */
28
+ export async function readGuide(id, commandName = 'mearl', version = CLIENT_VERSION) {
29
+ const topic = GUIDE_TOPICS.find(topic => topic.id === id);
30
+ if (!topic)
31
+ throw new Error(`未知指南主题:${id}。用 ${commandName} guide --list 查看主题。`);
32
+ let source;
33
+ try {
34
+ source = readFileSync(new URL(`./guides/${topic.file}`, import.meta.url), 'utf8');
35
+ }
36
+ catch (error) {
37
+ throw new Error(`当前安装缺少指南资源:${topic.id}。请通过当前发行版的安装入口修复安装包;参数可用 ${commandName} <action> --help 查询。`, { cause: error });
38
+ }
39
+ let management;
40
+ if (source.includes('{{setup}}')) {
41
+ const { readInstallationManagement, setupManagementCommand } = await import('@mearl/daemon-core/installation');
42
+ const installed = await readInstallationManagement();
43
+ const command = setupManagementCommand(installed.setup ?? { package: '@mearl/setup', version: 'beta' });
44
+ source = source.replaceAll('{{setup}}', command);
45
+ management = installed.source ? `管理入口:${command};沿用本机已选 preset。` : `首次安装入口:${command};本机尚未选择 preset,组织发行环境使用其首次安装指引。`;
46
+ }
47
+ return [
48
+ `[mearl:guide] CLI ${version} · ${topic.id}`,
49
+ '本指南随 CLI 分发;扩展、远端宿主与已安装能力仍须按目标实际帮助核验。',
50
+ ...(management ? [management] : []),
51
+ '',
52
+ renderGuideLinks(source.trim(), commandName),
53
+ '',
54
+ `其他主题:${commandName} guide --list;具体参数:${commandName} <action> --help。`,
55
+ `[mearl:guide] end ${topic.id}`,
56
+ ].join('\n');
57
+ }
58
+ export async function runGuideCli(args, commandName = 'mearl', version = CLIENT_VERSION) {
59
+ const list = () => GUIDE_TOPICS.map(topic => ` ${topic.id.padEnd(18)}${topic.title}`).join('\n');
60
+ if (args.length === 1 && (args[0] === '--help' || args[0] === '-h')) {
61
+ console.log(`${commandName} guide — CLI ${version}\n\n用法:${commandName} guide [topic]\n ${commandName} guide --list\n\n默认只读 core;按需读取单个专题。只读本地资源,不连接浏览器或检查更新。\n\n${list()}`);
62
+ return 0;
63
+ }
64
+ if (args.length === 1 && args[0] === '--list') {
65
+ console.log(`${commandName} guide — CLI ${version}\n${list()}`);
66
+ return 0;
67
+ }
68
+ if (args.length > 1 || args[0]?.startsWith('-') || !GUIDE_TOPICS.some(topic => topic.id === (args[0] ?? 'core'))) {
69
+ console.error(`未知指南主题或选项:${args.join(' ')}。用 ${commandName} guide --list 查看主题。`);
70
+ return 2;
71
+ }
72
+ try {
73
+ console.log(await readGuide(args[0] ?? 'core', commandName, version));
74
+ return 0;
75
+ }
76
+ catch (error) {
77
+ console.error(error instanceof Error ? error.message : String(error));
78
+ return 1;
79
+ }
80
+ }
@@ -0,0 +1,93 @@
1
+ # Mearl API 场景:浏览器初始化与管理
2
+
3
+ 需要管理控制会话、选择远端 connector、在同一 connector 下选择浏览器,或列出、启动、关闭、释放普通及 Provider 托管浏览器实例时读取本文件。设备、时区和 Cookie 操作见 [页面测试环境准备](./api-page-environment.md)。
4
+
5
+ ## 目录
6
+
7
+ - [浏览器实例](#browser-instances)
8
+ - [控制会话与人工交接](#control-sessions)
9
+ - [目标宿主与高级路由参数](#cloud-connectors)
10
+ - [可选浏览器 Provider](#browser-providers)
11
+
12
+ <a id="browser-instances"></a>
13
+
14
+ ## 浏览器实例
15
+
16
+ `browser_list` 返回普通浏览器和 Provider 托管浏览器。顶层包含 `count`、`connectedCount`、`defaultBrowserId`、`browsers`,部分来源发现失败时还会返回 `warnings`。公共字段包括 `browserId`、`name`、`type` 和 `status`:
17
+
18
+ - `type` 为 `regular` 或 `managed`。
19
+ - `status` 为 `connected`、`pairing`、`running_disconnected` 或 `stopped`;只有 `connected` 可作为页面操作目标。
20
+ - Provider 实例还会返回 `provider`、`ownership`、`persistence`、`operations`、`references`、`details` 和可选的 `pairing`。用 `operations` 判断当前可执行的生命周期操作。
21
+
22
+ `browser_launch` 默认启动本地独立 Chrome。外部 Provider 使用以下通用结构,具体 `providerOptions` 必须通过 `mearl <providerId>` 查询:
23
+
24
+ ```bash
25
+ mearl browser_launch --payload '{"provider":"<providerId>","providerOptions":{}}'
26
+ ```
27
+
28
+ 本机与远端 connector 同时存在时,用 `--local`、`--connector <id|name>`,或用 `--browser <global-id>` 同时指定宿主和 Cookie/UA 的来源浏览器。启动响应中的全局 `browserId` 用于首次操作和交付;建立控制会话后,后续操作由 `--session` 固定目标,无会话时继续传选定的 `--browser`。
29
+
30
+ `browser_close` 关闭托管实例;`deleteProfile: true` 表示同时删除 Provider 持久化数据。是否支持关闭、删除、启动、同步 Cookie、detach 或访问入口,以实例的 `operations` 和 Provider 命令帮助为准。
31
+
32
+ 不带 `--session` 的 `browser_release` 通过 `--browser <id|名称>` 选择普通浏览器,只在用户明确要求结束调试、退出接管或清理环境时调用。它会释放 debugger/CDP 控制,清理依赖当前调试连接的 Mock、设备/时区模拟与持续采集,保留浏览器和标签页;存在活动控制会话时拒绝浏览器级释放。用户要求的终态依赖这些效果时保持控制。会话任务的收尾见[控制会话](#control-sessions);Provider 的 detach 或其他收尾遵循 `mearl <providerId>`。
33
+
34
+ 浏览器访问入口不会出现在 `browser_list` 中。只有用户明确需要时才运行 `mearl check --browser <id|名称>`,并把返回的 `browserAccess.url` 按敏感信息处理,不写入日志或转发给无关方。
35
+
36
+ <a id="control-sessions"></a>
37
+
38
+ ## 控制会话与人工交接
39
+
40
+ 扩展免打扰默认开启;`tab_open active:true` 为 HTTP(S) 页面启用后台焦点模拟,新页在首次导航前生效,不切换标签页或窗口。关闭免打扰后,`active:true` 才会真实激活并恢复最小化窗口。普通页面操作不会自动启用模拟。`activation.mode` 区分 `background` / `foreground`;模拟后的 `document.visibilityState` 可为 `visible`,不能据此判断窗口在前台。交给用户、释放控制或扩展连接断开时恢复,`preserveEnvironment` 不保留此临时状态;交还后按需用 `reuse:"require", active:true` 再次激活。未带会话时通过 `browser_release` 清理。纯 CDP 和外部 Provider 沿用各自激活能力。
41
+
42
+ 首次 `tab_open` / `page_snapshot` / `page_screenshot` 传 `--session new`,后续命令传 `--session <sessionId>`,使用响应的完整 `session.sessionId`。会话绑定浏览器与传输,页面操作同时指定 `tabId`;仅支持视觉感知的 Provider 可从截图建立会话。
43
+
44
+ 扩展新建的后台页面默认进入折叠的 `Mearl` 标签组,前台新页进入展开的 `Mearl · 待操作` 组;两个管理组复用同一个已有窗口,页面打开的后续标签继承源组状态。复用用户的普通页面保留原窗口和分组,`tab_open.group` 可指定其他分组。接管时会话内的管理页移入待操作组,交还后收回 `Mearl` 组;用户正在查看组内其他页面或窗口没有其他页面时保留展开状态。纯 CDP 和外部 Provider 沿用各自的页面组织方式。
45
+
46
+ 常规响应的 session 只包含 ID、浏览器、传输、状态、代次和可选 reason,不重复标签页清单。页面列表用 tab_list 查询;browser_control 的交接结果还包含会话页面的 tabs。CLI、SDK、MCP 使用同一结构。
47
+
48
+ 会话自动记录新建与复用页面,串行执行同页面操作,并阻止其他会话或无会话调用占用其页面。不同任务使用独立会话;会话不隔离 Cookie 与存储,账号或浏览器共享资源冲突时使用独立浏览器。Extension、CDP 和采用 Mearl 控制的 Provider 共用这些规则;声明外部控制的 Provider(如 Ego)拒绝 Mearl 会话,交接和收尾沿用原工具。
49
+
50
+ `browser_control` 的 `operation:"handoff"` 将控制权交给用户,`tabId` 指定会话页面,`reason` 说明需要用户处理的事项。用户在 Mearl Popup 浏览器管理页接管和交还;无扩展 UI 的环境,在用户明确确认交还后调用 `operation:"resume"`。
51
+
52
+ - `CONTROL_SESSION_PAUSED`:停止派发动作,交还后重新快照或截图,根据当前状态继续,不重放未完成批次;已派发的操作可能仍然生效。
53
+ - `CONTROL_SESSION_NOT_FOUND`:会话不存在或已失效,在原浏览器以普通调用执行 `tab_list`,获取当前 `tabId` 并检查操作结果,再按任务需要建立新会话,避免重复写操作。
54
+
55
+ 任务结束调用 `browser_release --session <sessionId>`,释放该会话的控制归属并清理临时文件,默认保留页面、Mock 与模拟环境。payload 支持以下保留与清理选项:
56
+
57
+ | 参数 | 行为 |
58
+ | --- | --- |
59
+ | `closeCreatedTabs:true` | 关闭确认不再需要的会话新建页;复用的用户页面始终保留 |
60
+ | `keepTabIds` | 配合关闭新建页时保留结果页面 |
61
+ | `preserveEnvironment:false` | 清理会话页面的 Mock 与模拟环境 |
62
+ | `keepArtifactIds` | 保留指定浏览器文件产物,其他会话临时文件清理 |
63
+
64
+ 会话释放保留 Provider 实例;关闭、退出接管和同步 Cookie 使用原有实例操作,存在活动控制会话时先释放所属会话。
65
+
66
+ <a id="cloud-connectors"></a>
67
+
68
+ ## 目标宿主与高级路由参数
69
+
70
+ 默认不传宿主、连接或传输覆盖参数。`browser_list` 会同时查询当前机器和全部远端 connector,结果名称带机器前缀,`source` 包含远端机器的 `connectorId` 和 `connectorName`,全局 `browserId` 可跨 CLI 调用并自动选择本地或远端传输。需要指定目标时优先传这个全局 ID;完整实例名称跨来源唯一时也可由客户端解析。建立控制会话后,后续 action 只需传 `--session <sessionId>` 和页面参数。不要依赖名称片段的模糊匹配。
71
+
72
+ | 参数 | 作用 | 使用时机 |
73
+ | --- | --- | --- |
74
+ | `--local` | 只使用当前机器 | 限定本机清单、检查,或让 `browser_launch` 落到本机 |
75
+ | `--connector <id\|name>` | 只使用一台远端 connector | 限定远端清单、检查或启动宿主;名称或 ID 片段必须唯一 |
76
+ | `--cdp` | 本机强制使用 CDP,并隐含 `--local` | 需要验证或绕过 Extension 控制链路时 |
77
+ | `--server <url>` | 覆盖当前调用使用的 cloud-server URL | 自动配置不可用或临时排障时 |
78
+
79
+ `--local` / `--cdp` 不能与 `--connector` 同时使用。全局远端 `browserId` 已包含 connector,普通页面 action 不重复传 `--connector`。`--server` 的解析顺序见 `mearl check --help`,连接排障见[环境安装与连接排查](./troubleshooting.md#cloud-agent)。高级诊断命令 `mearl connector_list` 只用于查看没有可列出浏览器的 connector,普通浏览器操作无需先调用它。
80
+
81
+ <a id="browser-providers"></a>
82
+
83
+ ## 可选浏览器 Provider
84
+
85
+ Provider 的参数、配置和生命周期随独立包演进,Skill 只保留能力与安装入口。安装后必须读取 Provider 自带的当前帮助,不从本文件推断字段。
86
+
87
+ 支持的平台和设备来源以已安装 Provider 的能力声明及配套 Skill 为准。
88
+
89
+ 只询问能力或配置时不创建实例。执行任务前先运行 `mearl browser_list`:已有符合目标且 `status: "connected"` 的实例时直接复用;需要创建、配对、接入或收尾时,遵循对应 Provider 命令帮助。实例返回的全局 `browserId` 用于选择目标,无会话时后续统一页面 action 继续使用该 ID。
90
+
91
+ 用户只要求移动视口、移动 UA、触摸事件或机型样式时使用设备模拟,无需创建外部 Provider 实例。通过 connector 接入远端浏览器属于控制链路,平台实例由对应 Provider 管理。
92
+
93
+ 已有 Ego 任务的接入、只读候选查询及页面目标映射见[与其他浏览器工具协作](./browser-tool-cooperation.md)。该流程仅查询明确选择的本机 Provider,不广播查询全部来源。