@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.
Files changed (56) hide show
  1. package/README.md +95 -16
  2. package/dist/actionTimeouts.js +1 -1
  3. package/dist/autoUpdate.js +2 -1
  4. package/dist/capabilityHelp.d.ts +4 -0
  5. package/dist/capabilityHelp.js +69 -0
  6. package/dist/check.d.ts +5 -6
  7. package/dist/check.js +4 -7
  8. package/dist/cli.js +22 -56
  9. package/dist/commandHelp.d.ts +3 -0
  10. package/dist/commandHelp.js +79 -0
  11. package/dist/commandSuggestions.d.ts +3 -0
  12. package/dist/commandSuggestions.js +16 -5
  13. package/dist/commands.d.ts +78 -62
  14. package/dist/commands.js +67 -49
  15. package/dist/index.d.ts +6 -2
  16. package/dist/index.js +10 -4
  17. package/dist/nativeHost.js +1 -1
  18. package/dist/plugins/clients/pluginHostConnection.d.ts +2 -0
  19. package/dist/plugins/clients/pluginHostConnection.js +3 -1
  20. package/dist/plugins/officialPluginInstaller.js +2 -1
  21. package/dist/plugins/pluginRegistry.d.ts +1 -1
  22. package/dist/plugins/pluginRegistry.js +12 -4
  23. package/dist/plugins/runtime/pluginCommandWorker.js +8 -6
  24. package/dist/plugins/runtime/pluginExecutor.d.ts +5 -0
  25. package/dist/plugins/runtime/pluginExecutor.js +15 -2
  26. package/dist/plugins/runtime/pluginExecutorProtocol.d.ts +4 -0
  27. package/dist/plugins/runtime/pluginExecutorSupervisor.js +2 -1
  28. package/dist/plugins/runtime/pluginHostServer.js +4 -0
  29. package/dist/plugins/runtime/pluginPageManager.js +0 -4
  30. package/dist/plugins/runtime/pluginRevision.js +0 -51
  31. package/dist/plugins/runtime/pluginStateStore.js +3 -8
  32. package/dist/plugins/runtime/pluginTaskManager.js +4 -8
  33. package/dist/plugins/sdk/plugin.js +1 -1
  34. package/dist/plugins/sdk/pluginModelDefinition.js +0 -6
  35. package/dist/plugins/sdk/pluginPageDefinition.d.ts +0 -1
  36. package/dist/plugins/sdk/pluginPageDefinition.js +2 -18
  37. package/dist/plugins/sdk/pluginRecoveryDefinition.js +0 -3
  38. package/dist/plugins/sdk/pluginStateDefinition.d.ts +0 -1
  39. package/dist/plugins/sdk/pluginStateDefinition.js +0 -11
  40. package/dist/runtimePaths.d.ts +1 -0
  41. package/dist/runtimePaths.js +1 -0
  42. package/dist/script.d.ts +30 -0
  43. package/dist/script.js +261 -0
  44. package/dist/scriptCli.d.ts +1 -0
  45. package/dist/scriptCli.js +94 -0
  46. package/dist/scriptErrors.d.ts +8 -0
  47. package/dist/scriptErrors.js +21 -0
  48. package/dist/scriptWorker.d.ts +1 -0
  49. package/dist/scriptWorker.js +50 -0
  50. package/dist/sdkMethods.d.ts +3 -0
  51. package/dist/sdkMethods.js +9 -0
  52. package/dist/socket.js +34 -9
  53. package/dist/unified.js +11 -1
  54. package/dist/unifiedConfig.d.ts +4 -0
  55. package/dist/unifiedConfig.js +11 -0
  56. package/package.json +13 -11
@@ -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
@@ -13,13 +13,13 @@ import os from 'node:os';
13
13
  import path from 'node:path';
14
14
  import { CLIENT_VERSION } from './runtimePaths.js';
15
15
  import { StringDecoder } from 'node:string_decoder';
