@mearl/client 3.0.0-beta.3 → 3.0.0-beta.5

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 (46) hide show
  1. package/README.md +94 -15
  2. package/dist/check.d.ts +5 -6
  3. package/dist/check.js +3 -6
  4. package/dist/cli.js +15 -43
  5. package/dist/commandHelp.d.ts +3 -0
  6. package/dist/commandHelp.js +79 -0
  7. package/dist/commands.d.ts +24 -14
  8. package/dist/commands.js +23 -18
  9. package/dist/index.d.ts +3 -0
  10. package/dist/index.js +4 -0
  11. package/dist/nativeHost.js +1 -1
  12. package/dist/plugins/clients/pluginHostConnection.d.ts +2 -0
  13. package/dist/plugins/clients/pluginHostConnection.js +3 -1
  14. package/dist/plugins/pluginRegistry.d.ts +1 -1
  15. package/dist/plugins/pluginRegistry.js +12 -4
  16. package/dist/plugins/runtime/pluginCommandWorker.js +8 -6
  17. package/dist/plugins/runtime/pluginExecutor.d.ts +5 -0
  18. package/dist/plugins/runtime/pluginExecutor.js +15 -2
  19. package/dist/plugins/runtime/pluginExecutorProtocol.d.ts +4 -0
  20. package/dist/plugins/runtime/pluginExecutorSupervisor.js +2 -1
  21. package/dist/plugins/runtime/pluginHostServer.js +4 -0
  22. package/dist/plugins/runtime/pluginPageManager.js +0 -4
  23. package/dist/plugins/runtime/pluginRevision.js +0 -51
  24. package/dist/plugins/runtime/pluginStateStore.js +3 -8
  25. package/dist/plugins/runtime/pluginTaskManager.js +3 -7
  26. package/dist/plugins/sdk/plugin.js +1 -1
  27. package/dist/plugins/sdk/pluginModelDefinition.js +0 -6
  28. package/dist/plugins/sdk/pluginPageDefinition.d.ts +0 -1
  29. package/dist/plugins/sdk/pluginPageDefinition.js +2 -18
  30. package/dist/plugins/sdk/pluginRecoveryDefinition.js +0 -3
  31. package/dist/plugins/sdk/pluginStateDefinition.d.ts +0 -1
  32. package/dist/plugins/sdk/pluginStateDefinition.js +0 -11
  33. package/dist/runtimePaths.d.ts +1 -0
  34. package/dist/runtimePaths.js +1 -0
  35. package/dist/script.d.ts +30 -0
  36. package/dist/script.js +260 -0
  37. package/dist/scriptCli.d.ts +1 -0
  38. package/dist/scriptCli.js +94 -0
  39. package/dist/scriptErrors.d.ts +8 -0
  40. package/dist/scriptErrors.js +21 -0
  41. package/dist/scriptWorker.d.ts +1 -0
  42. package/dist/scriptWorker.js +50 -0
  43. package/dist/sdkMethods.d.ts +3 -0
  44. package/dist/sdkMethods.js +9 -0
  45. package/dist/socket.js +2 -1
  46. package/package.json +10 -8
