mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-06 06:41:08 +00:00
fix: unblock cli startup metadata
This commit is contained in:
@@ -1,11 +1,16 @@
|
||||
import { Command } from "commander";
|
||||
import { getPluginCliCommandDescriptors } from "../../plugins/cli.js";
|
||||
import type { OpenClawPluginCliCommandDescriptor } from "../../plugins/types.js";
|
||||
import { VERSION } from "../../version.js";
|
||||
import { getCoreCliCommandDescriptors } from "./core-command-descriptors.js";
|
||||
import { configureProgramHelp } from "./help.js";
|
||||
import { getSubCliEntries } from "./subcli-descriptors.js";
|
||||
|
||||
async function buildRootHelpProgram(): Promise<Command> {
|
||||
type RootHelpRenderOptions = {
|
||||
pluginDescriptors?: OpenClawPluginCliCommandDescriptor[] | null;
|
||||
};
|
||||
|
||||
async function buildRootHelpProgram(options?: RootHelpRenderOptions): Promise<Command> {
|
||||
const program = new Command();
|
||||
configureProgramHelp(program, {
|
||||
programVersion: VERSION,
|
||||
@@ -26,7 +31,11 @@ async function buildRootHelpProgram(): Promise<Command> {
|
||||
program.command(command.name).description(command.description);
|
||||
existingCommands.add(command.name);
|
||||
}
|
||||
for (const command of await getPluginCliCommandDescriptors()) {
|
||||
const pluginDescriptors =
|
||||
options && "pluginDescriptors" in options
|
||||
? (options.pluginDescriptors ?? [])
|
||||
: await getPluginCliCommandDescriptors();
|
||||
for (const command of pluginDescriptors) {
|
||||
if (existingCommands.has(command.name)) {
|
||||
continue;
|
||||
}
|
||||
@@ -37,8 +46,8 @@ async function buildRootHelpProgram(): Promise<Command> {
|
||||
return program;
|
||||
}
|
||||
|
||||
export async function renderRootHelpText(): Promise<string> {
|
||||
const program = await buildRootHelpProgram();
|
||||
export async function renderRootHelpText(options?: RootHelpRenderOptions): Promise<string> {
|
||||
const program = await buildRootHelpProgram(options);
|
||||
let output = "";
|
||||
const originalWrite = process.stdout.write.bind(process.stdout);
|
||||
const captureWrite: typeof process.stdout.write = ((chunk: string | Uint8Array) => {
|
||||
@@ -54,6 +63,6 @@ export async function renderRootHelpText(): Promise<string> {
|
||||
return output;
|
||||
}
|
||||
|
||||
export async function outputRootHelp(): Promise<void> {
|
||||
process.stdout.write(await renderRootHelpText());
|
||||
export async function outputRootHelp(options?: RootHelpRenderOptions): Promise<void> {
|
||||
process.stdout.write(await renderRootHelpText(options));
|
||||
}
|
||||
|
||||
43
src/cli/root-help-metadata.ts
Normal file
43
src/cli/root-help-metadata.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
let precomputedRootHelpText: string | null | undefined;
|
||||
|
||||
export function loadPrecomputedRootHelpText(): string | null {
|
||||
if (precomputedRootHelpText !== undefined) {
|
||||
return precomputedRootHelpText;
|
||||
}
|
||||
try {
|
||||
const metadataPath = path.resolve(
|
||||
path.dirname(fileURLToPath(import.meta.url)),
|
||||
"..",
|
||||
"cli-startup-metadata.json",
|
||||
);
|
||||
const raw = fs.readFileSync(metadataPath, "utf8");
|
||||
const parsed = JSON.parse(raw) as { rootHelpText?: unknown };
|
||||
if (typeof parsed.rootHelpText === "string" && parsed.rootHelpText.length > 0) {
|
||||
precomputedRootHelpText = parsed.rootHelpText;
|
||||
return precomputedRootHelpText;
|
||||
}
|
||||
} catch {
|
||||
// Fall back to live root-help rendering.
|
||||
}
|
||||
precomputedRootHelpText = null;
|
||||
return null;
|
||||
}
|
||||
|
||||
export function outputPrecomputedRootHelpText(): boolean {
|
||||
const rootHelpText = loadPrecomputedRootHelpText();
|
||||
if (!rootHelpText) {
|
||||
return false;
|
||||
}
|
||||
process.stdout.write(rootHelpText);
|
||||
return true;
|
||||
}
|
||||
|
||||
export const __testing = {
|
||||
resetPrecomputedRootHelpTextForTests(): void {
|
||||
precomputedRootHelpText = undefined;
|
||||
},
|
||||
};
|
||||
@@ -12,6 +12,7 @@ const hasMemoryRuntimeMock = vi.hoisted(() => vi.fn(() => false));
|
||||
const ensureTaskRegistryReadyMock = vi.hoisted(() => vi.fn());
|
||||
const startTaskRegistryMaintenanceMock = vi.hoisted(() => vi.fn());
|
||||
const outputRootHelpMock = vi.hoisted(() => vi.fn());
|
||||
const outputPrecomputedRootHelpTextMock = vi.hoisted(() => vi.fn(() => false));
|
||||
const buildProgramMock = vi.hoisted(() => vi.fn());
|
||||
const maybeRunCliInContainerMock = vi.hoisted(() =>
|
||||
vi.fn<
|
||||
@@ -64,6 +65,10 @@ vi.mock("./program/root-help.js", () => ({
|
||||
outputRootHelp: outputRootHelpMock,
|
||||
}));
|
||||
|
||||
vi.mock("./root-help-metadata.js", () => ({
|
||||
outputPrecomputedRootHelpText: outputPrecomputedRootHelpTextMock,
|
||||
}));
|
||||
|
||||
vi.mock("./program.js", () => ({
|
||||
buildProgram: buildProgramMock,
|
||||
}));
|
||||
@@ -72,6 +77,7 @@ describe("runCli exit behavior", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
hasMemoryRuntimeMock.mockReturnValue(false);
|
||||
outputPrecomputedRootHelpTextMock.mockReturnValue(false);
|
||||
});
|
||||
|
||||
it("does not force process.exit after successful routed command", async () => {
|
||||
@@ -100,6 +106,7 @@ describe("runCli exit behavior", () => {
|
||||
|
||||
expect(maybeRunCliInContainerMock).toHaveBeenCalledWith(["node", "openclaw", "--help"]);
|
||||
expect(tryRouteCliMock).not.toHaveBeenCalled();
|
||||
expect(outputPrecomputedRootHelpTextMock).toHaveBeenCalledTimes(1);
|
||||
expect(outputRootHelpMock).toHaveBeenCalledTimes(1);
|
||||
expect(buildProgramMock).not.toHaveBeenCalled();
|
||||
expect(closeActiveMemorySearchManagersMock).not.toHaveBeenCalled();
|
||||
|
||||
@@ -158,8 +158,11 @@ export async function runCli(argv: string[] = process.argv) {
|
||||
|
||||
try {
|
||||
if (shouldUseRootHelpFastPath(normalizedArgv)) {
|
||||
const { outputRootHelp } = await import("./program/root-help.js");
|
||||
await outputRootHelp();
|
||||
const { outputPrecomputedRootHelpText } = await import("./root-help-metadata.js");
|
||||
if (!outputPrecomputedRootHelpText()) {
|
||||
const { outputRootHelp } = await import("./program/root-help.js");
|
||||
await outputRootHelp();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user