@mearl/setup 2.12.0 → 2.13.0

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 CHANGED
@@ -9,6 +9,7 @@ npx @mearl/setup extension [--full] [--force]
9
9
  npx @mearl/setup plugin <name> <path>
10
10
  npx @mearl/setup plugin install <ali-skills add 参数...>
11
11
  npx @mearl/setup plugin uninstall <name>
12
+ npx @mearl/setup provider <install|update|uninstall> <package|id>
12
13
  ```
13
14
 
14
15
  配置 AgentBay API Key 时只需执行一次下面的命令,然后在隐藏输入提示中粘贴 Key。
@@ -70,6 +71,23 @@ npx @mearl/setup plugin uninstall yuque
70
71
  移除失败时保留注册以便重试。手工注册的其他路径只解除 Mearl 注册,不删除源码。
71
72
  重复卸载未注册名称会成功返回,不产生改动。
72
73
 
74
+ ## 管理浏览器 Provider
75
+
76
+ Provider 由 npm 包分发,但包本身无需暴露 CLI 或安装脚本。setup 使用当前 npm 包管理器
77
+ 完成全局包生命周期,再读取包内的 `package.json#mearl.provider` 元数据登记协议入口、
78
+ 可创建的浏览器类型名称及其表单参数:
79
+
80
+ ```bash
81
+ npx @mearl/setup provider install @ali/mearl-provider-brow
82
+ npx @mearl/setup provider update brow
83
+ npx @mearl/setup provider uninstall brow
84
+ ```
85
+
86
+ 安装参数接受包名、版本或 dist-tag;更新和卸载可使用 `providerId` 或完整包名。阿里包在
87
+ 本机存在 `tnpm` 时优先使用 `tnpm`,其他情况沿用启动 setup 的包管理器。Provider 登记只保存
88
+ 经过校验的包名、安装目录和包内入口;不接受包自行注入启动命令、参数、工作目录或环境变量。
89
+ 卸载仅在包管理器成功移除包后清除登记,以便失败时可以重试。
90
+
73
91
  ## 行为
74
92
 
75
93
  - `install` 可以省略;直接执行 `npx @mearl/setup` 等同于 `npx @mearl/setup install`。
@@ -200,4 +218,4 @@ npx @mearl/setup agentbay
200
218
  npx @mearl/setup agentbay --key-file ./agentbay.key
