mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-21 13:44:03 +00:00
CLI: restore lightweight root help and scoped status plugin preload
This commit is contained in:
@@ -2,14 +2,32 @@ import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent
|
||||
import { loadConfig } from "../config/config.js";
|
||||
import { createSubsystemLogger } from "../logging.js";
|
||||
import { loadOpenClawPlugins } from "../plugins/loader.js";
|
||||
import { loadPluginManifestRegistry } from "../plugins/manifest-registry.js";
|
||||
import { getActivePluginRegistry } from "../plugins/runtime.js";
|
||||
import type { PluginLogger } from "../plugins/types.js";
|
||||
|
||||
const log = createSubsystemLogger("plugins");
|
||||
let pluginRegistryLoaded = false;
|
||||
let pluginRegistryLoaded: "none" | "channels" | "all" = "none";
|
||||
|
||||
export function ensurePluginRegistryLoaded(): void {
|
||||
if (pluginRegistryLoaded) {
|
||||
export type PluginRegistryScope = "channels" | "all";
|
||||
|
||||
function resolveChannelPluginIds(params: {
|
||||
config: ReturnType<typeof loadConfig>;
|
||||
workspaceDir?: string;
|
||||
env: NodeJS.ProcessEnv;
|
||||
}): string[] {
|
||||
return loadPluginManifestRegistry({
|
||||
config: params.config,
|
||||
workspaceDir: params.workspaceDir,
|
||||
env: params.env,
|
||||
})
|
||||
.plugins.filter((plugin) => plugin.channels.length > 0)
|
||||
.map((plugin) => plugin.id);
|
||||
}
|
||||
|
||||
export function ensurePluginRegistryLoaded(options?: { scope?: PluginRegistryScope }): void {
|
||||
const scope = options?.scope ?? "all";
|
||||
if (pluginRegistryLoaded === "all" || pluginRegistryLoaded === scope) {
|
||||
return;
|
||||
}
|
||||
const active = getActivePluginRegistry();
|
||||
@@ -19,7 +37,7 @@ export function ensurePluginRegistryLoaded(): void {
|
||||
active &&
|
||||
(active.plugins.length > 0 || active.channels.length > 0 || active.tools.length > 0)
|
||||
) {
|
||||
pluginRegistryLoaded = true;
|
||||
pluginRegistryLoaded = "all";
|
||||
return;
|
||||
}
|
||||
const config = loadConfig();
|
||||
@@ -34,6 +52,15 @@ export function ensurePluginRegistryLoaded(): void {
|
||||
config,
|
||||
workspaceDir,
|
||||
logger,
|
||||
...(scope === "channels"
|
||||
? {
|
||||
onlyPluginIds: resolveChannelPluginIds({
|
||||
config,
|
||||
workspaceDir,
|
||||
env: process.env,
|
||||
}),
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
pluginRegistryLoaded = true;
|
||||
pluginRegistryLoaded = scope;
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@ describe("registerPreActionHooks", () => {
|
||||
runtime: runtimeMock,
|
||||
commandPath: ["status"],
|
||||
});
|
||||
expect(ensurePluginRegistryLoadedMock).toHaveBeenCalledTimes(1);
|
||||
expect(ensurePluginRegistryLoadedMock).toHaveBeenCalledWith({ scope: "channels" });
|
||||
expect(process.title).toBe("openclaw-status");
|
||||
|
||||
vi.clearAllMocks();
|
||||
@@ -164,7 +164,7 @@ describe("registerPreActionHooks", () => {
|
||||
runtime: runtimeMock,
|
||||
commandPath: ["message", "send"],
|
||||
});
|
||||
expect(ensurePluginRegistryLoadedMock).toHaveBeenCalledTimes(1);
|
||||
expect(ensurePluginRegistryLoadedMock).toHaveBeenCalledWith({ scope: "all" });
|
||||
});
|
||||
|
||||
it("skips help/version preaction and respects banner opt-out", async () => {
|
||||
|
||||
@@ -67,6 +67,10 @@ function loadPluginRegistryModule() {
|
||||
return pluginRegistryModulePromise;
|
||||
}
|
||||
|
||||
function resolvePluginRegistryScope(commandPath: string[]): "channels" | "all" {
|
||||
return commandPath[0] === "status" || commandPath[0] === "health" ? "channels" : "all";
|
||||
}
|
||||
|
||||
function getRootCommand(command: Command): Command {
|
||||
let current = command;
|
||||
while (current.parent) {
|
||||
@@ -136,7 +140,7 @@ export function registerPreActionHooks(program: Command, programVersion: string)
|
||||
// Load plugins for commands that need channel access
|
||||
if (PLUGIN_REQUIRED_COMMANDS.has(commandPath[0])) {
|
||||
const { ensurePluginRegistryLoaded } = await loadPluginRegistryModule();
|
||||
ensurePluginRegistryLoaded();
|
||||
ensurePluginRegistryLoaded({ scope: resolvePluginRegistryScope(commandPath) });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ describe("tryRouteCli", () => {
|
||||
vi.resetModules();
|
||||
({ tryRouteCli } = await import("./route.js"));
|
||||
findRoutedCommandMock.mockReturnValue({
|
||||
loadPlugins: false,
|
||||
loadPlugins: true,
|
||||
run: runRouteMock,
|
||||
});
|
||||
});
|
||||
@@ -59,6 +59,7 @@ describe("tryRouteCli", () => {
|
||||
suppressDoctorStdout: true,
|
||||
}),
|
||||
);
|
||||
expect(ensurePluginRegistryLoadedMock).toHaveBeenCalledWith({ scope: "channels" });
|
||||
});
|
||||
|
||||
it("does not pass suppressDoctorStdout for routed non-json commands", async () => {
|
||||
@@ -68,6 +69,7 @@ describe("tryRouteCli", () => {
|
||||
runtime: expect.any(Object),
|
||||
commandPath: ["status"],
|
||||
});
|
||||
expect(ensurePluginRegistryLoadedMock).toHaveBeenCalledWith({ scope: "channels" });
|
||||
});
|
||||
|
||||
it("routes status when root options precede the command", async () => {
|
||||
@@ -80,5 +82,6 @@ describe("tryRouteCli", () => {
|
||||
runtime: expect.any(Object),
|
||||
commandPath: ["status"],
|
||||
});
|
||||
expect(ensurePluginRegistryLoadedMock).toHaveBeenCalledWith({ scope: "channels" });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -22,7 +22,12 @@ async function prepareRoutedCommand(params: {
|
||||
const shouldLoadPlugins =
|
||||
typeof params.loadPlugins === "function" ? params.loadPlugins(params.argv) : params.loadPlugins;
|
||||
if (shouldLoadPlugins) {
|
||||
ensurePluginRegistryLoaded();
|
||||
ensurePluginRegistryLoaded({
|
||||
scope:
|
||||
params.commandPath[0] === "status" || params.commandPath[0] === "health"
|
||||
? "channels"
|
||||
: "all",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user