From 41e87013ae48dd4166e7d7357f3cd2c7c413dc1c Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 25 Aug 2026 06:24:58 -0700 Subject: [PATCH] fix(cli): preserve active target in plugin install hints (#129283) --- src/cli/plugins-search-command.test.ts | 40 ++++++++++++++++++++++---- src/cli/plugins-search-command.ts | 3 +- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/cli/plugins-search-command.test.ts b/src/cli/plugins-search-command.test.ts index f3380fcb282f..4392b9a20045 100644 --- a/src/cli/plugins-search-command.test.ts +++ b/src/cli/plugins-search-command.test.ts @@ -1,6 +1,7 @@ // Plugins search command tests cover plugin search command registration and results. import { Command } from "commander"; import { beforeEach, describe, expect, it, vi } from "vitest"; +import { withEnvAsync } from "../test-utils/env.js"; const mocks = vi.hoisted(() => { const logs: string[] = []; @@ -50,7 +51,32 @@ describe("plugins search command", () => { mocks.searchClawHubPackages.mockReset(); }); - it("searches ClawHub code and bundle plugin families", async () => { + it.each([ + { + context: "default", + profile: undefined, + container: undefined, + command: "openclaw plugins install clawhub:openclaw-calendar", + }, + { + context: "profile", + profile: "work", + container: undefined, + command: "openclaw --profile work plugins install clawhub:openclaw-calendar", + }, + { + context: "container", + profile: undefined, + container: "staging", + command: "openclaw --container staging plugins install clawhub:openclaw-calendar", + }, + { + context: "container over profile", + profile: "work", + container: "staging", + command: "openclaw --container staging plugins install clawhub:openclaw-calendar", + }, + ])("searches ClawHub plugin families with the $context install context", async (scenario) => { mocks.searchClawHubPackages .mockResolvedValueOnce([ { @@ -85,7 +111,13 @@ describe("plugins search command", () => { }, ]); - await runPluginsSearchCommand(["calendar"], { limit: 5 }, mocks.runtime); + await withEnvAsync( + { + OPENCLAW_PROFILE: scenario.profile, + OPENCLAW_CONTAINER_HINT: scenario.container, + }, + () => runPluginsSearchCommand(["calendar"], { limit: 5 }, mocks.runtime), + ); expect(mocks.searchClawHubPackages).toHaveBeenCalledWith({ query: "calendar", @@ -98,9 +130,7 @@ describe("plugins search command", () => { limit: 5, }); expect(mocks.logs.join("\n")).toContain("openclaw-calendar"); - expect(mocks.logs.join("\n")).toContain( - "Install: openclaw plugins install clawhub:openclaw-calendar", - ); + expect(mocks.logs.join("\n")).toContain(`Install: ${scenario.command}`); }); it("writes JSON results when requested", async () => { diff --git a/src/cli/plugins-search-command.ts b/src/cli/plugins-search-command.ts index 308d2459656e..5b2b12cd1ba5 100644 --- a/src/cli/plugins-search-command.ts +++ b/src/cli/plugins-search-command.ts @@ -5,6 +5,7 @@ import type { ClawHubPackageSearchResult } from "../infra/clawhub-packages.js"; import { formatErrorMessage } from "../infra/errors.js"; import { searchInstallablePluginPackages } from "../plugins/catalog-search.js"; import { defaultRuntime, writeRuntimeJson, type RuntimeEnv } from "../runtime.js"; +import { formatCliCommand } from "./command-format.js"; import { ExpectedCliError } from "./failure-output.js"; /** Options accepted by `openclaw plugins search`. */ @@ -22,7 +23,7 @@ function formatPackageSearchLine(entry: ClawHubPackageSearchResult): string { pkg.latestVersion ? `v${pkg.latestVersion}` : undefined, ].filter(Boolean); const summary = pkg.summary ? theme.muted(` — ${pkg.summary}`) : ""; - return `${pkg.name} ${theme.muted(flags.join(" | "))}${summary}\n ${theme.muted(`Install: openclaw plugins install clawhub:${pkg.name}`)}`; + return `${pkg.name} ${theme.muted(flags.join(" | "))}${summary}\n ${theme.muted(`Install: ${formatCliCommand(`openclaw plugins install clawhub:${pkg.name}`)}`)}`; } /** Search ClawHub for installable plugins and write JSON or terminal output. */