// Core command registry that lazily imports command groups based on parsed argv. import type { Command } from "commander"; import { resolveCliArgvInvocation } from "../argv-invocation.js"; import { shouldRegisterPrimaryCommandOnly } from "../command-registration-policy.js"; import { buildCommandGroupEntries, defineImportedCommandGroupSpec, defineImportedProgramCommandGroupSpecs, type CommandGroupDescriptorSpec, } from "./command-group-descriptors.js"; import type { ProgramContext } from "./context.js"; import { getCoreCliCommandDescriptors, getCoreCliCommandNames as getCoreDescriptorNames, } from "./core-command-descriptors.js"; import { registerCommandGroupByName, registerCommandGroups, type CommandGroupEntry, } from "./register-command-groups.js"; type CommandRegisterParams = { program: Command; ctx: ProgramContext; argv: string[]; }; function withProgramOnlySpecs( specs: readonly CommandGroupDescriptorSpec<(program: Command) => Promise | void>[], ): CommandGroupDescriptorSpec<(params: CommandRegisterParams) => Promise>[] { return specs.map((spec) => ({ commandNames: spec.commandNames, register: async ({ program }) => { await spec.register(program); }, })); } // Note for humans and agents: // If you update the list of commands, also check whether they have subcommands // and set the flag accordingly. const coreEntrySpecs: readonly CommandGroupDescriptorSpec< (params: CommandRegisterParams) => Promise | void >[] = [ ...withProgramOnlySpecs( defineImportedProgramCommandGroupSpecs([ { commandNames: ["setup", "crestodian"], // hidden alias loadModule: () => import("./register.setup.js"), exportName: "registerSetupCommand", }, { commandNames: ["onboard"], loadModule: () => import("./register.onboard.js"), exportName: "registerOnboardCommand", }, { commandNames: ["configure"], loadModule: () => import("./register.configure.js"), exportName: "registerConfigureCommand", }, { commandNames: ["config"], loadModule: () => import("../config-cli.js"), exportName: "registerConfigCli", }, { commandNames: ["claws"], loadModule: () => import("../claws-cli.js"), exportName: "registerClawsCli", }, { commandNames: ["backup"], loadModule: () => import("./register.backup.js"), exportName: "registerBackupCommand", }, { commandNames: ["migrate"], loadModule: () => import("./register.migrate.js"), exportName: "registerMigrateCommand", }, { commandNames: ["audit"], loadModule: () => import("./register.audit.js"), exportName: "registerAuditCommand", }, { commandNames: ["doctor", "dashboard", "reset", "uninstall"], loadModule: () => import("./register.maintenance.js"), exportName: "registerMaintenanceCommands", }, ]), ), defineImportedCommandGroupSpec( ["message"], () => import("./register.message.js"), (mod, { program, ctx }) => { mod.registerMessageCommands(program, ctx); }, ), ...withProgramOnlySpecs( defineImportedProgramCommandGroupSpecs([ { commandNames: ["mcp"], loadModule: () => import("../mcp-cli.js"), exportName: "registerMcpCli", }, { commandNames: ["transcripts"], loadModule: () => import("./register.transcripts.js"), exportName: "registerTranscriptsCli", }, ]), ), defineImportedCommandGroupSpec( ["agent"], () => import("./register.agent-turn.js"), (mod, { program, ctx }) => { mod.registerAgentTurnCommand(program, { agentChannelOptions: ctx.agentChannelOptions, }); }, ), defineImportedCommandGroupSpec( ["agents"], () => import("./register.agent.js"), (mod, { program }) => { mod.registerAgentsCommands(program); }, ), ...withProgramOnlySpecs( defineImportedProgramCommandGroupSpecs([ { commandNames: ["status", "health", "sessions", "commitments", "tasks"], loadModule: () => import("./register.status-health-sessions.js"), exportName: "registerStatusHealthSessionsCommands", }, ]), ), ]; function resolveCoreCommandGroups(ctx: ProgramContext, argv: string[]): CommandGroupEntry[] { const descriptors = getCoreCliCommandDescriptors(); const visibleCommandNames = new Set(descriptors.map((descriptor) => descriptor.name)); const visibleEntrySpecs = coreEntrySpecs.filter((spec) => spec.commandNames.every((name) => visibleCommandNames.has(name)), ); // Descriptor metadata and import specs stay separate so help can stay cheap. return buildCommandGroupEntries(descriptors, visibleEntrySpecs, (register) => async (program) => { await register({ program, ctx, argv }); }); } export function getCoreCliCommandNames(): string[] { return getCoreDescriptorNames(); } export async function registerCoreCliByName( program: Command, ctx: ProgramContext, name: string, argv: string[] = process.argv, ): Promise { return registerCommandGroupByName(program, resolveCoreCommandGroups(ctx, argv), name); } export function registerCoreCliCommands(program: Command, ctx: ProgramContext, argv: string[]) { const { primary } = resolveCliArgvInvocation(argv); registerCommandGroups(program, resolveCoreCommandGroups(ctx, argv), { eager: false, primary, registerPrimaryOnly: Boolean(primary && shouldRegisterPrimaryCommandOnly(argv)), }); }