mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
Merged via squash.
Prepared head SHA: 4598f2a541
Co-authored-by: Sid-Qin <201593046+Sid-Qin@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
305 lines
8.0 KiB
TypeScript
305 lines
8.0 KiB
TypeScript
import type { Command } from "commander";
|
|
import { getPrimaryCommand, hasHelpOrVersion } from "../argv.js";
|
|
import { reparseProgramFromActionArgs } from "./action-reparse.js";
|
|
import { removeCommandByName } from "./command-tree.js";
|
|
import type { ProgramContext } from "./context.js";
|
|
import { registerSubCliCommands } from "./register.subclis.js";
|
|
|
|
type CommandRegisterParams = {
|
|
program: Command;
|
|
ctx: ProgramContext;
|
|
argv: string[];
|
|
};
|
|
|
|
export type CommandRegistration = {
|
|
id: string;
|
|
register: (params: CommandRegisterParams) => void;
|
|
};
|
|
|
|
type CoreCliCommandDescriptor = {
|
|
name: string;
|
|
description: string;
|
|
hasSubcommands: boolean;
|
|
};
|
|
|
|
type CoreCliEntry = {
|
|
commands: CoreCliCommandDescriptor[];
|
|
register: (params: CommandRegisterParams) => Promise<void> | void;
|
|
};
|
|
|
|
const shouldRegisterCorePrimaryOnly = (argv: string[]) => {
|
|
if (hasHelpOrVersion(argv)) {
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
|
|
// Note for humans and agents:
|
|
// If you update the list of commands, also check whether they have subcommands
|
|
// and set the flag accordingly.
|
|
const coreEntries: CoreCliEntry[] = [
|
|
{
|
|
commands: [
|
|
{
|
|
name: "setup",
|
|
description: "Initialize local config and agent workspace",
|
|
hasSubcommands: false,
|
|
},
|
|
],
|
|
register: async ({ program }) => {
|
|
const mod = await import("./register.setup.js");
|
|
mod.registerSetupCommand(program);
|
|
},
|
|
},
|
|
{
|
|
commands: [
|
|
{
|
|
name: "onboard",
|
|
description: "Interactive onboarding wizard for gateway, workspace, and skills",
|
|
hasSubcommands: false,
|
|
},
|
|
],
|
|
register: async ({ program }) => {
|
|
const mod = await import("./register.onboard.js");
|
|
mod.registerOnboardCommand(program);
|
|
},
|
|
},
|
|
{
|
|
commands: [
|
|
{
|
|
name: "configure",
|
|
description:
|
|
"Interactive setup wizard for credentials, channels, gateway, and agent defaults",
|
|
hasSubcommands: false,
|
|
},
|
|
],
|
|
register: async ({ program }) => {
|
|
const mod = await import("./register.configure.js");
|
|
mod.registerConfigureCommand(program);
|
|
},
|
|
},
|
|
{
|
|
commands: [
|
|
{
|
|
name: "config",
|
|
description:
|
|
"Non-interactive config helpers (get/set/unset/file/validate). Default: starts setup wizard.",
|
|
hasSubcommands: true,
|
|
},
|
|
],
|
|
register: async ({ program }) => {
|
|
const mod = await import("../config-cli.js");
|
|
mod.registerConfigCli(program);
|
|
},
|
|
},
|
|
{
|
|
commands: [
|
|
{
|
|
name: "doctor",
|
|
description: "Health checks + quick fixes for the gateway and channels",
|
|
hasSubcommands: false,
|
|
},
|
|
{
|
|
name: "dashboard",
|
|
description: "Open the Control UI with your current token",
|
|
hasSubcommands: false,
|
|
},
|
|
{
|
|
name: "reset",
|
|
description: "Reset local config/state (keeps the CLI installed)",
|
|
hasSubcommands: false,
|
|
},
|
|
{
|
|
name: "uninstall",
|
|
description: "Uninstall the gateway service + local data (CLI remains)",
|
|
hasSubcommands: false,
|
|
},
|
|
],
|
|
register: async ({ program }) => {
|
|
const mod = await import("./register.maintenance.js");
|
|
mod.registerMaintenanceCommands(program);
|
|
},
|
|
},
|
|
{
|
|
commands: [
|
|
{
|
|
name: "message",
|
|
description: "Send, read, and manage messages",
|
|
hasSubcommands: true,
|
|
},
|
|
],
|
|
register: async ({ program, ctx }) => {
|
|
const mod = await import("./register.message.js");
|
|
mod.registerMessageCommands(program, ctx);
|
|
},
|
|
},
|
|
{
|
|
commands: [
|
|
{
|
|
name: "memory",
|
|
description: "Search and reindex memory files",
|
|
hasSubcommands: true,
|
|
},
|
|
],
|
|
register: async ({ program }) => {
|
|
const mod = await import("../memory-cli.js");
|
|
mod.registerMemoryCli(program);
|
|
},
|
|
},
|
|
{
|
|
commands: [
|
|
{
|
|
name: "agent",
|
|
description: "Run one agent turn via the Gateway",
|
|
hasSubcommands: false,
|
|
},
|
|
{
|
|
name: "agents",
|
|
description: "Manage isolated agents (workspaces, auth, routing)",
|
|
hasSubcommands: true,
|
|
},
|
|
],
|
|
register: async ({ program, ctx }) => {
|
|
const mod = await import("./register.agent.js");
|
|
mod.registerAgentCommands(program, {
|
|
agentChannelOptions: ctx.agentChannelOptions,
|
|
});
|
|
},
|
|
},
|
|
{
|
|
commands: [
|
|
{
|
|
name: "status",
|
|
description: "Show channel health and recent session recipients",
|
|
hasSubcommands: false,
|
|
},
|
|
{
|
|
name: "health",
|
|
description: "Fetch health from the running gateway",
|
|
hasSubcommands: false,
|
|
},
|
|
{
|
|
name: "sessions",
|
|
description: "List stored conversation sessions",
|
|
hasSubcommands: true,
|
|
},
|
|
],
|
|
register: async ({ program }) => {
|
|
const mod = await import("./register.status-health-sessions.js");
|
|
mod.registerStatusHealthSessionsCommands(program);
|
|
},
|
|
},
|
|
{
|
|
commands: [
|
|
{
|
|
name: "browser",
|
|
description: "Manage OpenClaw's dedicated browser (Chrome/Chromium)",
|
|
hasSubcommands: true,
|
|
},
|
|
],
|
|
register: async ({ program }) => {
|
|
const mod = await import("../browser-cli.js");
|
|
mod.registerBrowserCli(program);
|
|
},
|
|
},
|
|
];
|
|
|
|
function collectCoreCliCommandNames(predicate?: (command: CoreCliCommandDescriptor) => boolean) {
|
|
const seen = new Set<string>();
|
|
const names: string[] = [];
|
|
for (const entry of coreEntries) {
|
|
for (const command of entry.commands) {
|
|
if (predicate && !predicate(command)) {
|
|
continue;
|
|
}
|
|
if (seen.has(command.name)) {
|
|
continue;
|
|
}
|
|
seen.add(command.name);
|
|
names.push(command.name);
|
|
}
|
|
}
|
|
return names;
|
|
}
|
|
|
|
export function getCoreCliCommandNames(): string[] {
|
|
return collectCoreCliCommandNames();
|
|
}
|
|
|
|
export function getCoreCliCommandsWithSubcommands(): string[] {
|
|
return collectCoreCliCommandNames((command) => command.hasSubcommands);
|
|
}
|
|
|
|
function removeEntryCommands(program: Command, entry: CoreCliEntry) {
|
|
// Some registrars install multiple top-level commands (e.g. status/health/sessions).
|
|
// Remove placeholders/old registrations for all names in the entry before re-registering.
|
|
for (const cmd of entry.commands) {
|
|
removeCommandByName(program, cmd.name);
|
|
}
|
|
}
|
|
|
|
function registerLazyCoreCommand(
|
|
program: Command,
|
|
ctx: ProgramContext,
|
|
entry: CoreCliEntry,
|
|
command: CoreCliCommandDescriptor,
|
|
) {
|
|
const placeholder = program.command(command.name).description(command.description);
|
|
placeholder.allowUnknownOption(true);
|
|
placeholder.allowExcessArguments(true);
|
|
placeholder.action(async (...actionArgs) => {
|
|
removeEntryCommands(program, entry);
|
|
await entry.register({ program, ctx, argv: process.argv });
|
|
await reparseProgramFromActionArgs(program, actionArgs);
|
|
});
|
|
}
|
|
|
|
export async function registerCoreCliByName(
|
|
program: Command,
|
|
ctx: ProgramContext,
|
|
name: string,
|
|
argv: string[] = process.argv,
|
|
): Promise<boolean> {
|
|
const entry = coreEntries.find((candidate) =>
|
|
candidate.commands.some((cmd) => cmd.name === name),
|
|
);
|
|
if (!entry) {
|
|
return false;
|
|
}
|
|
|
|
removeEntryCommands(program, entry);
|
|
await entry.register({ program, ctx, argv });
|
|
return true;
|
|
}
|
|
|
|
export function registerCoreCliCommands(program: Command, ctx: ProgramContext, argv: string[]) {
|
|
const primary = getPrimaryCommand(argv);
|
|
if (primary && shouldRegisterCorePrimaryOnly(argv)) {
|
|
const entry = coreEntries.find((candidate) =>
|
|
candidate.commands.some((cmd) => cmd.name === primary),
|
|
);
|
|
if (entry) {
|
|
const cmd = entry.commands.find((c) => c.name === primary);
|
|
if (cmd) {
|
|
registerLazyCoreCommand(program, ctx, entry, cmd);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
for (const entry of coreEntries) {
|
|
for (const cmd of entry.commands) {
|
|
registerLazyCoreCommand(program, ctx, entry, cmd);
|
|
}
|
|
}
|
|
}
|
|
|
|
export function registerProgramCommands(
|
|
program: Command,
|
|
ctx: ProgramContext,
|
|
argv: string[] = process.argv,
|
|
) {
|
|
registerCoreCliCommands(program, ctx, argv);
|
|
registerSubCliCommands(program, argv);
|
|
}
|