16
- import { ensureProviderControlHost, listInstalledProviders } from '@mearl/provider/host';
17
- import { MEARL_PROVIDER_PROTOCOL_VERSION } from '@mearl/provider';
18
- import { readLiveProvider } from '@mearl/provider/runtime';
16
+ import { assertProviderControlSessionMode, ensureProviderControlHost, listInstalledProviders } from '@mearl/provider/host';
17
+ import { MEARL_PROVIDER_PROTOCOL_VERSION, assertProviderProtocolVersion, validateProviderLaunchForm } from '@mearl/provider';
18
+ import { readLiveProvider, ensureInstalledProvidersRunning } from '@mearl/provider/runtime';
19
19
  import { resolveFileRefs } from './fileRefs.js';
20
20
  import { listLiveBrowsers, findBrowser, describeBrowser, } from './browserRegistry.js';
21
21
  import { resolveActionTimeoutSec } from './actionTimeouts.js';
22
- import { isBrowserCapabilityAction } from '@mearl/browser-core';
22
+ import { isBrowserCapabilityAction, parseBrowserListParams } from '@mearl/browser-core';
23
23
  export { CLIENT_VERSION };
24
24
  const MAX_SOCKET_BUFFER_SIZE = 64 * 1024 * 1024;
25
25
  /**
@@ -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_'))
@@ -375,6 +376,29 @@ export function invoke(action, data = {}, options = {}) {
375
376
  const resolvedData = resolveFileRefs(data);
376
377
  Object.defineProperty(resolvedData, SESSION_OPTION, { value: options.controlSessionId });
377
378
  if (action === 'browser_list') {
379
+ const discovery = parseBrowserListParams(resolvedData);
380
+ if (discovery) {
381
+ return (async () => {
382
+ if (transport || options.socketPath || controlSource !== 'local' || options.controlSessionId)
383
+ throw new Error('Provider discovery requires the local source without a transport, socket or session override');
384
+ const provider = listInstalledProviders().find(provider => provider.providerId === discovery.provider);
385
+ if (!provider?.browserType.dynamicLaunchForm)
386
+ throw new Error(`Provider does not support dynamic launch forms: ${discovery.provider}`);
387
+ const warnings = await ensureInstalledProvidersRunning([discovery.provider]);
388
+ if (warnings.length)
389
+ throw new Error(warnings.join('; '));
390
+ const live = readLiveProvider(discovery.provider);
391
+ if (!live)
392
+ throw new Error(`Provider did not start: ${discovery.provider}`);
393
+ assertProviderProtocolVersion(live.providerProtocolVersion, discovery.provider);
394
+ const form = await invokeOnce('browser_providers', { operation: 'launch_form', ...discovery.launchForm }, timeoutSec, undefined, live.socketPath, 'local');
395
+ validateProviderLaunchForm(form);
396
+ return decorateBrowserListResult({
397
+ ...browserListFromProviderRecords(listLiveBrowsers().filter(browser => browser.provider?.id === discovery.provider)),
398
+ discovery: { provider: discovery.provider, launchForm: form },
399
+ });
400
+ })();
401
+ }
378
402
  return dispatchInvoke(action, resolvedData, timeoutSec, transport, undefined, controlSource, options.socketPath).then(result => decorateBrowserListResult(transport === 'cdp' ? cdpOnlyBrowserList(result) : result));
379
403
  }
380
404
  const selector = browser ?? defaultBrowser ?? process.env.MEARL_BROWSER ?? undefined;
@@ -509,7 +533,7 @@ async function dispatchInvoke(action, data, timeoutSec, transport, selector, con
509
533
  throw new Error(`Browser ${describeBrowser(match)} does not support ${action}`);
510
534
  }
511
535
  try {
512
- return await invokeOnce(action, data, timeoutSec, transport, match.socketPath, controlSource, match.transport === 'provider' ? match.browserId : undefined);
536
+ return await invokeOnce(action, data, timeoutSec, transport, match.socketPath, controlSource, match.transport === 'provider' ? match.browserId : undefined, match.capabilities?.controlSessionMode);
513
537
  }
514
538
  catch (error) {
515
539
  if (isConnError(error) || isSocketSandboxError(error)) {
@@ -526,7 +550,7 @@ async function dispatchInvoke(action, data, timeoutSec, transport, selector, con
526
550
  if (candidates.length > 0) {
527
551
  const target = candidates[0];
528
552
  try {
529
- return await invokeOnce(action, data, timeoutSec, transport, target.socketPath, controlSource, target.transport === 'provider' ? target.browserId : undefined);
553
+ return await invokeOnce(action, data, timeoutSec, transport, target.socketPath, controlSource, target.transport === 'provider' ? target.browserId : undefined, target.capabilities?.controlSessionMode);
530
554
  }
531
555
  catch (error) {
532
556
  if (isSocketSandboxError(error)) {
@@ -574,7 +598,7 @@ async function invokeViaLegacy(action, data, timeoutSec, transport, controlSourc
574
598
  !(transport === 'cdp' && browser.transport === 'provider') &&
575
599
  supportsAction(browser, action, data));
576
600
  if (target) {
577
- return invokeOnce(action, data, timeoutSec, transport, target.socketPath, controlSource, target.transport === 'provider' ? target.browserId : undefined);
601
+ return invokeOnce(action, data, timeoutSec, transport, target.socketPath, controlSource, target.transport === 'provider' ? target.browserId : undefined, target.capabilities?.controlSessionMode);
578
602
  }
579
603
  return invokeViaLegacy(action, data, timeoutSec, transport, controlSource,
580
604
  /* isRetry */ true, localOnly);
