mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 21:07:01 -06:00
Fix memory plugin CLI help dispatch (#83841)
* fix cli help for active memory plugin * docs add changelog for memory cli help * test fix root help mock type
This commit is contained in:
@@ -35,7 +35,7 @@ describe("command-registration-policy", () => {
|
||||
primary: "voicecall",
|
||||
hasBuiltinPrimary: false,
|
||||
}),
|
||||
).toBe(true);
|
||||
).toBe(false);
|
||||
expect(
|
||||
shouldSkipPluginCommandRegistration({
|
||||
argv: ["node", "openclaw", "help", "--help"],
|
||||
|
||||
@@ -22,7 +22,9 @@ export function shouldSkipPluginCommandRegistration(params: {
|
||||
return invocation.hasHelpOrVersion && invocation.commandPath.length <= 1;
|
||||
}
|
||||
if (invocation.hasHelpOrVersion) {
|
||||
return true;
|
||||
return (
|
||||
!params.primary || params.hasBuiltinPrimary || isReservedNonPluginCommandRoot(params.primary)
|
||||
);
|
||||
}
|
||||
if (params.hasBuiltinPrimary) {
|
||||
return true;
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { loadRootHelpRenderOptionsForConfigSensitivePlugins } from "./root-help-live-config.js";
|
||||
|
||||
const readConfigFileSnapshotMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("../config/config.js", () => ({
|
||||
readConfigFileSnapshot: readConfigFileSnapshotMock,
|
||||
}));
|
||||
|
||||
describe("root help live config", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("uses precomputed help when plugin-sensitive config is invalid", async () => {
|
||||
readConfigFileSnapshotMock.mockResolvedValueOnce({
|
||||
valid: false,
|
||||
sourceConfig: {
|
||||
plugins: {
|
||||
slots: {
|
||||
memory: "memory-lancedb",
|
||||
},
|
||||
},
|
||||
},
|
||||
runtimeConfig: {},
|
||||
});
|
||||
|
||||
await expect(loadRootHelpRenderOptionsForConfigSensitivePlugins({})).resolves.toBeNull();
|
||||
});
|
||||
|
||||
it("uses snapshot runtime config when plugin config affects help", async () => {
|
||||
const runtimeConfig = {
|
||||
plugins: {
|
||||
slots: {
|
||||
memory: "memory-lancedb",
|
||||
},
|
||||
},
|
||||
};
|
||||
const env = {};
|
||||
readConfigFileSnapshotMock.mockResolvedValueOnce({
|
||||
valid: true,
|
||||
sourceConfig: runtimeConfig,
|
||||
runtimeConfig,
|
||||
});
|
||||
|
||||
await expect(loadRootHelpRenderOptionsForConfigSensitivePlugins(env)).resolves.toEqual({
|
||||
config: runtimeConfig,
|
||||
env,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,53 @@
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import type { RootHelpRenderOptions } from "./program/root-help.js";
|
||||
|
||||
function hasEntries(value: object | undefined): boolean {
|
||||
return !!value && Object.keys(value).length > 0;
|
||||
}
|
||||
|
||||
function hasListEntries(value: string[] | undefined): boolean {
|
||||
return Array.isArray(value) && value.length > 0;
|
||||
}
|
||||
|
||||
export function hasPluginHelpAffectingConfig(config: OpenClawConfig | null | undefined): boolean {
|
||||
const plugins = config?.plugins;
|
||||
if (!plugins) {
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
plugins.enabled === false ||
|
||||
hasListEntries(plugins.allow) ||
|
||||
hasListEntries(plugins.deny) ||
|
||||
plugins.bundledDiscovery !== undefined ||
|
||||
hasListEntries(plugins.load?.paths) ||
|
||||
hasEntries(plugins.slots) ||
|
||||
hasEntries(plugins.entries) ||
|
||||
hasEntries(plugins.installs)
|
||||
);
|
||||
}
|
||||
|
||||
export function hasPluginHelpAffectingEnv(env: NodeJS.ProcessEnv): boolean {
|
||||
return Boolean(
|
||||
env.OPENCLAW_BUNDLED_PLUGINS_DIR?.trim() || env.OPENCLAW_DISABLE_BUNDLED_PLUGINS?.trim(),
|
||||
);
|
||||
}
|
||||
|
||||
export async function loadRootHelpRenderOptionsForConfigSensitivePlugins(
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
): Promise<RootHelpRenderOptions | null> {
|
||||
const configModule = await import("../config/config.js");
|
||||
const snapshot = await configModule.readConfigFileSnapshot({
|
||||
observe: false,
|
||||
skipPluginValidation: true,
|
||||
});
|
||||
if (!snapshot.valid) {
|
||||
return null;
|
||||
}
|
||||
if (!hasPluginHelpAffectingEnv(env) && !hasPluginHelpAffectingConfig(snapshot.sourceConfig)) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
config: snapshot.runtimeConfig,
|
||||
env,
|
||||
};
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import process from "node:process";
|
||||
import { CommanderError } from "commander";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { loggingState } from "../logging/state.js";
|
||||
import type { RootHelpRenderOptions } from "./program/root-help.js";
|
||||
import { runCli, shouldStartProxyForCli } from "./run-main.js";
|
||||
|
||||
const tryRouteCliMock = vi.hoisted(() => vi.fn());
|
||||
@@ -18,6 +19,9 @@ const startTaskRegistryMaintenanceMock = vi.hoisted(() => vi.fn());
|
||||
const outputRootHelpMock = vi.hoisted(() => vi.fn());
|
||||
const outputPrecomputedRootHelpTextMock = vi.hoisted(() => vi.fn(() => false));
|
||||
const outputPrecomputedBrowserHelpTextMock = vi.hoisted(() => vi.fn(() => false));
|
||||
const loadRootHelpRenderOptionsForConfigSensitivePluginsMock = vi.hoisted(() =>
|
||||
vi.fn<() => Promise<RootHelpRenderOptions | null>>(async () => null),
|
||||
);
|
||||
const buildProgramMock = vi.hoisted(() => vi.fn());
|
||||
const getProgramContextMock = vi.hoisted(() => vi.fn(() => null));
|
||||
const registerCoreCliByNameMock = vi.hoisted(() => vi.fn());
|
||||
@@ -168,6 +172,11 @@ vi.mock("./root-help-metadata.js", () => ({
|
||||
outputPrecomputedRootHelpText: outputPrecomputedRootHelpTextMock,
|
||||
}));
|
||||
|
||||
vi.mock("./root-help-live-config.js", () => ({
|
||||
loadRootHelpRenderOptionsForConfigSensitivePlugins:
|
||||
loadRootHelpRenderOptionsForConfigSensitivePluginsMock,
|
||||
}));
|
||||
|
||||
vi.mock("./program.js", () => ({
|
||||
buildProgram: buildProgramMock,
|
||||
}));
|
||||
@@ -242,6 +251,7 @@ describe("runCli exit behavior", () => {
|
||||
listAgentHarnessIdsMock.mockReturnValue([]);
|
||||
outputPrecomputedBrowserHelpTextMock.mockReturnValue(false);
|
||||
outputPrecomputedRootHelpTextMock.mockReturnValue(false);
|
||||
loadRootHelpRenderOptionsForConfigSensitivePluginsMock.mockResolvedValue(null);
|
||||
hasEnvHttpProxyAgentConfiguredMock.mockReturnValue(false);
|
||||
loadConfigMock.mockReturnValue({});
|
||||
startProxyMock.mockResolvedValue(null);
|
||||
@@ -401,6 +411,7 @@ describe("runCli exit behavior", () => {
|
||||
|
||||
await runCli(["node", "openclaw", "--help"]);
|
||||
|
||||
expect(loadRootHelpRenderOptionsForConfigSensitivePluginsMock).toHaveBeenCalledTimes(1);
|
||||
expect(outputPrecomputedRootHelpTextMock).toHaveBeenCalledTimes(1);
|
||||
expect(hasEnvHttpProxyAgentConfiguredMock).not.toHaveBeenCalled();
|
||||
expect(ensureGlobalUndiciEnvProxyDispatcherMock).not.toHaveBeenCalled();
|
||||
@@ -416,6 +427,7 @@ describe("runCli exit behavior", () => {
|
||||
|
||||
expect(maybeRunCliInContainerMock).toHaveBeenCalledWith(["node", "openclaw", "--help"]);
|
||||
expect(tryRouteCliMock).not.toHaveBeenCalled();
|
||||
expect(loadRootHelpRenderOptionsForConfigSensitivePluginsMock).toHaveBeenCalledTimes(1);
|
||||
expect(outputPrecomputedRootHelpTextMock).toHaveBeenCalledTimes(1);
|
||||
expect(outputRootHelpMock).toHaveBeenCalledTimes(1);
|
||||
expect(buildProgramMock).not.toHaveBeenCalled();
|
||||
@@ -424,6 +436,28 @@ describe("runCli exit behavior", () => {
|
||||
exitSpy.mockRestore();
|
||||
});
|
||||
|
||||
it("renders config-sensitive root help live instead of precomputed metadata", async () => {
|
||||
const liveOptions: RootHelpRenderOptions = {
|
||||
config: {
|
||||
plugins: {
|
||||
slots: {
|
||||
memory: "memory-lancedb",
|
||||
},
|
||||
},
|
||||
},
|
||||
env: process.env,
|
||||
};
|
||||
loadRootHelpRenderOptionsForConfigSensitivePluginsMock.mockResolvedValueOnce(liveOptions);
|
||||
outputPrecomputedRootHelpTextMock.mockReturnValueOnce(true);
|
||||
|
||||
await runCli(["node", "openclaw", "--help"]);
|
||||
|
||||
expect(loadRootHelpRenderOptionsForConfigSensitivePluginsMock).toHaveBeenCalledTimes(1);
|
||||
expect(outputPrecomputedRootHelpTextMock).not.toHaveBeenCalled();
|
||||
expect(outputRootHelpMock).toHaveBeenCalledWith(liveOptions);
|
||||
expect(buildProgramMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not start the managed proxy for local gateway client commands", async () => {
|
||||
tryRouteCliMock.mockResolvedValueOnce(true);
|
||||
|
||||
|
||||
+12
-4
@@ -534,11 +534,19 @@ export async function runCli(argv: string[] = process.argv) {
|
||||
|
||||
try {
|
||||
if (shouldUseRootHelpFastPath(normalizedArgv)) {
|
||||
const { outputPrecomputedRootHelpText } = await import("./root-help-metadata.js");
|
||||
if (!outputPrecomputedRootHelpText()) {
|
||||
const { outputRootHelp } = await import("./program/root-help.js");
|
||||
await outputRootHelp();
|
||||
const { loadRootHelpRenderOptionsForConfigSensitivePlugins } =
|
||||
await import("./root-help-live-config.js");
|
||||
const liveRootHelpOptions = await loadRootHelpRenderOptionsForConfigSensitivePlugins(
|
||||
process.env,
|
||||
);
|
||||
if (!liveRootHelpOptions) {
|
||||
const { outputPrecomputedRootHelpText } = await import("./root-help-metadata.js");
|
||||
if (outputPrecomputedRootHelpText()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const { outputRootHelp } = await import("./program/root-help.js");
|
||||
await outputRootHelp(liveRootHelpOptions ?? undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user