201
219
  ```
202
220
 
203
- 原有的 npm/npx 安装方式和各包 CLI 保持可用;setup 只是统一的便利入口。
221
+ 原有 Mearl 环境包的 npm/npx 安装方式和 CLI 保持可用;setup 是统一的便利入口。
package/dist/cli.d.ts CHANGED
@@ -4,6 +4,7 @@ import { installMearlBrowserExtension } from './browserExtension.js';
4
4
  import { runMearlLifecycle, type MearlLifecycleOperation } from './lifecycle.js';
5
5
  import type { MearlProfile } from './profiles.js';
6
6
  import { installPlugins, setupPlugin, uninstallPlugin } from './plugin.js';
7
+ import { installProviderPackage, uninstallProviderPackage, updateProviderPackage } from './provider.js';
7
8
  export declare const SETUP_VERSION: string;
8
9
  interface ParsedArgs {
9
10
  agentBayKeyFile?: string;
@@ -12,11 +13,13 @@ interface ParsedArgs {
12
13
  force?: boolean;
13
14
  full?: boolean;
14
15
  help: boolean;
15
- operation?: MearlLifecycleOperation | 'agentbay' | 'extension' | 'plugin';
16
+ operation?: MearlLifecycleOperation | 'agentbay' | 'extension' | 'plugin' | 'provider';
16
17
  pluginName?: string;
17
18
  pluginPath?: string;
18
19
  pluginInstallArgs?: string[];
19
20
  pluginUninstallName?: string;
21
+ providerCommand?: 'install' | 'uninstall' | 'update';
22
+ providerTarget?: string;
20
23
  profiles?: MearlProfile[];
21
24
  skipSkill: boolean;
22
25
  targetLine?: string;
@@ -32,7 +35,10 @@ export interface SetupCliDependencies {
32
35
  readAgentBayKeyFile?: typeof readAgentBayApiKeyFile;
33
36
  readAgentBayKeyStdin?: typeof readAgentBayApiKeyStdin;
34
37
  installBrowserExtension?: typeof installMearlBrowserExtension;
38
+ installProvider?: typeof installProviderPackage;
35
39
  runLifecycle?: typeof runMearlLifecycle;
40
+ uninstallProvider?: typeof uninstallProviderPackage;
41
+ updateProvider?: typeof updateProviderPackage;
36
42
  }
37
43
  export declare function parseSetupArgs(argv: string[]): ParsedArgs;
38
44
  export declare function main(argv?: string[], interactiveTerminal?: boolean, dependencies?: SetupCliDependencies): Promise<number>;
package/dist/cli.js CHANGED
@@ -6,6 +6,7 @@ import { installMearlBrowserExtension } from './browserExtension.js';
6
6
  import { runMearlLifecycle } from './lifecycle.js';
7
7
  import { isMearlReleaseLine } from './version.js';
8
8
  import { installPlugins, setupPlugin, uninstallPlugin } from './plugin.js';
9
+ import { installProviderPackage, uninstallProviderPackage, updateProviderPackage, } from './provider.js';
9
10
  const require = createRequire(import.meta.url);
10
11
  export const SETUP_VERSION = require('../package.json').version;
11
12
  const baseParsedArgs = () => ({
@@ -25,6 +26,20 @@ function commanderError(error) {
25
26
  return new Error(message);
26
27
  }
27
28
  export function parseSetupArgs(argv) {
29
+ if (argv[0] === 'provider') {
30
+ const command = argv[1];
31
+ if ((command === 'install' || command === 'update' || command === 'uninstall') &&
32
+ argv.length === 3 &&
33
+ argv[2]) {
34
+ return {
35
+ ...baseParsedArgs(),
36
+ operation: 'provider',
37
+ providerCommand: command,
38
+ providerTarget: argv[2],
39
+ };
40
+ }
41
+ throw new Error('provider requires install <package>, update <id>, or uninstall <id>');
42
+ }
28
43
  if (argv[0] === 'plugin' && argv[1] === 'install') {
29
44
  return { ...baseParsedArgs(), operation: 'plugin', pluginInstallArgs: argv.slice(2) };
30
45
  }
@@ -166,6 +181,7 @@ Usage:
166
181
  npx @mearl/setup plugin <name> <path>
167
182
  npx @mearl/setup plugin install <ali-skills add arguments...>
168
183
  npx @mearl/setup plugin uninstall <name>
184
+ npx @mearl/setup provider <install|update|uninstall> <package|id>
169
185
  npx @mearl/setup agentbay [--stdin | --key-file <path>]
170
186
 
171
187
  Behavior:
@@ -175,6 +191,7 @@ Behavior:
175
191
  extension Install or update the browser extension; --full also installs the local environment
176
192
  agentbay Save or update AGENTBAY_KEY without changing other Mearl settings
177
193
  plugin Register, install, or uninstall a CLI plugin
194
+ provider Install npm Provider packages and manage their Mearl registration
178
195
 
179
196
  Options:
180
197
  --local Manage @mearl/native-host and @mearl/client
@@ -206,6 +223,7 @@ Examples:
206
223
  npx @mearl/setup extension
207
224
  npx @mearl/setup extension --full
208
225
  npx @mearl/setup plugin uninstall yuque
226
+ npx @mearl/setup provider install @ali/mearl-provider-brow
209
227
  npx @mearl/setup agentbay
210
228
  npx @mearl/setup --qoder-cloud --yes
211
229
  npx @mearl/setup update --local --target-line 2.3.x --skip-skill
@@ -268,6 +286,27 @@ export async function main(argv = process.argv.slice(2), interactiveTerminal = p
268
286
  return 1;
269
287
  }
270
288
  }
289
+ if (parsed.operation === 'provider') {
290
+ try {
291
+ const target = parsed.providerTarget;
292
+ const result = parsed.providerCommand === 'install'
293
+ ? await (dependencies.installProvider ?? installProviderPackage)(target)
294
+ : parsed.providerCommand === 'update'
295
+ ? await (dependencies.updateProvider ?? updateProviderPackage)(target)
296
+ : await (dependencies.uninstallProvider ?? uninstallProviderPackage)(target);
297
+ const verb = parsed.providerCommand === 'uninstall'
298
+ ? 'uninstalled'
299
+ : parsed.providerCommand === 'update'
300
+ ? 'updated'
301
+ : 'installed';
302
+ console.error(`Provider ${result.manifest.providerId} ${verb}: ${result.manifest.packageName}@${result.manifest.version} (${result.manager})`);
303
+ return 0;
304
+ }
305
+ catch (error) {
306
+ console.error(error instanceof Error ? error.message : String(error));
307
+ return 1;
308
+ }
309
+ }
271
310
  if (parsed.operation === 'agentbay') {
272
311
  try {
273
312
  const configureAgentBay = dependencies.configureAgentBay ?? configureAgentBayApiKey;
package/dist/index.d.ts CHANGED
@@ -11,4 +11,6 @@ export type { DetectedMearlProfiles, MearlProfile, MearlProfileConfig } from './
11
11
  export { MEARL_NATIVE_HOST_NAMES, resolveNativeHostDirectory, uninstallNativeHostArtifacts, } from './nativeHost.js';
12
12
  export { compareMearlReleaseLines, compareMearlReleaseVersions, isMearlReleaseLine, isMearlReleaseVersion, isMearlReleaseVersionInLine, mearlReleaseLineForVersion, parseMearlReleaseLine, parseMearlReleaseVersion, } from './version.js';
13
13
  export type { MearlReleaseLine, MearlReleaseVersion } from './version.js';
14
+ export { installProviderPackage, parseProviderPackageSpec, uninstallProviderPackage, updateProviderPackage, } from './provider.js';
15
+ export type { ProviderSetupDependencies, ProviderSetupResult } from './provider.js';
14
16
  export type { NativeHostCleanupDependencies, NativeHostCleanupOptions, NativeHostIntegrationMode, } from './nativeHost.js';
package/dist/index.js CHANGED
@@ -5,3 +5,4 @@ export { runMearlLifecycle } from './lifecycle.js';
5
5
  export { MEARL_PROFILES, detectMearlProfiles } from './profiles.js';
6
6
  export { MEARL_NATIVE_HOST_NAMES, resolveNativeHostDirectory, uninstallNativeHostArtifacts, } from './nativeHost.js';
7
7
  export { compareMearlReleaseLines, compareMearlReleaseVersions, isMearlReleaseLine, isMearlReleaseVersion, isMearlReleaseVersionInLine, mearlReleaseLineForVersion, parseMearlReleaseLine, parseMearlReleaseVersion, } from './version.js';
8
+ export { installProviderPackage, parseProviderPackageSpec, uninstallProviderPackage, updateProviderPackage, } from './provider.js';
package/dist/plugin.js CHANGED
@@ -17,9 +17,9 @@ const registrationContext = {
17
17
  export async function setupPlugin(name, target) {
18
18
  assertPluginName(name);
19
19
  const entry = resolvePluginEntry(target);
20
- await loadPlugin(entry, registrationContext);
20
+ const plugin = await loadPlugin(entry, registrationContext);
21
21
  await ensurePluginRuntime();
22
- return registerPlugin(name, entry);
22
+ return registerPlugin(name, entry, plugin.description);
23
23
  }
24
24
  function globalAliSkill(entry) {
25
25
  const globalSkillsDirectory = join(homedir(), '.agents', 'skills');
@@ -170,15 +170,15 @@ export async function installPlugins(args, runner = runCommand) {
170
170
  assertPluginName(name);
171
171
  if (plugins.has(name))
172
172
  throw new Error(`多个 skill 使用插件名称 ${name},请通过 setup plugin <name> <path> 分别注册。`);
173
- plugins.set(name, entry);
173
+ plugins.set(name, { entry, description: plugin.description });
174
174
  }
175
175
  if (plugins.size === 0) {
176
176
  console.error('未找到 scripts/main.mjs 插件入口;自定义入口可用 setup plugin <name> <path> 注册。');
177
177
  return 0;
178
178
  }
179
179
  await ensurePluginRuntime(runner);
180
- for (const [name, entry] of plugins) {
181
- registerPlugin(name, entry);
180
+ for (const [name, { entry, description }] of plugins) {
181
+ registerPlugin(name, entry, description);
182
182
  console.error(`Plugin ${name} registered: ${entry}\nRun: mearl ${name} --help`);
183
183
  }
184
184
  return 0;
@@ -0,0 +1,28 @@
1
+ import { listInstalledProviders, registerProviderPackage, stopProvider, uninstallProvider, type InstalledProviderManifest } from '@mearl/provider/host';
2
+ import { resolvePackageManagerInstallation, type PackageManagerInstallation } from './packageManager.js';
3
+ import { findExecutable, type CommandRunner } from './process.js';
4
+ interface ProviderPackageSpec {
5
+ packageName: string;
6
+ target: string;
7
+ }
8
+ export interface ProviderSetupDependencies {
9
+ existsSync?: (filePath: string) => boolean;
10
+ findExecutable?: typeof findExecutable;
11
+ listProviders?: typeof listInstalledProviders;
12
+ registerPackage?: typeof registerProviderPackage;
13
+ resolveInvokingManager?: (env: NodeJS.ProcessEnv) => PackageManagerInstallation;
14
+ resolvePackageManager?: typeof resolvePackageManagerInstallation;
15
+ resolvePackageRoot?: (installation: PackageManagerInstallation, packageName: string, runner: CommandRunner, env: NodeJS.ProcessEnv) => Promise<string>;
16
+ runCommand?: CommandRunner;
17
+ stopProvider?: typeof stopProvider;
18
+ unregisterProvider?: typeof uninstallProvider;
19
+ }
20
+ export interface ProviderSetupResult {
21
+ manifest: InstalledProviderManifest;
22
+ manager: PackageManagerInstallation['manager'];
23
+ }
24
+ export declare function parseProviderPackageSpec(value: string): ProviderPackageSpec;
25
+ export declare function installProviderPackage(packageSpec: string, dependencies?: ProviderSetupDependencies): Promise<ProviderSetupResult>;
26
+ export declare function updateProviderPackage(selector: string, dependencies?: ProviderSetupDependencies): Promise<ProviderSetupResult>;
27
+ export declare function uninstallProviderPackage(selector: string, dependencies?: ProviderSetupDependencies): Promise<ProviderSetupResult>;
28
+ export {};
@@ -0,0 +1,114 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { dirname, join, resolve } from 'node:path';
3
+ import { listInstalledProviders, registerProviderPackage, stopProvider, uninstallProvider, } from '@mearl/provider/host';
4
+ import { buildGlobalPackageCommand, resolveInvokingPackageManager, resolvePackageManagerInstallation, } from './packageManager.js';
5
+ import { findExecutable, prependCommandPath, runCommand } from './process.js';
6
+ export function parseProviderPackageSpec(value) {
7
+ const input = value.trim();
8
+ const nameMatch = input.match(/^(@[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._-]*|[a-z0-9][a-z0-9._-]*)(?:@(.+))?$/i);
9
+ if (!nameMatch || !nameMatch[1] || /\s/.test(nameMatch[2] ?? '')) {
10
+ throw new Error(`Provider install requires an npm package name, received: ${value}`);
11
+ }
12
+ return { packageName: nameMatch[1], target: nameMatch[2] || 'latest' };
13
+ }
14
+ function providerManager(packageName, env, dependencies) {
15
+ const resolved = (dependencies.resolveInvokingManager ??
16
+ (childEnv => resolveInvokingPackageManager({ env: childEnv })))(env);
17
+ if (!packageName.startsWith('@ali/') || resolved.command.includes('tnpm'))
18
+ return resolved;
19
+ const tnpm = (dependencies.findExecutable ?? findExecutable)('tnpm', {
20
+ env,
21
+ extraDirectories: [dirname(process.execPath)],
22
+ });
23
+ return tnpm ? { manager: 'npm', command: tnpm } : resolved;
24
+ }
25
+ function outputPath(output) {
26
+ const lines = output
27
+ .split(/\r?\n/)
28
+ .map(line => line.trim())
29
+ .filter(Boolean);
30
+ return lines.at(-1) ?? null;
31
+ }
32
+ async function resolveGlobalProviderPackageRoot(installation, packageName, runner, env) {
33
+ let args;
34
+ let toNodeModules;
35
+ switch (installation.manager) {
36
+ case 'npm':
37
+ case 'pnpm':
38
+ args = ['root', '-g'];
39
+ toNodeModules = value => value;
40
+ break;
41
+ case 'yarn':
42
+ args = ['global', 'dir'];
43
+ toNodeModules = value => join(value, 'node_modules');
44
+ break;
45
+ case 'bun':
46
+ args = ['pm', 'bin', '-g'];
47
+ toNodeModules = value => resolve(value, '..', 'install', 'global', 'node_modules');
48
+ break;
49
+ case 'volta':
50
+ throw new Error('Volta cannot manage a Provider package without a binary; use npm or pnpm');
51
+ }
52
+ const result = await runner(installation.command, args, {
53
+ capture: true,
54
+ env: prependCommandPath(installation.command, env),
55
+ });
56
+ const root = outputPath(result.stdout);
57
+ if (result.code !== 0 || !root) {
58
+ throw new Error(`${installation.manager} global package root lookup failed`);
59
+ }
60
+ return join(toNodeModules(root), ...packageName.split('/'));
61
+ }
62
+ function findRegisteredProvider(selector, listProviders) {
63
+ const providers = listProviders();
64
+ const matches = providers.filter(provider => provider.providerId === selector || provider.packageName === selector);
65
+ if (matches.length === 0)
66
+ throw new Error(`Provider is not registered: ${selector}`);
67
+ if (matches.length > 1)
68
+ throw new Error(`Provider selector is ambiguous: ${selector}`);
69
+ return matches[0];
70
+ }
71
+ async function runPackageCommand(installation, operation, packageName, target, runner, env) {
72
+ const command = buildGlobalPackageCommand(installation, operation, [packageName], target);
73
+ const result = await runner(command.command, command.args, {
74
+ env: prependCommandPath(command.command, env),
75
+ tee: true,
76
+ });
77
+ if (result.code !== 0) {
78
+ throw new Error(`${packageName} ${operation} failed (exit ${result.code})`);
79
+ }
80
+ }
81
+ export async function installProviderPackage(packageSpec, dependencies = {}) {
82
+ const { packageName, target } = parseProviderPackageSpec(packageSpec);
83
+ const env = process.env;
84
+ const runner = dependencies.runCommand ?? runCommand;
85
+ const installation = providerManager(packageName, env, dependencies);
86
+ await runPackageCommand(installation, 'install', packageName, target, runner, env);
87
+ const packageRoot = await (dependencies.resolvePackageRoot ?? resolveGlobalProviderPackageRoot)(installation, packageName, runner, env);
88
+ if (!(dependencies.existsSync ?? existsSync)(join(packageRoot, 'package.json'))) {
89
+ throw new Error(`${packageName} was installed but its package root was not found: ${packageRoot}`);
90
+ }
91
+ const manifest = (dependencies.registerPackage ?? registerProviderPackage)(packageRoot);
92
+ return { manifest, manager: installation.manager };
93
+ }
94
+ export async function updateProviderPackage(selector, dependencies = {}) {
95
+ const listProviders = dependencies.listProviders ?? listInstalledProviders;
96
+ const current = findRegisteredProvider(selector, listProviders);
97
+ const env = process.env;
98
+ const runner = dependencies.runCommand ?? runCommand;
99
+ const installation = (dependencies.resolvePackageManager ?? resolvePackageManagerInstallation)(current.packageRoot, current.packageName) ?? providerManager(current.packageName, env, dependencies);
100
+ (dependencies.stopProvider ?? stopProvider)(current.providerId);
101
+ await runPackageCommand(installation, 'update', current.packageName, 'latest', runner, env);
102
+ const manifest = (dependencies.registerPackage ?? registerProviderPackage)(current.packageRoot);
103
+ return { manifest, manager: installation.manager };
104
+ }
105
+ export async function uninstallProviderPackage(selector, dependencies = {}) {
106
+ const listProviders = dependencies.listProviders ?? listInstalledProviders;
107
+ const manifest = findRegisteredProvider(selector, listProviders);
108
+ const env = process.env;
109
+ const installation = (dependencies.resolvePackageManager ?? resolvePackageManagerInstallation)(manifest.packageRoot, manifest.packageName) ?? providerManager(manifest.packageName, env, dependencies);
110
+ (dependencies.stopProvider ?? stopProvider)(manifest.providerId);
111
+ await runPackageCommand(installation, 'uninstall', manifest.packageName, 'latest', dependencies.runCommand ?? runCommand, env);
112
+ (dependencies.unregisterProvider ?? uninstallProvider)(manifest.providerId);
113
+ return { manifest, manager: installation.manager };
114
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mearl/setup",
3
- "version": "2.12.0",
3
+ "version": "2.13.0",
4
4
  "description": "One-shot environment setup and configuration for Mearl",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -65,7 +65,8 @@
65
65
  "commander": "^15.0.0",
66
66
  "extract-zip": "^2.0.1",
67
67
  "ws": "^8.18.3",
68
- "@mearl/client": "2.12.0"
68
+ "@mearl/client": "2.13.0",
69
+ "@mearl/provider": "2.13.0"
69
70
  },
70
71
  "devDependencies": {
71
72
  "@types/node": "^24.9.1",