@mearl/setup 2.15.0 → 2.15.1

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
@@ -35,10 +35,12 @@ setup 从 `Installed … skill(s)` 成功区块提取路径,仅注册本次安
35
35
  普通 skill 正常安装。输出格式无法识别时提示手动注册,不扫描其他 skill 或猜测安装结果。
36
36
 
37
37
  默认 `install` 和 `update` 完成后,setup 会用最多 5 秒的 `npm ping` 检查阿里内网 registry。
38
- 可访问时通过上述 Ali Skills 链路自动安装并注册 `tdbank-account`;该 registry 不用于下载插件。
38
+ 可访问时通过上述 Ali Skills 链路依次自动安装并注册 `buc-request` 与 `tdbank-account`;该 registry 不用于下载插件。
39
39
  探测不可用或插件安装失败不会破坏 Mearl 主环境的安装;`--skip-skill` 和
40
40
  `--target-line` 安装不执行自动插件步骤。
41
41
 
42
+ Mearl client 内置官方插件名称与安装来源目录。CLI、SDK、MCP 或另一个插件首次调用尚未注册的官方插件时,会通过内部幂等流程安装并重试一次;未知名称不会触发安装。
43
+
42
44
  自动注册默认使用安装目录名;入口可用 `export const name = 'yuque'` 指定简短命令名。
43
45
  重装会刷新同名绑定。每个入口必须默认导出 `register(app)`;完整协议见
44
46
  [Skill 插件规范](../skills/mearl-skill-creator/references/cli-plugin.md)。
@@ -55,7 +57,7 @@ path 接受目录或具体文件;目录默认读取 `scripts/main.mjs`,相
55
57
  两种注册流程都会检查本机 `@mearl/client` 和 `@mearl/native-host`:缺失或低于当前 setup 版本时,
56
58
  复用已有包管理器安装 setup 的对应版本,更新后再次验证;更高版本保持不动。
57
59
  native-host 会幂等初始化 Skills 模式。基础环境补齐或初始化失败时保留已安装的 skill,并停止注册。
58
- 注册后可在任意目录运行 `mearl <name> --help`,也可通过 `@mearl/client` 的 `invokePlugin` 或 MCP 的 `mearl_plugin` 调用;日常业务调用不执行安装或版本检查。
60
+ 注册后可在任意目录运行 `mearl <name> --help`,也可通过 `@mearl/client` 的 `invokePlugin` 或 MCP 的 `mearl_plugin` 调用。已注册插件的日常调用不执行安装或版本检查;只有缺失的官方插件会触发一次按需安装。
59
61
 
60
62
  不再需要插件时执行:
61
63
 
package/dist/cli.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  import { installMearlBrowserExtension } from './browserExtension.js';
3
3
  import { runMearlLifecycle, type MearlLifecycleOperation } from './lifecycle.js';
4
4
  import type { MearlProfile } from './profiles.js';
5
- import { installPlugins, setupPlugin, uninstallPlugin } from './plugin.js';
5
+ import { ensureOfficialPlugin, installPlugins, setupPlugin, uninstallPlugin } from './plugin.js';
6
6
  import { installProviderPackage, uninstallProviderPackage, updateProviderPackage } from './provider.js';
7
7
  export declare const SETUP_VERSION: string;
