





















@@ -1,17 +1,10 @@
1-import os from "node:os";
2-import path from "node:path";
31import type { Command } from "commander";
42import { getRuntimeConfig, readConfigFileSnapshot, replaceConfigFile } from "../config/config.js";
5-import { resolveStateDir } from "../config/paths.js";
63import type { OpenClawConfig } from "../config/types.openclaw.js";
7-import {
8-tracePluginLifecyclePhase,
9-tracePluginLifecyclePhaseAsync,
10-} from "../plugins/plugin-lifecycle-trace.js";
4+import { tracePluginLifecyclePhaseAsync } from "../plugins/plugin-lifecycle-trace.js";
115import { defaultRuntime } from "../runtime.js";
126import { formatDocsLink } from "../terminal/links.js";
137import { theme } from "../terminal/theme.js";
14-import { shortenHomePath } from "../utils.js";
158import type { PluginInspectOptions } from "./plugins-inspect-command.js";
169import type { PluginsListOptions } from "./plugins-list-command.js";
1710import { applyParentDefaultHelpAction } from "./program/parent-default-help.js";
@@ -26,6 +19,11 @@ export type PluginMarketplaceListOptions = {
2619json?: boolean;
2720};
282122+export type PluginSearchOptions = {
23+json?: boolean;
24+limit?: number;
25+};
26+2927export type PluginUninstallOptions = {
3028keepFiles?: boolean;
3129/** @deprecated Use keepFiles. */
@@ -74,6 +72,17 @@ export function registerPluginsCli(program: Command) {
7472await runPluginsListCommand(opts);
7573});
767475+plugins
76+.command("search")
77+.description("Search ClawHub plugin packages")
78+.argument("[query...]", "Search query")
79+.option("--limit <n>", "Max results", (value) => Number.parseInt(value, 10))
80+.option("--json", "Print JSON", false)
81+.action(async (queryParts: string[], opts: PluginSearchOptions) => {
82+const { runPluginsSearchCommand } = await import("./plugins-search-command.js");
83+await runPluginsSearchCommand(queryParts, opts);
84+});
85+7786plugins
7887.command("inspect")
7988.alias("info")
@@ -162,172 +171,8 @@ export function registerPluginsCli(program: Command) {
162171.option("--force", "Skip confirmation prompt", false)
163172.option("--dry-run", "Show what would be removed without making changes", false)
164173.action(async (id: string, opts: PluginUninstallOptions) => {
165-const {
166- loadInstalledPluginIndexInstallRecords,
167- removePluginInstallRecordFromRecords,
168- withoutPluginInstallRecords,
169- withPluginInstallRecords,
170-} = await import("../plugins/installed-plugin-index-records.js");
171-const { buildPluginSnapshotReport } = await import("../plugins/status.js");
172-const {
173- applyPluginUninstallDirectoryRemoval,
174- formatUninstallActionLabels,
175- formatUninstallSlotResetPreview,
176- planPluginUninstall,
177- resolveUninstallChannelConfigKeys,
178-UNINSTALL_ACTION_LABELS,
179-} = await import("../plugins/uninstall.js");
180-const { commitPluginInstallRecordsWithConfig } =
181-await import("./plugins-install-record-commit.js");
182-const { refreshPluginRegistryAfterConfigMutation } =
183-await import("./plugins-registry-refresh.js");
184-const { resolvePluginUninstallId } = await import("./plugins-uninstall-selection.js");
185-const { promptYesNo } = await import("./prompt.js");
186-const snapshot = await tracePluginLifecyclePhaseAsync(
187-"config read",
188-() => readConfigFileSnapshot(),
189-{ command: "uninstall" },
190-);
191-const sourceConfig = (snapshot.sourceConfig ?? snapshot.config) as OpenClawConfig;
192-const installRecords = await tracePluginLifecyclePhaseAsync(
193-"install records load",
194-() => loadInstalledPluginIndexInstallRecords(),
195-{ command: "uninstall" },
196-);
197-const cfg = withPluginInstallRecords(sourceConfig, installRecords);
198-const report = tracePluginLifecyclePhase(
199-"plugin registry snapshot",
200-() => buildPluginSnapshotReport({ config: cfg }),
201-{ command: "uninstall" },
202-);
203-const extensionsDir = path.join(resolveStateDir(process.env, os.homedir), "extensions");
204-const keepFiles = Boolean(opts.keepFiles || opts.keepConfig);
205-206-if (opts.keepConfig) {
207-defaultRuntime.log(theme.warn("`--keep-config` is deprecated, use `--keep-files`."));
208-}
209-210-const { plugin, pluginId } = resolvePluginUninstallId({
211-rawId: id,
212-config: cfg,
213-plugins: report.plugins,
214-});
215-const hasEntry = pluginId in (cfg.plugins?.entries ?? {});
216-const hasInstall = pluginId in (cfg.plugins?.installs ?? {});
217-218-if (!hasEntry && !hasInstall) {
219-if (plugin) {
220-defaultRuntime.error(
221-`Plugin "${pluginId}" is not managed by plugins config/install records and cannot be uninstalled.`,
222-);
223-} else {
224-defaultRuntime.error(`Plugin not found: ${id}`);
225-}
226-return defaultRuntime.exit(1);
227-}
228-229-const channelIds = plugin?.status === "loaded" ? plugin.channelIds : undefined;
230-const plan = planPluginUninstall({
231-config: cfg,
232- pluginId,
233- channelIds,
234-deleteFiles: !keepFiles,
235- extensionsDir,
236-});
237-if (!plan.ok) {
238-defaultRuntime.error(plan.error);
239-return defaultRuntime.exit(1);
240-}
241-242-const preview: string[] = [];
243-if (plan.actions.entry) {
244-preview.push(UNINSTALL_ACTION_LABELS.entry);
245-}
246-if (plan.actions.install) {
247-preview.push(UNINSTALL_ACTION_LABELS.install);
248-}
249-if (plan.actions.allowlist) {
250-preview.push(UNINSTALL_ACTION_LABELS.allowlist);
251-}
252-if (plan.actions.denylist) {
253-preview.push(UNINSTALL_ACTION_LABELS.denylist);
254-}
255-if (plan.actions.loadPath) {
256-preview.push(UNINSTALL_ACTION_LABELS.loadPath);
257-}
258-if (plan.actions.memorySlot) {
259-preview.push(formatUninstallSlotResetPreview("memory"));
260-}
261-if (plan.actions.contextEngineSlot) {
262-preview.push(formatUninstallSlotResetPreview("contextEngine"));
263-}
264-const channels = cfg.channels as Record<string, unknown> | undefined;
265-if (plan.actions.channelConfig && hasInstall && channels) {
266-for (const key of resolveUninstallChannelConfigKeys(pluginId, { channelIds })) {
267-if (Object.hasOwn(channels, key)) {
268-preview.push(`${UNINSTALL_ACTION_LABELS.channelConfig} (channels.${key})`);
269-}
270-}
271-}
272-if (plan.directoryRemoval) {
273-preview.push(`directory: ${shortenHomePath(plan.directoryRemoval.target)}`);
274-}
275-276-const pluginName = plugin?.name || pluginId;
277-defaultRuntime.log(
278-`Plugin: ${theme.command(pluginName)}${pluginName !== pluginId ? theme.muted(` (${pluginId})`) : ""}`,
279-);
280-defaultRuntime.log(`Will remove: ${preview.length > 0 ? preview.join(", ") : "(nothing)"}`);
281-282-if (opts.dryRun) {
283-defaultRuntime.log(theme.muted("Dry run, no changes made."));
284-return;
285-}
286-287-if (!opts.force) {
288-const confirmed = await promptYesNo(`Uninstall plugin "${pluginId}"?`);
289-if (!confirmed) {
290-defaultRuntime.log("Cancelled.");
291-return;
292-}
293-}
294-295-const nextInstallRecords = removePluginInstallRecordFromRecords(installRecords, pluginId);
296-const nextConfig = withoutPluginInstallRecords(plan.config);
297-await tracePluginLifecyclePhaseAsync(
298-"config mutation",
299-() =>
300-commitPluginInstallRecordsWithConfig({
301-previousInstallRecords: installRecords,
302- nextInstallRecords,
303- nextConfig,
304- ...(snapshot.hash !== undefined ? { baseHash: snapshot.hash } : {}),
305-}),
306-{ command: "uninstall" },
307-);
308-const directoryResult = await applyPluginUninstallDirectoryRemoval(plan.directoryRemoval);
309-for (const warning of directoryResult.warnings) {
310-defaultRuntime.log(theme.warn(warning));
311-}
312-await refreshPluginRegistryAfterConfigMutation({
313-config: nextConfig,
314-reason: "source-changed",
315-installRecords: nextInstallRecords,
316-traceCommand: "uninstall",
317-logger: {
318-warn: (message) => defaultRuntime.log(theme.warn(message)),
319-},
320-});
321-322-const removed = formatUninstallActionLabels({
323- ...plan.actions,
324-directory: directoryResult.directoryRemoved,
325-});
326-327-defaultRuntime.log(
328-`Uninstalled plugin "${pluginId}". Removed: ${removed.length > 0 ? removed.join(", ") : "nothing"}.`,
329-);
330-defaultRuntime.log("Restart the gateway to apply changes.");
174+const { runPluginUninstallCommand } = await import("./plugins-uninstall-command.js");
175+await runPluginUninstallCommand(id, opts);
331176});
332177333178plugins
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。