@@ -0,0 +1,94 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { resolve } from 'node:path';
3
+ import { Command } from 'commander';
4
+ import { executeScript } from './script.js';
5
+ export async function runScriptCli(args, commandName) {
6
+ const program = new Command()
7
+ .name(`${commandName} run`)
8
+ .description('执行 Node.js 脚本;预注入 mearl SDK,支持顶层 await、条件和循环')
9
+ .option('--file <path>', '读取 JavaScript 文件;省略时从 stdin 读取')
10
+ .option('--session <new-or-id>', '首次建立或复用控制会话')
11
+ .option('--browser <id-or-name>', '指定浏览器')
12
+ .option('--connector <id-or-name>', '限制到远端 connector')
13
+ .option('--local', '仅使用本机浏览器')
14
+ .option('--cdp', '强制本机 CDP')
15
+ .option('--server <url>', '覆盖 cloud-server 地址')
16
+ .option('--timeout <seconds>', '整个脚本的执行时限(默认 60 秒)', '60')
17
+ .allowExcessArguments(false)
18
+ .exitOverride()
19
+ .addHelpText('after', `\n示例:\n ${commandName} run --file task.mjs\n ${commandName} run <<'JS'\n console.log(await mearl.tabList());\n JS\n\n脚本拥有当前宿主的 Node.js 权限;使用 await import() 加载模块。\n调用 Skill 命令:await mearl.invokePlugin('notes', { command: 'search', input: { query: 'project' } })。\n用 console.log(await mearl.help('pageClick')) 查询共享帮助,mearl.structure(value) 查看结果结构。\n每次运行重建 JS 变量;复用 session 和 tabId 可继续同一浏览器任务。\n`);
20
+ let source;
21
+ let options;
22
+ try {
23
+ program.parse(args, { from: 'user' });
24
+ options = program.opts();
25
+ const timeout = Number(options.timeout);
26
+ if (!Number.isFinite(timeout) || timeout <= 0 || timeout * 1000 > 2_147_483_647)
27
+ throw new Error('--timeout 必须是有效范围内的大于 0 的秒数');
28
+ if ((options.local || options.cdp) && options.connector)
29
+ throw new Error('--local/--cdp 不能与 --connector 同时使用');
30
+ if (options.file)
31
+ source = await readFile(resolve(options.file), 'utf8');
32
+ else {
33
+ if (process.stdin.isTTY)
34
+ throw new Error('通过 stdin 提交脚本,或使用 --file <path>');
35
+ const chunks = [];
36
+ let size = 0;
37
+ for await (const chunk of process.stdin) {
38
+ const buffer = Buffer.from(chunk);
39
+ size += buffer.length;
40
+ if (size > 1024 * 1024)
41
+ throw new Error('脚本不能超过 1 MiB');
42
+ chunks.push(buffer);
43
+ }
44
+ source = Buffer.concat(chunks).toString('utf8');
45
+ }
46
+ if (!source.trim() || Buffer.byteLength(source) > 1024 * 1024)
47
+ throw new Error('脚本必须是非空且不超过 1 MiB 的 JavaScript');
48
+ }
49
+ catch (error) {
50
+ if (error.code === 'commander.helpDisplayed')
51
+ return 0;
52
+ console.error(error instanceof Error ? error.message : String(error));
53
+ return 2;
54
+ }
55
+ const controller = new AbortController();
56
+ const abort = () => controller.abort();
57
+ process.once('SIGINT', abort);
58
+ process.once('SIGTERM', abort);
59
+ try {
60
+ const result = await executeScript(source, {
61
+ executionTimeoutSec: Number(options.timeout),
62
+ signal: controller.signal,
63
+ source: 'cli',
64
+ ...(options.session ? { session: options.session } : {}),
65
+ ...(options.browser ? { browser: options.browser } : {}),
66
+ ...(options.connector ? { connector: options.connector } : {}),
67
+ ...(options.local || options.cdp ? { local: true } : {}),
68
+ ...(options.cdp ? { transport: 'cdp' } : {}),
69
+ ...(options.server ? { serverUrl: options.server } : {}),
70
+ });
71
+ if (result.stdout)
72
+ process.stdout.write(result.stdout);
73
+ if (result.stderr)
74
+ process.stderr.write(result.stderr);
75
+ if (result.session)
76
+ console.error(JSON.stringify({ session: result.session }));
77
+ if (!result.success)
78
+ console.error(JSON.stringify({
79
+ error: result.error,
80
+ executionStopped: result.executionStopped,
81
+ mayHaveLateEffects: result.mayHaveLateEffects,
82
+ pendingActions: result.pendingActions,
83
+ }));
84
+ return result.success ? 0 : 1;
85
+ }
86
+ catch (error) {
87
+ console.error(error instanceof Error ? error.message : String(error));
88
+ return 1;
89
+ }
90
+ finally {
91
+ process.removeListener('SIGINT', abort);
92
+ process.removeListener('SIGTERM', abort);
93
+ }
94
+ }
@@ -0,0 +1,8 @@
1
+ export declare function serializeScriptError(error: unknown, fallback?: string): {
2
+ stack?: string | undefined;
3
+ attempt?: {} | null | undefined;
4
+ stage?: string | undefined;
5
+ details?: Record<string, unknown> | undefined;
6
+ code: string;
7
+ message: string;
8
+ };
@@ -0,0 +1,21 @@
1
+ import { serializePluginExecutionError } from './plugins/runtime/pluginExecutorProtocol.js';
2
+ export function serializeScriptError(error, fallback = 'SCRIPT_ERROR') {
3
+ const value = error;
4
+ const diagnostic = serializePluginExecutionError({
5
+ message: typeof value?.message === 'string' ? value.message : String(error),
6
+ code: typeof value?.code === 'string' ? value.code : fallback,
7
+ details: {
8
+ ...value?.details,
9
+ ...(value?.attempt !== undefined ? { attempt: value.attempt } : {}),
10
+ },
11
+ ...(typeof value?.stage === 'string' ? { stage: value.stage } : {}),
12
+ });
13
+ return {
14
+ code: diagnostic.code ?? fallback,
15
+ message: diagnostic.message,
16
+ ...(diagnostic.details ? { details: diagnostic.details } : {}),
17
+ ...(typeof diagnostic.metadata?.stage === 'string' ? { stage: diagnostic.metadata.stage } : {}),
18
+ ...(diagnostic.details?.attempt !== undefined ? { attempt: diagnostic.details.attempt } : {}),
19
+ ...(typeof value?.stack === 'string' ? { stack: value.stack.slice(0, 16384) } : {}),
20
+ };
21
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,50 @@
1
+ import { getStructure } from '@mearl/browser-core';
2
+ import { serializeScriptError } from './scriptErrors.js';
3
+ const pending = new Map();
4
+ let sequence = 0;
5
+ let session;
6
+ const call = (method, args) => new Promise((resolve, reject) => {
7
+ const id = ++sequence;
8
+ pending.set(id, { resolve, reject });
9
+ process.send({ type: 'call', id, method, args });
10
+ });
11
+ process.on('disconnect', () => process.exit(1));
12
+ process.on('message', async (message) => {
13
+ if (message.type === 'response') {
14
+ const entry = pending.get(message.id);
15
+ if (!entry)
16
+ return;
17
+ pending.delete(message.id);
18
+ session = message.session ?? session;
19
+ if (message.error)
20
+ entry.reject(Object.assign(new Error(message.error.message), message.error));
21
+ else
22
+ entry.resolve(message.result);
23
+ return;
24
+ }
25
+ if (message.type !== 'start')
26
+ return;
27
+ session = message.session;
28
+ const api = Object.fromEntries(message.methods.map((method) => [method, (...args) => call(method, args)]));
29
+ api.structure = getStructure;
30
+ Object.defineProperty(api, 'session', { get: () => session, enumerable: true });
31
+ Object.defineProperty(globalThis, 'mearl', { value: Object.freeze(api), configurable: true });
32
+ let failure;
33
+ try {
34
+ const AsyncFunction = Object.getPrototypeOf(async function () { }).constructor;
35
+ const fn = new AsyncFunction('mearl', '"use strict";\n' + message.code + '\n//# sourceURL=mearl-script.js');
36
+ await fn(api);
37
+ if (pending.size)
38
+ throw Object.assign(new Error('Script finished with unawaited SDK calls'), {
39
+ code: 'SCRIPT_PENDING_CALLS',
40
+ });
41
+ }
42
+ catch (error) {
43
+ failure = serializeScriptError(error);
44
+ }
45
+ await Promise.all([
46
+ new Promise(resolve => process.stdout.write('', resolve)),
47
+ new Promise(resolve => process.stderr.write('', resolve)),
48
+ ]);
49
+ process.send(failure ? { type: 'error', error: failure } : { type: 'done' });
50
+ });
@@ -0,0 +1,3 @@
1
+ /** Method names and signature exceptions shared by script dispatch and command help. */
2
+ export declare const SDK_METHOD_ACTIONS: Map<string, string>;
3
+ export declare const SDK_OPTIONS_ONLY_METHODS: Set<string>;
@@ -0,0 +1,9 @@
1
+ import { BROWSER_COMMAND_ACTIONS } from '@mearl/browser-core/browserActionProtocol';
2
+ /** Method names and signature exceptions shared by script dispatch and command help. */
3
+ export const SDK_METHOD_ACTIONS = new Map(Object.keys(BROWSER_COMMAND_ACTIONS).map(action => [
4
+ action.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase()),
5
+ action,
6
+ ]));
7
+ SDK_METHOD_ACTIONS.set('selectBrowser', 'browser_select_browser');
8
+ SDK_METHOD_ACTIONS.set('captureCheckpoint', 'tab_checkpoint');
9
+ export const SDK_OPTIONS_ONLY_METHODS = new Set(['browserList', 'tabList', 'getRules']);
package/dist/socket.js CHANGED
@@ -133,6 +133,7 @@ function isOrdinaryLocalBrowser(browser) {
133
133
  function supportsAction(browser, action, data) {
134
134
  if (browser.transport === 'provider') {
135
135
  if (action === 'browser_control' ||
136
+ (action === 'get_capabilities' && isConnectedBrowser(browser)) ||
136
137
  (action === 'browser_release' && data[SESSION_OPTION]))
137
138
  return true;
138
139
  if (action.startsWith('__artifact_'))
@@ -686,7 +687,7 @@ function formatConnectError(error, socketPath) {
686
687
  if (error.code === 'ENOENT') {
687
688
  return [
688
689
  `未找到 Socket: ${socketPath}`,
689
- 'native host 自动拉起失败。先运行 mearl check --local;缺少命令时运行 npx --@mearl:registry=https://registry.npmjs.org @mearl/setup --local --yes。',
690
+ 'native host 自动拉起失败。先运行 mearl check --local;缺少命令时运行 npx @mearl/setup --local --yes。',
690
691
  '自动拉起只使用默认 daemon 参数;自定义 CDP/Profile/浏览器参数需手工启动,参见 mearl-native-host --help。',
691
692
  '',
692
693
  '【方式一:浏览器插件模式】',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mearl/client",
3
- "version": "3.0.0-beta.3",
3
+ "version": "3.0.0-beta.5",
4
4
  "description": "Unified Mearl SDK & CLI for local and remote browsers",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -37,6 +37,10 @@
37
37
  "./plugin": {
38
38
  "types": "./dist/plugin.d.ts",
39
39
  "import": "./dist/plugin.js"
40
+ },
41
+ "./script": {
42
+ "types": "./dist/script.d.ts",
43
+ "import": "./dist/script.js"
40
44
  }
41
45
  },
42
46
  "bin": {
@@ -60,16 +64,14 @@
60
64
  "registry": "https://registry.npmjs.org"
61
65
  },
62
66
  "dependencies": {
63
- "acorn": "^8.16.0",
64
- "ajv": "^8.18.0",
65
67
  "commander": "^15.0.0",
66
68
  "fastest-levenshtein": "^1.0.16",
67
69
  "ws": "^8.18.0",
68
- "@mearl/daemon-core": "3.0.0-beta.3",
69
- "@mearl/cloud-types": "3.0.0-beta.3",
70
- "@mearl/provider": "3.0.0-beta.3",
71
- "@mearl/agent-runtime": "3.0.0-beta.3",
72
- "@mearl/browser-core": "3.0.0-beta.3"
70
+ "@mearl/provider": "3.0.0-beta.5",
71
+ "@mearl/agent-runtime": "3.0.0-beta.5",
72
+ "@mearl/browser-core": "3.0.0-beta.5",
73
+ "@mearl/cloud-types": "3.0.0-beta.5",
74
+ "@mearl/daemon-core": "3.0.0-beta.5"
73
75
  },
74
76
  "devDependencies": {
75
77
  "@types/node": "^24.9.1",