8
8
  interface ParsedArgs {
@@ -14,6 +14,7 @@ interface ParsedArgs {
14
14
  pluginName?: string;
15
15
  pluginPath?: string;
16
16
  pluginInstallArgs?: string[];
17
+ pluginEnsureName?: string;
17
18
  pluginUninstallName?: string;
18
19
  providerCommand?: 'install' | 'uninstall' | 'update';
19
20
  providerTarget?: string;
@@ -25,6 +26,7 @@ interface ParsedArgs {
25
26
  }
26
27
  export interface SetupCliDependencies {
27
28
  registerPlugin?: typeof setupPlugin;
29
+ ensureOfficialPlugin?: typeof ensureOfficialPlugin;
28
30
  installPlugins?: typeof installPlugins;
29
31
  uninstallPlugin?: typeof uninstallPlugin;
30
32
  installBrowserExtension?: typeof installMearlBrowserExtension;
package/dist/cli.js CHANGED
@@ -4,7 +4,7 @@ import { Command, CommanderError } from 'commander';
4
4
  import { installMearlBrowserExtension } from './browserExtension.js';
5
5
  import { runMearlLifecycle } from './lifecycle.js';
6
6
  import { isMearlReleaseLine } from './version.js';
7
- import { installPlugins, setupPlugin, uninstallPlugin } from './plugin.js';
7
+ import { ensureOfficialPlugin, installPlugins, setupPlugin, uninstallPlugin } from './plugin.js';
8
8
  import { installProviderPackage, uninstallProviderPackage, updateProviderPackage, } from './provider.js';
9
9
  const require = createRequire(import.meta.url);
10
10
  export const SETUP_VERSION = require('../package.json').version;
@@ -41,6 +41,12 @@ export function parseSetupArgs(argv) {
41
41
  if (argv[0] === 'plugin' && argv[1] === 'install') {
42
42
  return { ...baseParsedArgs(), operation: 'plugin', pluginInstallArgs: argv.slice(2) };
43
43
  }
44
+ if (argv[0] === 'plugin' && argv[1] === 'ensure') {
45
+ if (argv.length !== 3 || !argv[2]) {
46
+ throw new Error('plugin ensure requires exactly one official plugin name');
47
+ }
48
+ return { ...baseParsedArgs(), operation: 'plugin', pluginEnsureName: argv[2] };
49
+ }
44
50
  if (argv[0] === 'plugin' && argv[1] === 'uninstall') {
45
51
  if (argv.length !== 3 || !argv[2]) {
46
52
  throw new Error('plugin uninstall requires exactly one plugin name');
@@ -225,6 +231,13 @@ export async function main(argv = process.argv.slice(2), interactiveTerminal = p
225
231
  if (parsed.pluginInstallArgs) {
226
232
  return await (dependencies.installPlugins ?? installPlugins)(parsed.pluginInstallArgs);
227
233
  }
234
+ if (parsed.pluginEnsureName) {
235
+ const result = await (dependencies.ensureOfficialPlugin ?? ensureOfficialPlugin)(parsed.pluginEnsureName);
236
+ console.error(result === 'installed'
237
+ ? `Official plugin ${parsed.pluginEnsureName} installed.`
238
+ : `Official plugin ${parsed.pluginEnsureName} is already registered.`);
239
+ return 0;
240
+ }
228
241
  if (parsed.pluginUninstallName) {
229
242
  const result = await (dependencies.uninstallPlugin ?? uninstallPlugin)(parsed.pluginUninstallName);
230
243
  if (!result.removed) {
@@ -2,8 +2,7 @@ import { findPluginRegistration } from '@mearl/client/plugin';
2
2
  import { installPlugins, uninstallPlugin } from './plugin.js';
3
3
  import { findExecutable, type CommandRunner } from './process.js';
4
4
  export declare const ALIBABA_NPM_REGISTRY = "https://registry.anpm.alibaba-inc.com/";
5
- export declare const TDBANK_PLUGIN_INSTALL_ARGS: readonly ["trip/mearl", "--skill", "tdbank-account", "--yes"];
6
- export declare const INTERNAL_PLUGIN_MANAGER = "@mearl/setup";
5
+ export declare const ALIBABA_INTERNAL_PLUGIN_NAMES: string[];
7
6
  export interface InternalPluginOptions {
8
7
  env?: NodeJS.ProcessEnv;
9
8
  runCommand?: CommandRunner;
@@ -17,6 +16,6 @@ export interface InternalPluginDependencies {
17
16
  uninstallPlugin?: typeof uninstallPlugin;
18
17
  }
19
18
  export declare function canAccessAlibabaNpmRegistry(options?: InternalPluginOptions, dependencies?: Pick<InternalPluginDependencies, 'findExecutable'>): Promise<boolean>;
20
- /** Uses the internal registry only as an intranet probe; the plugin is installed by Ali Skills. */
19
+ /** Uses the internal registry only as an intranet probe; Ali Skills installs the plugins. */
21
20
  export declare function installAlibabaInternalPlugins(options?: InternalPluginOptions, dependencies?: InternalPluginDependencies): Promise<'installed' | 'skipped' | 'failed'>;
22
21
  export declare function uninstallAlibabaInternalPlugins(options?: InternalPluginOptions, dependencies?: InternalPluginDependencies): Promise<'uninstalled' | 'skipped' | 'failed'>;
@@ -1,16 +1,9 @@
1
1
  import { dirname } from 'node:path';
2
- import { findPluginRegistration } from '@mearl/client/plugin';
2
+ import { findOfficialPlugin, findPluginRegistration, listOfficialPluginNames, OFFICIAL_PLUGIN_MANAGER, } from '@mearl/client/plugin';
3
3
  import { installPlugins, uninstallPlugin } from './plugin.js';
4
4
  import { findExecutable, prependCommandPath, runCommand } from './process.js';
5
5
  export const ALIBABA_NPM_REGISTRY = 'https://registry.anpm.alibaba-inc.com/';
6
- export const TDBANK_PLUGIN_INSTALL_ARGS = [
7
- 'trip/mearl',
8
- '--skill',
9
- 'tdbank-account',
10
- '--yes',
11
- ];
12
- export const INTERNAL_PLUGIN_MANAGER = '@mearl/setup';
13
- const TDBANK_PLUGIN_NAME = 'tdbank';
6
+ export const ALIBABA_INTERNAL_PLUGIN_NAMES = listOfficialPluginNames('alibaba');
14
7
  export async function canAccessAlibabaNpmRegistry(options = {}, dependencies = {}) {
15
8
  const env = options.env ?? process.env;
16
9
  const runner = options.runCommand ?? runCommand;
@@ -38,48 +31,67 @@ export async function canAccessAlibabaNpmRegistry(options = {}, dependencies = {
38
31
  return false;
39
32
  }
40
33
  }
41
- /** Uses the internal registry only as an intranet probe; the plugin is installed by Ali Skills. */
34
+ /** Uses the internal registry only as an intranet probe; Ali Skills installs the plugins. */
42
35
  export async function installAlibabaInternalPlugins(options = {}, dependencies = {}) {
43
36
  const writeLine = options.writeLine ?? (line => console.error(line));
44
- try {
45
- const registration = (dependencies.findPluginRegistration ?? findPluginRegistration)(TDBANK_PLUGIN_NAME);
46
- if (registration && registration.managedBy !== INTERNAL_PLUGIN_MANAGER) {
47
- writeLine('TDBank plugin: existing user registration kept.');
48
- return 'skipped';
37
+ const registrationFor = dependencies.findPluginRegistration ?? findPluginRegistration;
38
+ const candidates = ALIBABA_INTERNAL_PLUGIN_NAMES.filter(name => {
39
+ const registration = registrationFor(name);
40
+ if (registration && registration.managedBy !== OFFICIAL_PLUGIN_MANAGER) {
41
+ writeLine(`${name} plugin: existing user registration kept.`);
42
+ return false;
43
+ }
44
+ return true;
45
+ });
46
+ if (candidates.length === 0)
47
+ return 'skipped';
48
+ const probe = dependencies.probeAlibabaRegistry ?? (input => canAccessAlibabaNpmRegistry(input));
49
+ if (!(await probe(options)))
50
+ return 'skipped';
51
+ let installed = false;
52
+ let failed = false;
53
+ for (const name of candidates) {
54
+ const definition = findOfficialPlugin(name);
55
+ try {
56
+ const code = await (dependencies.installPlugins ?? installPlugins)([...definition.installArgs], options.runCommand, { registrationManagedBy: OFFICIAL_PLUGIN_MANAGER });
57
+ if (code !== 0) {
58
+ failed = true;
59
+ writeLine(`${name} plugin: install failed (exit ${code}).`);
60
+ continue;
61
+ }
62
+ installed = true;
63
+ writeLine(`${name} plugin: installed and registered.`);
49
64
  }
50
- const probe = dependencies.probeAlibabaRegistry ?? (input => canAccessAlibabaNpmRegistry(input));
51
- if (!(await probe(options)))
52
- return 'skipped';
53
- const code = await (dependencies.installPlugins ?? installPlugins)([...TDBANK_PLUGIN_INSTALL_ARGS], options.runCommand, { registrationManagedBy: INTERNAL_PLUGIN_MANAGER });
54
- if (code !== 0) {
55
- writeLine(`TDBank plugin: install failed (exit ${code}).`);
56
- return 'failed';
65
+ catch (error) {
66
+ failed = true;
67
+ writeLine(`${name} plugin: ${error instanceof Error ? error.message : String(error)}; skipped.`);
57
68
  }
58
- writeLine('TDBank plugin: installed and registered.');
59
- return 'installed';
60
- }
61
- catch (error) {
62
- writeLine(`TDBank plugin: ${error instanceof Error ? error.message : String(error)}; skipped.`);
63
- return 'failed';
64
69
  }
70
+ return failed ? 'failed' : installed ? 'installed' : 'skipped';
65
71
  }
66
72
  export async function uninstallAlibabaInternalPlugins(options = {}, dependencies = {}) {
67
73
  const writeLine = options.writeLine ?? (line => console.error(line));
68
- try {
69
- const registration = (dependencies.findPluginRegistration ?? findPluginRegistration)(TDBANK_PLUGIN_NAME);
70
- if (registration?.managedBy !== INTERNAL_PLUGIN_MANAGER) {
71
- if (registration)
72
- writeLine('TDBank plugin: existing user registration kept.');
73
- return 'skipped';
74
+ const registrationFor = dependencies.findPluginRegistration ?? findPluginRegistration;
75
+ let uninstalled = false;
76
+ let failed = false;
77
+ for (const name of [...ALIBABA_INTERNAL_PLUGIN_NAMES].reverse()) {
78
+ try {
79
+ const registration = registrationFor(name);
80
+ if (registration?.managedBy !== OFFICIAL_PLUGIN_MANAGER) {
81
+ if (registration)
82
+ writeLine(`${name} plugin: existing user registration kept.`);
83
+ continue;
84
+ }
85
+ const result = await (dependencies.uninstallPlugin ?? uninstallPlugin)(name, options.runCommand);
86
+ if (!result.removed)
87
+ continue;
88
+ uninstalled = true;
89
+ writeLine(`${name} plugin: uninstalled.`);
90
+ }
91
+ catch (error) {
92
+ failed = true;
93
+ writeLine(`${name} plugin: ${error instanceof Error ? error.message : String(error)}; uninstall failed.`);
74
94
  }
75
- const result = await (dependencies.uninstallPlugin ?? uninstallPlugin)(TDBANK_PLUGIN_NAME, options.runCommand);
76
- if (!result.removed)
77
- return 'skipped';
78
- writeLine('TDBank plugin: uninstalled.');
79
- return 'uninstalled';
80
- }
81
- catch (error) {
82
- writeLine(`TDBank plugin: ${error instanceof Error ? error.message : String(error)}; uninstall failed.`);
83
- return 'failed';
84
95
  }
96
+ return failed ? 'failed' : uninstalled ? 'uninstalled' : 'skipped';
85
97
  }
package/dist/lifecycle.js CHANGED
@@ -313,7 +313,7 @@ export async function runMearlLifecycle(options, dependencies = {}) {
313
313
  if (packagesOk && skillOk && selectedUsesClient && options.skipSkill !== true) {
314
314
  if (options.operation === 'uninstall') {
315
315
  if (remainingClientProfiles.length > 0) {
316
- writeLine(`TDBank plugin: kept for ${remainingClientProfiles.join(', ')}.`);
316
+ writeLine(`Internal plugins: kept for ${remainingClientProfiles.join(', ')}.`);
317
317
  }
318
318
  else {
319
319
  try {
@@ -325,7 +325,7 @@ export async function runMearlLifecycle(options, dependencies = {}) {
325
325
  })) !== 'failed';
326
326
  }
327
327
  catch (error) {
328
- writeLine(`TDBank plugin: ${error instanceof Error ? error.message : String(error)}; uninstall failed.`);
328
+ writeLine(`Internal plugins: ${error instanceof Error ? error.message : String(error)}; uninstall failed.`);
329
329
  internalPluginsOk = false;
330
330
  }
331
331
  }
@@ -339,7 +339,7 @@ export async function runMearlLifecycle(options, dependencies = {}) {
339
339
  });
340
340
  }
341
341
  catch (error) {
342
- writeLine(`TDBank plugin: ${error instanceof Error ? error.message : String(error)}; skipped.`);
342
+ writeLine(`Internal plugins: ${error instanceof Error ? error.message : String(error)}; skipped.`);
343
343
  }
344
344
  }
345
345
  }
package/dist/plugin.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { type CommandRunner } from './process.js';
2
2
  export declare function setupPlugin(name: string, target: string): Promise<string>;
3
+ export declare function ensureOfficialPlugin(name: string, runner?: CommandRunner): Promise<'existing' | 'installed'>;
3
4
  export interface PluginUninstallResult {
4
5
  entryMissing?: boolean;
5
6
  removed: boolean;
package/dist/plugin.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { existsSync, mkdirSync, rmdirSync, statSync } from 'node:fs';
2
2
  import { homedir } from 'node:os';
3
3
  import { basename, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
4
- import { assertPluginName, findPluginEntry, listPluginNames, loadPlugin, registerPlugin, resolvePluginEntry, unregisterPlugin, } from '@mearl/client/plugin';
4
+ import { assertPluginName, findOfficialPlugin, findPluginEntry, findPluginRegistration, listPluginNames, loadPlugin, OFFICIAL_PLUGIN_MANAGER, registerPlugin, resolvePluginEntry, unregisterPlugin, } from '@mearl/client/plugin';
5
5
  import { ensurePluginRuntime } from './pluginRuntime.js';
6
6
  import { resolveAliSkillsInvocation, stripAnsi } from './aliSkills.js';
7
7
  import { findExecutable, prependNodePath, runCommand } from './process.js';
@@ -21,6 +21,22 @@ export async function setupPlugin(name, target) {
21
21
  await ensurePluginRuntime();
22
22
  return registerPlugin(name, entry, plugin.description);
23
23
  }
24
+ export async function ensureOfficialPlugin(name, runner = runCommand) {
25
+ const definition = findOfficialPlugin(name);
26
+ if (!definition)
27
+ throw new Error(`未知官方插件: ${name}`);
28
+ if (findPluginRegistration(name))
29
+ return 'existing';
30
+ const code = await installPlugins([...definition.installArgs], runner, {
31
+ registrationManagedBy: OFFICIAL_PLUGIN_MANAGER,
32
+ });
33
+ if (code !== 0)
34
+ throw new Error(`官方插件 ${name} 安装失败 (exit ${code})`);
35
+ const registration = findPluginRegistration(name);
36
+ if (!registration)
37
+ throw new Error(`官方插件 ${name} 安装完成后仍未注册`);
38
+ return 'installed';
39
+ }
24
40
  function globalAliSkill(entry) {
25
41
  const globalSkillsDirectory = join(homedir(), '.agents', 'skills');
26
42
  const relativeEntry = relative(globalSkillsDirectory, resolve(entry));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mearl/setup",
3
- "version": "2.15.0",
3
+ "version": "2.15.1",
4
4
  "description": "One-shot environment setup and configuration for Mearl",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -61,8 +61,8 @@
61
61
  "commander": "^15.0.0",
62
62
  "extract-zip": "^2.0.1",
63
63
  "ws": "^8.18.3",
64
- "@mearl/client": "2.15.0",
65
- "@mearl/provider": "2.15.0"
64
+ "@mearl/client": "2.15.1",
65
+ "@mearl/provider": "2.15.1"
66
66
  },
67
67
  "devDependencies": {
68
68
  "@types/node": "^24.9.1",