mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-12 22:06:05 +00:00
fix(cli): align root command descriptions (#100670)
Co-authored-by: AmirF194 <amirfathi@fastinfer.org>
This commit is contained in:
@@ -8,17 +8,17 @@ export type CoreCliCommandDescriptor = NamedCommandDescriptor;
|
||||
const coreCliCommandCatalog = defineCommandDescriptorCatalog([
|
||||
{
|
||||
name: "crestodian",
|
||||
description: "Open the interactive setup and repair assistant",
|
||||
description: "Open the ring-zero setup and repair helper",
|
||||
hasSubcommands: false,
|
||||
},
|
||||
{
|
||||
name: "setup",
|
||||
description: "Initialize local config and an agent workspace",
|
||||
description: "Alias for openclaw onboard",
|
||||
hasSubcommands: false,
|
||||
},
|
||||
{
|
||||
name: "onboard",
|
||||
description: "Interactive onboarding for gateway, workspace, and skills",
|
||||
description: "Guided setup for auth, models, Gateway, workspace, channels, and skills",
|
||||
hasSubcommands: false,
|
||||
},
|
||||
{
|
||||
@@ -29,7 +29,7 @@ const coreCliCommandCatalog = defineCommandDescriptorCatalog([
|
||||
{
|
||||
name: "config",
|
||||
description:
|
||||
"Non-interactive config helpers (get/set/unset/file/validate). Default: starts guided setup.",
|
||||
"Non-interactive config helpers (get/set/patch/unset/file/schema/validate). Run without subcommand for guided setup.",
|
||||
hasSubcommands: true,
|
||||
},
|
||||
{
|
||||
@@ -44,7 +44,7 @@ const coreCliCommandCatalog = defineCommandDescriptorCatalog([
|
||||
},
|
||||
{
|
||||
name: "doctor",
|
||||
description: "Diagnose and repair config, Gateway, plugin, and channel problems",
|
||||
description: "Health checks + quick fixes for the gateway and channels",
|
||||
hasSubcommands: false,
|
||||
},
|
||||
{
|
||||
@@ -64,12 +64,12 @@ const coreCliCommandCatalog = defineCommandDescriptorCatalog([
|
||||
},
|
||||
{
|
||||
name: "message",
|
||||
description: "Send, read, and manage channel messages",
|
||||
description: "Send, read, and manage messages and channel actions",
|
||||
hasSubcommands: true,
|
||||
},
|
||||
{
|
||||
name: "mcp",
|
||||
description: "Manage OpenClaw MCP config and channel bridge",
|
||||
description: "Manage OpenClaw mcp.servers config and channel bridge",
|
||||
hasSubcommands: true,
|
||||
parentDefaultHelp: true,
|
||||
},
|
||||
@@ -80,22 +80,22 @@ const coreCliCommandCatalog = defineCommandDescriptorCatalog([
|
||||
},
|
||||
{
|
||||
name: "agent",
|
||||
description: "Run one agent turn via the Gateway",
|
||||
description: "Run an agent turn via the Gateway (use --local for embedded)",
|
||||
hasSubcommands: false,
|
||||
},
|
||||
{
|
||||
name: "agents",
|
||||
description: "Manage isolated agents (workspaces, auth, routing)",
|
||||
description: "Manage isolated agents (workspaces + auth + routing)",
|
||||
hasSubcommands: true,
|
||||
},
|
||||
{
|
||||
name: "status",
|
||||
description: "Show Gateway, channel, model, and recent-session status",
|
||||
description: "Show channel health and recent session recipients",
|
||||
hasSubcommands: false,
|
||||
},
|
||||
{
|
||||
name: "health",
|
||||
description: "Fetch detailed health from the running Gateway",
|
||||
description: "Fetch health from the running gateway",
|
||||
hasSubcommands: false,
|
||||
},
|
||||
{
|
||||
@@ -110,7 +110,7 @@ const coreCliCommandCatalog = defineCommandDescriptorCatalog([
|
||||
},
|
||||
{
|
||||
name: "tasks",
|
||||
description: "Inspect durable background tasks and flows",
|
||||
description: "Inspect durable background tasks and TaskFlow state",
|
||||
hasSubcommands: true,
|
||||
},
|
||||
] as const satisfies ReadonlyArray<CoreCliCommandDescriptor>);
|
||||
|
||||
64
src/cli/program/root-command-descriptions.test.ts
Normal file
64
src/cli/program/root-command-descriptions.test.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
// Root help renders catalog placeholders while command help and completion use
|
||||
// registered Commander commands. Keep those user-facing descriptions aligned.
|
||||
import { Command } from "commander";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
getCoreCliCommandDescriptors,
|
||||
getCoreCliCommandNames,
|
||||
registerCoreCliByName,
|
||||
} from "./command-registry-core.js";
|
||||
import { createProgramContext } from "./context.js";
|
||||
import { getSubCliEntries, registerSubCliByName } from "./register.subclis.js";
|
||||
|
||||
describe("root command descriptions", () => {
|
||||
beforeEach(() => {
|
||||
vi.stubEnv("OPENCLAW_ENABLE_PRIVATE_QA_CLI", "");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.unstubAllEnvs();
|
||||
});
|
||||
|
||||
it("keeps catalog placeholders and registered commands in sync", async () => {
|
||||
const program = new Command().name("openclaw");
|
||||
const ctx = createProgramContext();
|
||||
const argv = ["node", "openclaw", "completion"];
|
||||
|
||||
for (const name of getCoreCliCommandNames()) {
|
||||
await registerCoreCliByName(program, ctx, name, argv);
|
||||
}
|
||||
for (const entry of getSubCliEntries()) {
|
||||
await registerSubCliByName(program, entry.name, argv, { purpose: "completion" });
|
||||
}
|
||||
|
||||
const registeredCommands = new Map<string, { command: Command; registeredAsAlias: boolean }>();
|
||||
for (const command of program.commands) {
|
||||
registeredCommands.set(command.name(), { command, registeredAsAlias: false });
|
||||
for (const alias of command.aliases()) {
|
||||
registeredCommands.set(alias, { command, registeredAsAlias: true });
|
||||
}
|
||||
}
|
||||
|
||||
const descriptors = [...getCoreCliCommandDescriptors(), ...getSubCliEntries()];
|
||||
const missing: string[] = [];
|
||||
const mismatches: string[] = [];
|
||||
for (const descriptor of descriptors) {
|
||||
const registered = registeredCommands.get(descriptor.name);
|
||||
if (!registered) {
|
||||
missing.push(descriptor.name);
|
||||
continue;
|
||||
}
|
||||
if (
|
||||
!registered.registeredAsAlias &&
|
||||
registered.command.description() !== descriptor.description
|
||||
) {
|
||||
mismatches.push(
|
||||
`${descriptor.name}\n catalog: ${descriptor.description}\n registered: ${registered.command.description()}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
expect(missing, "catalog entries with no registered command or alias").toEqual([]);
|
||||
expect(mismatches, "root help vs registered command description drift").toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -7,31 +7,31 @@ import { isPrivateQaCliEnabled } from "./private-qa-cli.js";
|
||||
export type SubCliDescriptor = NamedCommandDescriptor;
|
||||
|
||||
const subCliCommandCatalog = defineCommandDescriptorCatalog([
|
||||
{ name: "acp", description: "Run and manage ACP-backed coding agents", hasSubcommands: true },
|
||||
{ name: "acp", description: "Run an ACP bridge backed by the Gateway", hasSubcommands: true },
|
||||
{
|
||||
name: "gateway",
|
||||
description: "Run, inspect, and query the OpenClaw Gateway",
|
||||
description: "Run, inspect, and query the WebSocket Gateway",
|
||||
hasSubcommands: true,
|
||||
},
|
||||
{
|
||||
name: "daemon",
|
||||
description: "Manage the Gateway service (legacy alias)",
|
||||
description: "Manage the Gateway service (launchd/systemd/schtasks)",
|
||||
hasSubcommands: true,
|
||||
},
|
||||
{ name: "logs", description: "Tail Gateway logs locally or via RPC", hasSubcommands: false },
|
||||
{ name: "logs", description: "Tail gateway file logs via RPC", hasSubcommands: false },
|
||||
{
|
||||
name: "system",
|
||||
description: "System events, heartbeat, and presence",
|
||||
description: "System tools (events, heartbeat, presence)",
|
||||
hasSubcommands: true,
|
||||
},
|
||||
{
|
||||
name: "models",
|
||||
description: "List, scan, and set model providers",
|
||||
description: "Model discovery, scanning, and configuration",
|
||||
hasSubcommands: true,
|
||||
},
|
||||
{
|
||||
name: "infer",
|
||||
description: "Run provider-backed model, media, search, and embedding commands",
|
||||
description: "Run provider-backed inference commands through a stable CLI surface",
|
||||
hasSubcommands: true,
|
||||
},
|
||||
{
|
||||
@@ -57,12 +57,12 @@ const subCliCommandCatalog = defineCommandDescriptorCatalog([
|
||||
},
|
||||
{
|
||||
name: "nodes",
|
||||
description: "Pair nodes and run node-host commands through the Gateway",
|
||||
description: "Manage gateway-owned nodes (pairing, status, invoke, and media)",
|
||||
hasSubcommands: true,
|
||||
},
|
||||
{
|
||||
name: "devices",
|
||||
description: "Device pairing + token management",
|
||||
description: "Device pairing and auth tokens",
|
||||
hasSubcommands: true,
|
||||
parentDefaultHelp: true,
|
||||
},
|
||||
@@ -73,12 +73,12 @@ const subCliCommandCatalog = defineCommandDescriptorCatalog([
|
||||
},
|
||||
{
|
||||
name: "sandbox",
|
||||
description: "Manage sandbox containers for agent isolation",
|
||||
description: "Manage sandbox containers (Docker-based agent isolation)",
|
||||
hasSubcommands: true,
|
||||
},
|
||||
{
|
||||
name: "worktrees",
|
||||
description: "Manage isolated git worktrees for agent tasks",
|
||||
description: "Create, inspect, restore, and clean up managed worktrees",
|
||||
hasSubcommands: true,
|
||||
parentDefaultHelp: true,
|
||||
},
|
||||
@@ -104,7 +104,7 @@ const subCliCommandCatalog = defineCommandDescriptorCatalog([
|
||||
},
|
||||
{
|
||||
name: "cron",
|
||||
description: "Schedule and inspect Gateway background jobs",
|
||||
description: "Manage cron jobs (via Gateway)",
|
||||
hasSubcommands: true,
|
||||
parentDefaultHelp: true,
|
||||
},
|
||||
@@ -140,7 +140,7 @@ const subCliCommandCatalog = defineCommandDescriptorCatalog([
|
||||
},
|
||||
{
|
||||
name: "qr",
|
||||
description: "Generate mobile pairing QR/setup code",
|
||||
description: "Generate a mobile pairing QR code and setup code",
|
||||
hasSubcommands: false,
|
||||
},
|
||||
{
|
||||
@@ -155,13 +155,13 @@ const subCliCommandCatalog = defineCommandDescriptorCatalog([
|
||||
},
|
||||
{
|
||||
name: "plugins",
|
||||
description: "Install, enable, disable, and inspect plugins",
|
||||
description: "Manage OpenClaw plugins and extensions",
|
||||
hasSubcommands: true,
|
||||
parentDefaultHelp: true,
|
||||
},
|
||||
{
|
||||
name: "channels",
|
||||
description: "Add, remove, login, and inspect messaging channels",
|
||||
description: "Manage connected chat channels and accounts",
|
||||
hasSubcommands: true,
|
||||
parentDefaultHelp: true,
|
||||
},
|
||||
@@ -172,17 +172,17 @@ const subCliCommandCatalog = defineCommandDescriptorCatalog([
|
||||
},
|
||||
{
|
||||
name: "security",
|
||||
description: "Security tools and local config audits",
|
||||
description: "Audit local config and state for common security foot-guns",
|
||||
hasSubcommands: true,
|
||||
},
|
||||
{
|
||||
name: "secrets",
|
||||
description: "Audit, apply, and reload SecretRef-backed credentials",
|
||||
description: "Secrets runtime controls",
|
||||
hasSubcommands: true,
|
||||
},
|
||||
{
|
||||
name: "skills",
|
||||
description: "List, inspect, and install agent skills",
|
||||
description: "List and inspect available skills",
|
||||
hasSubcommands: true,
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user