perf(cli): speed up precomputed command help startup

* perf: speed up precomputed command help

* perf: precompute sessions and tasks help

* Speed up precomputed command help startup

* Speed up precomputed command help startup

---------

Co-authored-by: Zeheng Huang <153708448+hunjaiboy@users.noreply.github.com>
Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
This commit is contained in:
Anson_H 2026-06-22 06:27:47 -07:00 committed by GitHub
parent 7626ca38b3
commit 3895c9341b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 504 additions and 27 deletions

View file

@ -371,22 +371,120 @@ const buildMissingEntryErrorMessage = async () => {
const isBareRootHelpInvocation = (argv) =>
argv.length === 3 && (argv[2] === "--help" || argv[2] === "-h");
const resolvePrecomputedCommandHelp = (argv) => {
if (argv.length !== 4 || (argv[3] !== "--help" && argv[3] !== "-h")) {
return null;
const LAUNCHER_HELP_FLAGS = new Set(["-h", "--help"]);
const LAUNCHER_ROOT_BOOLEAN_FLAGS = new Set(["--dev", "--no-color"]);
const LAUNCHER_ROOT_VALUE_FLAGS = new Set(["--profile", "--log-level", "--container"]);
const LAUNCHER_PRECOMPUTED_COMMAND_HELP = {
browser: { command: "browser", metadataKey: "browserHelpText" },
secrets: { command: "secrets", metadataKey: "secretsHelpText" },
nodes: { command: "nodes", metadataKey: "nodesHelpText" },
};
const LAUNCHER_PRECOMPUTED_SUBCOMMAND_HELP = new Set([
"doctor",
"gateway",
"models",
"plugins",
"sessions",
"tasks",
]);
const isLauncherRootOptionValueToken = (arg) => {
if (!arg || arg === "--") {
return false;
}
if (argv[2] === "browser") {
return { command: "browser", metadataKey: "browserHelpText" };
if (!arg.startsWith("-")) {
return true;
}
if (argv[2] === "secrets") {
return { command: "secrets", metadataKey: "secretsHelpText" };
return /^-\d+(?:\.\d+)?$/.test(arg);
};
const consumeLauncherRootOptionToken = (args, index) => {
const arg = args[index];
if (!arg) {
return 0;
}
if (argv[2] === "nodes") {
return { command: "nodes", metadataKey: "nodesHelpText" };
if (LAUNCHER_ROOT_BOOLEAN_FLAGS.has(arg)) {
return 1;
}
if (
arg.startsWith("--profile=") ||
arg.startsWith("--log-level=") ||
arg.startsWith("--container=")
) {
return 1;
}
if (LAUNCHER_ROOT_VALUE_FLAGS.has(arg)) {
return isLauncherRootOptionValueToken(args[index + 1]) ? 2 : 1;
}
return 0;
};
const hasLauncherContainerTarget = (argv) => {
if (normalizeLauncherMetadataValue(process.env.OPENCLAW_CONTAINER)) {
return true;
}
const args = argv.slice(2);
for (let index = 0; index < args.length; index += 1) {
const arg = args[index];
if (!arg || arg === "--") {
return false;
}
if (arg === "--container" || arg.startsWith("--container=")) {
return true;
}
}
return false;
};
const resolvePrecomputedCommandHelpByName = (commandName) => {
if (Object.hasOwn(LAUNCHER_PRECOMPUTED_COMMAND_HELP, commandName)) {
return LAUNCHER_PRECOMPUTED_COMMAND_HELP[commandName];
}
if (LAUNCHER_PRECOMPUTED_SUBCOMMAND_HELP.has(commandName)) {
return {
command: commandName,
metadataKey: "subcommandHelpText",
subcommandKey: commandName,
};
}
return null;
};
const resolvePrecomputedCommandHelp = (argv) => {
const args = argv.slice(2);
let commandHelp = null;
let sawHelp = false;
for (let index = 0; index < args.length; index += 1) {
const arg = args[index];
if (!arg || arg === "--") {
return null;
}
if (!commandHelp) {
const consumed = consumeLauncherRootOptionToken(args, index);
if (consumed > 0) {
index += consumed - 1;
continue;
}
if (arg.startsWith("-")) {
return null;
}
commandHelp = resolvePrecomputedCommandHelpByName(arg);
if (!commandHelp) {
return null;
}
continue;
}
if (LAUNCHER_HELP_FLAGS.has(arg)) {
sawHelp = true;
continue;
}
return null;
}
return commandHelp && sawHelp ? commandHelp : null;
};
const isHelpFastPathDisabled = () =>
process.env.OPENCLAW_DISABLE_CLI_STARTUP_HELP_FAST_PATH === "1";
@ -456,11 +554,11 @@ const shouldDeferRootHelpToRuntimeEntry = () => {
return false;
};
const loadPrecomputedHelpText = (key) => {
const loadPrecomputedHelpText = (key, subkey) => {
try {
const raw = readFileSync(new URL("./dist/cli-startup-metadata.json", import.meta.url), "utf8");
const parsed = JSON.parse(raw);
const value = parsed?.[key];
const value = subkey ? parsed?.[key]?.[subkey] : parsed?.[key];
return typeof value === "string" && value.length > 0 ? value : null;
} catch {
return null;
@ -650,10 +748,13 @@ const tryOutputPrecomputedCommandHelp = () => {
if (!commandHelp) {
return false;
}
if (hasLauncherContainerTarget(process.argv)) {
return false;
}
if (commandHelp.command === "nodes" && shouldDeferRootHelpToRuntimeEntry()) {
return false;
}
const precomputed = loadPrecomputedHelpText(commandHelp.metadataKey);
const precomputed = loadPrecomputedHelpText(commandHelp.metadataKey, commandHelp.subcommandKey);
if (!precomputed) {
return false;
}

View file

@ -663,6 +663,10 @@ function parseMaxRssMb(stderr: string): number | null {
return Number(lastMatch[1]) / 1024;
}
function nodeImportSpecifierForPath(filePath: string): string {
return pathToFileURL(filePath).href;
}
function buildCpuOrHeapFlags(options: { cpuProfDir?: string; heapProfDir?: string }): string[] {
const flags: string[] = [];
if (options.cpuProfDir) {
@ -697,7 +701,7 @@ async function runSample(params: {
}
const nodeArgs = [
"--import",
params.rssHookPath,
nodeImportSpecifierForPath(params.rssHookPath),
...buildCpuOrHeapFlags({
cpuProfDir: params.cpuProfDir,
heapProfDir: params.heapProfDir,
@ -1268,6 +1272,7 @@ async function main(): Promise<void> {
export const testing = {
buildConfigFixture,
collectFailedSamples,
nodeImportSpecifierForPath,
parseGatewayPortEnv,
parseNonNegativeInt,
parsePositiveInt,

View file

@ -173,6 +173,10 @@ function formatCaseCommand(testCase) {
return `node ${testCase.args.join(" ")}`;
}
function nodeImportSpecifierForPath(filePath) {
return pathToFileURL(filePath).href;
}
function buildBenchEnv() {
if (!tmpHome) {
throw new Error("temporary home is not initialized");
@ -218,14 +222,18 @@ function runCase(testCase, params = {}) {
const env = buildBenchEnv();
const spawn = params.spawnSync ?? defaultSpawnSync;
const timeoutMs = params.timeoutMs ?? COMMAND_TIMEOUT_MS;
const result = spawn(process.execPath, ["--import", rssHookPath, ...testCase.args], {
cwd: repoRoot,
env,
encoding: "utf8",
maxBuffer: 20 * 1024 * 1024,
timeout: timeoutMs,
killSignal: "SIGKILL",
});
const result = spawn(
process.execPath,
["--import", nodeImportSpecifierForPath(rssHookPath), ...testCase.args],
{
cwd: repoRoot,
env,
encoding: "utf8",
maxBuffer: 20 * 1024 * 1024,
timeout: timeoutMs,
killSignal: "SIGKILL",
},
);
const stderr = result.stderr ?? "";
const maxRssMb = parseMaxRssMb(stderr);
const matrixBootstrapWarning = /matrix: crypto runtime bootstrap failed/i.test(stderr);
@ -373,6 +381,7 @@ function runStartupMemoryCheck(argv = process.argv.slice(2), params = {}) {
*/
export const testing = {
cases,
nodeImportSpecifierForPath,
parseArgs,
readPositiveIntEnv,
readPositiveNumberEnv,

View file

@ -33,7 +33,14 @@ const COMMAND_HELP_RENDER_TIMEOUT_MS = 120_000;
const COMMAND_HELP_RENDER_MAX_OUTPUT_BYTES = 16 * 1024 * 1024;
const COMMAND_HELP_RENDER_KILL_GRACE_MS = 5_000;
const COMMAND_HELP_RENDER_CONCURRENCY = 2;
const PRECOMPUTED_SUBCOMMAND_HELP_COMMANDS = ["doctor", "gateway", "models", "plugins"] as const;
const PRECOMPUTED_SUBCOMMAND_HELP_COMMANDS = [
"doctor",
"gateway",
"models",
"plugins",
"sessions",
"tasks",
] as const;
const CORE_CHANNEL_ORDER = [
"telegram",
"whatsapp",
@ -249,6 +256,7 @@ function resolveSubcommandHelpSourceSignature(sourceRootDir: string = rootDir):
path.join(sourceRootDir, "src/cli/help-format.ts"),
path.join(sourceRootDir, "src/cli/daemon-cli/register-service-commands.ts"),
path.join(sourceRootDir, "src/cli/program/register.maintenance.ts"),
path.join(sourceRootDir, "src/cli/program/register.status-health-sessions.ts"),
path.join(sourceRootDir, "src/cli/gateway-cli.ts"),
path.join(sourceRootDir, "src/cli/gateway-cli/register.ts"),
path.join(sourceRootDir, "src/cli/gateway-cli/run-command.ts"),

View file

@ -1,7 +1,13 @@
// Cached startup metadata readers for precomputed root and subcommand help text.
import { readCliStartupMetadata } from "./startup-metadata.js";
export type PrecomputedSubcommandHelpName = "doctor" | "gateway" | "models" | "plugins";
export type PrecomputedSubcommandHelpName =
| "doctor"
| "gateway"
| "models"
| "plugins"
| "sessions"
| "tasks";
let precomputedRootHelpText: string | null | undefined;
let precomputedBrowserHelpText: string | null | undefined;
@ -139,7 +145,9 @@ function isPrecomputedSubcommandHelpName(
commandName === "doctor" ||
commandName === "gateway" ||
commandName === "models" ||
commandName === "plugins"
commandName === "plugins" ||
commandName === "sessions" ||
commandName === "tasks"
);
}

View file

@ -24,7 +24,14 @@ import { getSubCliParentDefaultHelpCommands } from "./program/subcli-descriptors
const ROOT_HELP_ALIASES = new Set(["tools"]);
const SETUP_ONBOARD_CONFIGURE_HELP_COMMANDS = new Set(["setup", "onboard", "configure"]);
const PRECOMPUTED_SUBCOMMAND_HELP_COMMANDS = new Set(["doctor", "gateway", "models", "plugins"]);
const PRECOMPUTED_SUBCOMMAND_HELP_COMMANDS = new Set([
"doctor",
"gateway",
"models",
"plugins",
"sessions",
"tasks",
]);
const HELP_FLAGS = new Set(["-h", "--help"]);
const VERSION_FLAGS = new Set(["-V", "--version"]);
const BARE_PARENT_DEFAULT_HELP_COMMANDS = new Set([

View file

@ -319,6 +319,12 @@ describe("resolvePrecomputedSubcommandHelpFastPath", () => {
expect(
resolvePrecomputedSubcommandHelpFastPath(["node", "openclaw", "plugins", "--help"]),
).toBe("plugins");
expect(
resolvePrecomputedSubcommandHelpFastPath(["node", "openclaw", "sessions", "--help"]),
).toBe("sessions");
expect(resolvePrecomputedSubcommandHelpFastPath(["node", "openclaw", "tasks", "-h"])).toBe(
"tasks",
);
expect(
resolvePrecomputedSubcommandHelpFastPath(["node", "openclaw", "doctor", "--version"]),
).toBeNull();

View file

@ -155,6 +155,68 @@ describe("entry precomputed command help fast path", () => {
expect(outputPrecomputedNodesHelpTextCalls).toBe(1);
});
it.each(["doctor", "sessions", "tasks"])(
"renders precomputed %s help from startup metadata without importing the full program",
async (commandName) => {
const outputPrecomputedSubcommandHelpTextCalls: string[] = [];
const handled = await tryHandlePrecomputedCommandHelpFastPath(
["node", "openclaw", commandName, "--help"],
{
env: {},
outputPrecomputedSubcommandHelpText: (requestedCommandName) => {
outputPrecomputedSubcommandHelpTextCalls.push(requestedCommandName);
return true;
},
},
);
expect(handled).toBe(true);
expect(outputPrecomputedSubcommandHelpTextCalls).toEqual([commandName]);
},
);
it("renders precomputed subcommand help with leading root options", async () => {
const outputPrecomputedSubcommandHelpTextCalls: string[] = [];
const handled = await tryHandlePrecomputedCommandHelpFastPath(
["node", "openclaw", "--profile", "work", "--no-color", "models", "-h"],
{
env: {},
outputPrecomputedSubcommandHelpText: (commandName) => {
outputPrecomputedSubcommandHelpTextCalls.push(commandName);
return true;
},
},
);
expect(handled).toBe(true);
expect(outputPrecomputedSubcommandHelpTextCalls).toEqual(["models"]);
});
it("keeps subcommand help fast path strict for extra or mixed flags", async () => {
const invocations = [
["node", "openclaw", "doctor", "--help", "--bogus"],
["node", "openclaw", "doctor", "--help", "extra"],
["node", "openclaw", "doctor", "--version", "-h"],
["node", "openclaw", "--bogus", "doctor", "--help"],
];
let outputPrecomputedSubcommandHelpTextCalls = 0;
for (const argv of invocations) {
const handled = await tryHandlePrecomputedCommandHelpFastPath(argv, {
env: {},
outputPrecomputedSubcommandHelpText: () => {
outputPrecomputedSubcommandHelpTextCalls += 1;
return true;
},
});
expect(handled).toBe(false);
}
expect(outputPrecomputedSubcommandHelpTextCalls).toBe(0);
});
it("defers nodes help when plugin config can change command metadata", async () => {
let outputPrecomputedNodesHelpTextCalls = 0;
let liveConfigChecks = 0;
@ -288,4 +350,22 @@ describe("entry precomputed command help fast path", () => {
expect(handled).toBe(false);
expect(outputPrecomputedSecretsHelpTextCalls).toBe(0);
});
it("skips the host command help fast path when a container target comes from env", async () => {
let outputPrecomputedBrowserHelpTextCalls = 0;
const handled = await tryHandlePrecomputedCommandHelpFastPath(
["node", "openclaw", "browser", "--help"],
{
env: { OPENCLAW_CONTAINER: "demo" },
outputPrecomputedBrowserHelpText: () => {
outputPrecomputedBrowserHelpTextCalls += 1;
return true;
},
},
);
expect(handled).toBe(false);
expect(outputPrecomputedBrowserHelpTextCalls).toBe(0);
});
});

View file

@ -15,6 +15,7 @@ import {
} from "./entry.compile-cache.js";
import { buildCliRespawnPlan, runCliRespawnPlan } from "./entry.respawn.js";
import { tryHandleRootVersionFastPath } from "./entry.version-fast-path.js";
import { consumeRootOptionToken } from "./infra/cli-root-options.js";
import { isTruthyEnvValue, normalizeEnv } from "./infra/env.js";
import { isMainModule } from "./infra/is-main.js";
import { ensureOpenClawExecMarkerOnProcess } from "./infra/openclaw-exec-env.js";
@ -26,8 +27,18 @@ const ENTRY_WRAPPER_PAIRS = [
] as const;
type PrecomputedCommandHelpName = "browser" | "secrets" | "nodes";
type PrecomputedSubcommandHelpName =
| "doctor"
| "gateway"
| "models"
| "plugins"
| "sessions"
| "tasks";
type OutputPrecomputedHelpText = () => boolean;
const HELP_FLAGS = new Set(["-h", "--help"]);
const VERSION_FLAGS = new Set(["-V", "--version"]);
const loadRootHelpLiveConfigModule = async () => await import("./cli/root-help-live-config.js");
const loadRootHelpMetadataModule = async () => await import("./cli/root-help-metadata.js");
@ -227,12 +238,69 @@ function resolvePrecomputedCommandHelpName(argv: string[]): PrecomputedCommandHe
return null;
}
function resolvePrecomputedSubcommandHelpName(
argv: string[],
): PrecomputedSubcommandHelpName | null {
const args = argv.slice(2);
let commandName: PrecomputedSubcommandHelpName | null = null;
let sawHelp = false;
for (let index = 0; index < args.length; index += 1) {
const arg = args[index];
if (!arg || arg === "--") {
return null;
}
if (VERSION_FLAGS.has(arg)) {
return null;
}
if (!commandName) {
const consumed = consumeRootOptionToken(args, index);
if (consumed > 0) {
index += consumed - 1;
continue;
}
if (arg.startsWith("-")) {
return null;
}
commandName = resolvePrecomputedSubcommandName(arg);
if (!commandName) {
return null;
}
continue;
}
if (HELP_FLAGS.has(arg)) {
sawHelp = true;
continue;
}
return null;
}
return commandName && sawHelp ? commandName : null;
}
function resolvePrecomputedSubcommandName(
commandName: string,
): PrecomputedSubcommandHelpName | null {
if (
commandName === "doctor" ||
commandName === "gateway" ||
commandName === "models" ||
commandName === "plugins" ||
commandName === "sessions" ||
commandName === "tasks"
) {
return commandName;
}
return null;
}
export async function tryHandlePrecomputedCommandHelpFastPath(
argv: string[],
deps: {
outputPrecomputedBrowserHelpText?: OutputPrecomputedHelpText;
outputPrecomputedSecretsHelpText?: OutputPrecomputedHelpText;
outputPrecomputedNodesHelpText?: OutputPrecomputedHelpText;
outputPrecomputedSubcommandHelpText?: (commandName: string) => boolean;
loadRootHelpRenderOptionsForConfigSensitivePlugins?: (
env?: NodeJS.ProcessEnv,
) => Promise<RootHelpRenderOptions | null>;
@ -247,11 +315,18 @@ export async function tryHandlePrecomputedCommandHelpFastPath(
return false;
}
const commandName = resolvePrecomputedCommandHelpName(argv);
if (!commandName) {
const subcommandName = commandName ? null : resolvePrecomputedSubcommandHelpName(argv);
if (!commandName && !subcommandName) {
return false;
}
try {
if (subcommandName) {
const outputPrecomputedSubcommandHelpText =
deps.outputPrecomputedSubcommandHelpText ??
(await loadRootHelpMetadataModule()).outputPrecomputedSubcommandHelpText;
return outputPrecomputedSubcommandHelpText(subcommandName);
}
if (commandName === "nodes") {
const loadRootHelpRenderOptionsForConfigSensitivePlugins =
deps.loadRootHelpRenderOptionsForConfigSensitivePlugins ??

View file

@ -480,6 +480,125 @@ describe("openclaw launcher", () => {
expect(result.stdout).toBe(`PRECOMPUTED ${params.command} help\n`);
});
it.each(["doctor", "gateway", "models", "plugins", "sessions", "tasks"])(
"uses precomputed %s help before loading the runtime entry",
async (command) => {
const fixtureRoot = await makeLauncherFixture(fixtureRoots);
await fs.writeFile(
path.join(fixtureRoot, "dist", "cli-startup-metadata.json"),
JSON.stringify({ subcommandHelpText: { [command]: `PRECOMPUTED ${command} help\n` } }),
"utf8",
);
const result = spawnSync(
process.execPath,
[path.join(fixtureRoot, "openclaw.mjs"), command, "--help"],
{
cwd: fixtureRoot,
env: launcherEnv(),
encoding: "utf8",
},
);
expect(result.status).toBe(0);
expect(result.stdout).toBe(`PRECOMPUTED ${command} help\n`);
},
);
it("uses precomputed subcommand help with leading root options", async () => {
const fixtureRoot = await makeLauncherFixture(fixtureRoots);
await fs.writeFile(
path.join(fixtureRoot, "dist", "cli-startup-metadata.json"),
JSON.stringify({ subcommandHelpText: { models: "PRECOMPUTED models help\n" } }),
"utf8",
);
const result = spawnSync(
process.execPath,
[path.join(fixtureRoot, "openclaw.mjs"), "--profile", "work", "--no-color", "models", "-h"],
{
cwd: fixtureRoot,
env: launcherEnv(),
encoding: "utf8",
},
);
expect(result.status).toBe(0);
expect(result.stdout).toBe("PRECOMPUTED models help\n");
});
it("defers precomputed subcommand help to the runtime entry when container env is set", async () => {
const fixtureRoot = await makeLauncherFixture(fixtureRoots);
await fs.writeFile(
path.join(fixtureRoot, "dist", "cli-startup-metadata.json"),
JSON.stringify({ subcommandHelpText: { models: "PRECOMPUTED models help\n" } }),
"utf8",
);
await fs.writeFile(
path.join(fixtureRoot, "dist", "entry.js"),
"process.stdout.write('RUNTIME ENTRY\\n');\n",
"utf8",
);
const result = spawnSync(
process.execPath,
[path.join(fixtureRoot, "openclaw.mjs"), "models", "--help"],
{
cwd: fixtureRoot,
env: launcherEnv({ OPENCLAW_CONTAINER: "demo" }),
encoding: "utf8",
},
);
expect(result.status).toBe(0);
expect(result.stdout).toBe("RUNTIME ENTRY\n");
expect(result.stdout).not.toContain("PRECOMPUTED");
});
it.each([
{
name: "container env",
args: ["browser", "--help"],
env: { OPENCLAW_CONTAINER: "demo" },
},
{
name: "root --container flag",
args: ["--container", "demo", "browser", "--help"],
env: {},
},
{
name: "root --container=value flag",
args: ["--container=demo", "browser", "--help"],
env: {},
},
])("defers precomputed command help to the runtime entry with $name", async (params) => {
const fixtureRoot = await makeLauncherFixture(fixtureRoots);
await fs.writeFile(
path.join(fixtureRoot, "dist", "cli-startup-metadata.json"),
JSON.stringify({ browserHelpText: "PRECOMPUTED browser help\n" }),
"utf8",
);
await fs.writeFile(
path.join(fixtureRoot, "dist", "entry.js"),
"process.stdout.write('RUNTIME ENTRY\\n');\n",
"utf8",
);
const result = spawnSync(
process.execPath,
[path.join(fixtureRoot, "openclaw.mjs"), ...params.args],
{
cwd: fixtureRoot,
env: launcherEnv(params.env),
encoding: "utf8",
},
);
expect(result.status).toBe(0);
expect(result.stdout).toBe("RUNTIME ENTRY\n");
expect(result.stdout).not.toContain("PRECOMPUTED");
});
it("defers root help to the runtime entry when plugin config can change help", async () => {
const fixtureRoot = await makeLauncherFixture(fixtureRoots);
const configPath = path.join(fixtureRoot, "openclaw.json");

View file

@ -1,7 +1,8 @@
// Bench Cli Startup tests cover bench cli startup script behavior.
import { spawnSync } from "node:child_process";
import { existsSync, readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { join, resolve } from "node:path";
import { pathToFileURL } from "node:url";
import { describe, expect, it } from "vitest";
import { testing } from "../../scripts/bench-cli-startup.ts";
import { withEnv } from "../../src/test-utils/env.js";
@ -187,6 +188,12 @@ describe("bench-cli-startup", () => {
}
});
it("passes generated import hook paths as file URL specifiers", () => {
const hookPath = resolve("measure-rss.mjs");
expect(testing.nodeImportSpecifierForPath(hookPath)).toBe(pathToFileURL(hookPath).href);
});
it("fails reports with no measured samples", () => {
expect(
testing.collectFailedSamples({

View file

@ -218,4 +218,42 @@ describe("check-cli-startup-memory", () => {
),
).toThrow("--help did not report max RSS");
});
it("passes the generated RSS hook as a Node import URL", () => {
if (process.platform !== "darwin" && process.platform !== "linux") {
return;
}
const tempRoot = makeTempRoot();
const seenArgs: string[][] = [];
const result = testing.runStartupMemoryCheck(
[
"--json",
path.join(tempRoot, "startup-memory.json"),
"--summary",
path.join(tempRoot, "summary.md"),
],
{
platform: "linux",
spawnSync: (_command: string, args: string[]) => {
seenArgs.push(args);
return {
error: null,
signal: null,
status: 0,
stderr: "__OPENCLAW_MAX_RSS_KB__=1024\n",
stdout: "",
};
},
},
);
expect(result.skipped).toBe(false);
expect(seenArgs).toHaveLength(testing.cases.length);
for (const args of seenArgs) {
expect(args[0]).toBe("--import");
expect(args[1]).toMatch(/^file:/u);
}
});
});

View file

@ -34,6 +34,10 @@ function writeStartupMetadataSourceSignatureFixture(rootDir: string): void {
["src/cli/models-cli.ts", "export const modelsHelp = 'models';\n"],
["src/cli/nodes-cli/register.ts", "export const nodesHelp = 'nodes';\n"],
["src/cli/program/register.maintenance.ts", "export const maintenanceHelp = 'maintenance';\n"],
[
"src/cli/program/register.status-health-sessions.ts",
"export const statusHealthSessionsHelp = 'sessions';\n",
],
["src/cli/program/context.ts", "export const context = 'context';\n"],
["src/cli/program/help.ts", "export const help = 'help';\n"],
["src/cli/plugins-cli.ts", "export const pluginsHelp = 'plugins';\n"],
@ -364,6 +368,8 @@ describe("write-cli-startup-metadata", () => {
gateway: "Usage: openclaw gateway\n",
models: "Usage: openclaw models\n",
plugins: "Usage: openclaw plugins\n",
sessions: "Usage: openclaw sessions\n",
tasks: "Usage: openclaw tasks\n",
}),
});
@ -379,6 +385,8 @@ describe("write-cli-startup-metadata", () => {
gateway: string;
models: string;
plugins: string;
sessions: string;
tasks: string;
};
};
expect(written.channelOptions).toContain("matrix");
@ -395,6 +403,8 @@ describe("write-cli-startup-metadata", () => {
expect(written.subcommandHelpText.gateway).toContain("openclaw gateway");
expect(written.subcommandHelpText.models).toContain("openclaw models");
expect(written.subcommandHelpText.plugins).toContain("openclaw plugins");
expect(written.subcommandHelpText.sessions).toContain("openclaw sessions");
expect(written.subcommandHelpText.tasks).toContain("openclaw tasks");
});
it("renders independent startup help snapshots concurrently", async () => {
@ -452,6 +462,8 @@ describe("write-cli-startup-metadata", () => {
gateway: "Usage: openclaw gateway\n",
models: "Usage: openclaw models\n",
plugins: "Usage: openclaw plugins\n",
sessions: "Usage: openclaw sessions\n",
tasks: "Usage: openclaw tasks\n",
};
},
});
@ -500,6 +512,8 @@ describe("write-cli-startup-metadata", () => {
gateway: "Usage: openclaw gateway\n",
models: "Usage: openclaw models\n",
plugins: "Usage: openclaw plugins\n",
sessions: "Usage: openclaw sessions\n",
tasks: "Usage: openclaw tasks\n",
}),
});
};