





















@@ -7,11 +7,13 @@ import { handlePluginsCommand } from "./commands-plugins.js";
77import { buildPluginsCommandParams } from "./commands.test-harness.js";
8899const {
10+ installPluginFromNpmSpecMock,
1011 installPluginFromPathMock,
1112 installPluginFromClawHubMock,
1213 installPluginFromGitSpecMock,
1314 persistPluginInstallMock,
1415} = vi.hoisted(() => ({
16+installPluginFromNpmSpecMock: vi.fn(),
1517installPluginFromPathMock: vi.fn(),
1618installPluginFromClawHubMock: vi.fn(),
1719installPluginFromGitSpecMock: vi.fn(),
@@ -24,6 +26,7 @@ vi.mock("../../plugins/install.js", async () => {
2426);
2527return {
2628 ...actual,
29+installPluginFromNpmSpec: installPluginFromNpmSpecMock,
2730installPluginFromPath: installPluginFromPathMock,
2831};
2932});
@@ -64,6 +67,7 @@ function buildPluginsParams(commandBodyNormalized: string, workspaceDir: string)
64676568describe("handleCommands /plugins install", () => {
6669afterEach(async () => {
70+installPluginFromNpmSpecMock.mockReset();
6771installPluginFromPathMock.mockReset();
6872installPluginFromClawHubMock.mockReset();
6973installPluginFromGitSpecMock.mockReset();
@@ -253,4 +257,60 @@ describe("handleCommands /plugins install", () => {
253257);
254258});
255259});
260+261+it("trusts catalog npm package installs with alternate selectors", async () => {
262+installPluginFromNpmSpecMock.mockResolvedValue({
263+ok: true,
264+pluginId: "wecom-openclaw-plugin",
265+targetDir: "/tmp/wecom-openclaw-plugin",
266+version: "2026.4.23",
267+extensions: ["index.js"],
268+npmResolution: {
269+name: "@wecom/wecom-openclaw-plugin",
270+version: "2026.4.23",
271+resolvedSpec: "@wecom/wecom-openclaw-plugin@2026.4.23",
272+integrity: "sha512-wecom",
273+resolvedAt: "2026-05-04T20:00:00.000Z",
274+},
275+});
276+persistPluginInstallMock.mockResolvedValue({});
277+278+await withTempHome("openclaw-command-plugins-home-", async () => {
279+const workspaceDir = await workspaceHarness.createWorkspace();
280+const params = buildPluginsParams(
281+"/plugins install @wecom/wecom-openclaw-plugin@latest",
282+workspaceDir,
283+);
284+const result = await handlePluginsCommand(params, true);
285+if (result === null) {
286+throw new Error("expected plugin install result");
287+}
288+expect(result.reply?.text).toContain('Installed plugin "wecom-openclaw-plugin"');
289+expect(installPluginFromNpmSpecMock).toHaveBeenCalledWith(
290+expect.objectContaining({
291+spec: "@wecom/wecom-openclaw-plugin@latest",
292+expectedPluginId: "wecom-openclaw-plugin",
293+trustedSourceLinkedOfficialInstall: true,
294+}),
295+);
296+expect(installPluginFromNpmSpecMock).toHaveBeenCalledWith(
297+expect.not.objectContaining({
298+expectedIntegrity: expect.any(String),
299+}),
300+);
301+expect(persistPluginInstallMock).toHaveBeenCalledWith(
302+expect.objectContaining({
303+pluginId: "wecom-openclaw-plugin",
304+install: expect.objectContaining({
305+source: "npm",
306+spec: "@wecom/wecom-openclaw-plugin@latest",
307+installPath: "/tmp/wecom-openclaw-plugin",
308+version: "2026.4.23",
309+resolvedName: "@wecom/wecom-openclaw-plugin",
310+resolvedVersion: "2026.4.23",
311+}),
312+}),
313+);
314+});
315+});
256316});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。