@@ -585,9 +609,10 @@ async function invokeViaLegacy(action, data, timeoutSec, transport, controlSourc
585
609
  throw new Error(formatConnectError(err, SOCKET_PATH), { cause: error });
586
610
  }
587
611
  }
588
- async function invokeOnce(action, data, timeoutSec, transport, socketPath, controlSource, providerTarget) {
612
+ async function invokeOnce(action, data, timeoutSec, transport, socketPath, controlSource, providerTarget, controlSessionMode) {
589
613
  if (providerTarget) {
590
614
  const host = await ensureProviderControlHost(Math.min(timeoutSec * 1000, 10_000));
615
+ assertProviderControlSessionMode(host, controlSessionMode);
591
616
  socketPath = host.socketPath;
592
617
  }
593
618
  const id = `${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
@@ -686,7 +711,7 @@ function formatConnectError(error, socketPath) {
686
711
  if (error.code === 'ENOENT') {
687
712
  return [
688
713
  `未找到 Socket: ${socketPath}`,
689
- 'native host 自动拉起失败。先运行 mearl check --local;缺少命令时运行 npx --@mearl:registry=https://registry.npmjs.org @mearl/setup --local --yes。',
714
+ 'native host 自动拉起失败。先运行 mearl check --local;缺少命令时运行 npx @mearl/setup --local --yes。',
690
715
  '自动拉起只使用默认 daemon 参数;自定义 CDP/Profile/浏览器参数需手工启动,参见 mearl-native-host --help。',
691
716
  '',
692
717
  '【方式一:浏览器插件模式】',
package/dist/unified.js CHANGED
@@ -3,7 +3,7 @@ import { stageFile, exportArtifact } from './artifacts.js';
3
3
  import WebSocket from 'ws';
4
4
  import { DEFAULT_CONNECT_TIMEOUT, DEFAULT_HEARTBEAT_INTERVAL, DEFAULT_REQUEST_TIMEOUT, MAX_BUFFER_SIZE, isHeartbeatMessage, resolveCloudConnectorSelector, } from '@mearl/cloud-types';
5
5
  import { resolveActionTimeoutSec } from './actionTimeouts.js';
6
- import { validateRequiredActionTabId, } from '@mearl/browser-core';
6
+ import { validateRequiredActionTabId, parseBrowserListParams, } from '@mearl/browser-core';
7
7
  import { invoke as invokeLocalBrowser, resolveLocalActionTarget } from './socket.js';
8
8
  import { loadCloudServerConfig, loadLocalConnectorId } from './unifiedConfig.js';
9
9
  const RESPONSE_GRACE_MS = 1_000;
@@ -146,6 +146,9 @@ export class UnifiedClient {
146
146
  }, options);
147
147
  }
148
148
  async invoke(action, data = {}, options = {}) {
149
+ const discovery = action === 'browser_list' ? parseBrowserListParams(data) : undefined;
150
+ if (discovery && (!options.local || options.connector || options.transport || options.session || options.controlSessionId))
151
+ throw new Error('Provider discovery requires explicit --local without connector, transport, socket or session overrides');
149
152
  if (action === 'plugin_state') {
150
153
  const { PluginStateClient } = await import('./plugins/clients/pluginState.js');
151
154
  const state = new PluginStateClient();
@@ -350,6 +353,12 @@ export class UnifiedClient {
350
353
  if (action === 'connector_list')
351
354
  return this.listConnectors(timeoutSec);
352
355
  if (action === 'browser_list') {
356
+ if (parseBrowserListParams(data)) {
357
+ const result = await invokeLocalBrowser('browser_list', data, { timeoutSec, controlSource: 'local' });
358
+ if (!result?.discovery)
359
+ throw new Error('Provider launch-form discovery is not supported by this host');
360
+ return this.applyConfiguredDefault(this.decorateListing(result, { kind: 'local' }));
361
+ }
353
362
  if (options.local || options.transport === 'cdp') {
354
363
  return this.listLocalBrowsers(timeoutSec, options.transport);
355
364
  }
@@ -543,6 +552,7 @@ export class UnifiedClient {
543
552
  })
544
553
  : null,
545
554
  browsers,
555
+ ...(result?.discovery ? { discovery: result.discovery } : {}),
546
556
  ...(resultWarnings.length > 0 ? { warnings: resultWarnings } : {}),
547
557
  };
548
558
  }
@@ -6,3 +6,7 @@ export declare function loadCliAutoUpdateIntervalDays(configPath?: string): numb
6
6
  export declare function getCloudServerConfigPath(): string;
7
7
  export declare function loadCloudServerConfig(): CloudServerConfig | null;
8
8
  export declare function loadLocalConnectorId(): string | null;
9
+ export declare function resolveServer(explicit?: string): {
10
+ serverUrl?: string;
11
+ serverUrlSource?: string;
12
+ };
@@ -56,3 +56,14 @@ export function loadLocalConnectorId() {
56
56
  return null;
57
57
  }
58
58
  }
59
+ export function resolveServer(explicit) {
60
+ if (explicit)
61
+ return { serverUrl: explicit, serverUrlSource: '--server' };
62
+ if (process.env.MEARL_SERVER_URL) {
63
+ return { serverUrl: process.env.MEARL_SERVER_URL, serverUrlSource: 'MEARL_SERVER_URL' };
64
+ }
65
+ const config = loadCloudServerConfig();
66
+ return config?.server
67
+ ? { serverUrl: config.server, serverUrlSource: getCloudServerConfigPath() }
68
+ : {};
69
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mearl/client",
3
- "version": "3.0.0-beta.4",
3
+ "version": "3.0.0-beta.7",
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": {
@@ -54,22 +58,20 @@
54
58
  ],
55
59
  "license": "Apache-2.0",
56
60
  "engines": {
57
- "node": ">=22.12.0"
61
+ "node": ">=20.18.0"
58
62
  },
59
63
  "publishConfig": {
60
64
  "registry": "https://registry.npmjs.org"
61
65
  },
62
66
  "dependencies": {
63
- "acorn": "^8.16.0",
64
- "ajv": "^8.18.0",
65
- "commander": "^15.0.0",
67
+ "commander": "^14.0.3",
66
68
  "fastest-levenshtein": "^1.0.16",
67
69
  "ws": "^8.18.0",
68
- "@mearl/cloud-types": "3.0.0-beta.4",
69
- "@mearl/provider": "3.0.0-beta.4",
70
- "@mearl/daemon-core": "3.0.0-beta.4",
71
- "@mearl/agent-runtime": "3.0.0-beta.4",
72
- "@mearl/browser-core": "3.0.0-beta.4"
70
+ "@mearl/daemon-core": "3.0.0-beta.7",
71
+ "@mearl/cloud-types": "3.0.0-beta.7",
72
+ "@mearl/provider": "3.0.0-beta.7",
73
+ "@mearl/agent-runtime": "3.0.0-beta.7",
74
+ "@mearl/browser-core": "3.0.0-beta.7"
73
75
  },
74
76
  "devDependencies": {
75
77
  "@types/node": "^24.9.1",
@@ -78,7 +80,7 @@
78
80
  },
79
81
  "repository": {
80
82
  "type": "git",
81
- "url": "git+https://github.com/F-loat/mearl.git",
83
+ "url": "git+https://github.com/mearlhq/mearl.git",
82
84
  "directory": "packages/client"
83
85
  },
84
86
  "scripts": {