File size: 4,760 Bytes
34810d2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | // Capability CLI command registration. Domain implementations live in ./capability-cli/.
import type { Command } from "commander";
import { formatDocsLink } from "../../packages/terminal-core/src/links.js";
import { theme } from "../../packages/terminal-core/src/theme.js";
import { FLAG_TERMINATOR, getCommandArgsWithRootOptions } from "../infra/cli-root-options.js";
import { defaultRuntime } from "../runtime.js";
import { getCommandPathWithRootOptions, normalizeRootLogLevelArgv } from "./argv.js";
import { CAPABILITY_METADATA, findCapabilityMetadata } from "./capability-cli/metadata.js";
import { emitJsonOrText, providerSummaryText } from "./capability-cli/output.js";
import { runCommandWithRuntime } from "./cli-utils.js";
import { removeCommandByName } from "./program/command-tree.js";
const capabilityCommandGroups = [
[
"model",
async () => (await import("./capability-cli/model.js")).registerModelCapabilityCommands,
],
[
"image",
async () => (await import("./capability-cli/image.js")).registerImageCapabilityCommands,
],
[
"audio",
async () => (await import("./capability-cli/audio.js")).registerAudioCapabilityCommands,
],
["tts", async () => (await import("./capability-cli/tts.js")).registerTtsCapabilityCommands],
[
"video",
async () => (await import("./capability-cli/video.js")).registerVideoCapabilityCommands,
],
["web", async () => (await import("./capability-cli/web.js")).registerWebCapabilityCommands],
[
"embedding",
async () => (await import("./capability-cli/embedding.js")).registerEmbeddingCapabilityCommands,
],
] as const;
function registerCapabilityListAndInspect(capability: Command): void {
capability
.command("list")
.description("List canonical capability ids and supported transports")
.option("--json", "Output JSON", false)
.action(async (opts) => {
await runCommandWithRuntime(defaultRuntime, async () => {
const result = CAPABILITY_METADATA.map((entry) => ({
id: entry.id,
transports: entry.transports,
description: entry.description,
}));
emitJsonOrText(defaultRuntime, Boolean(opts.json), result, providerSummaryText);
});
});
capability
.command("inspect")
.description("Inspect one canonical capability id")
.requiredOption("--name <capability>", "Capability id")
.option("--json", "Output JSON", false)
.action(async (opts) => {
await runCommandWithRuntime(defaultRuntime, async () => {
const entry = findCapabilityMetadata(String(opts.name));
if (!entry) {
throw new Error(`Unknown capability: ${String(opts.name)}`);
}
emitJsonOrText(defaultRuntime, Boolean(opts.json), entry, (value) =>
JSON.stringify(value, null, 2),
);
});
});
}
async function registerCapabilityDomainCommands(
capability: Command,
argv: string[],
): Promise<void> {
// Root log levels are normalized after registration. Reuse that view for selection,
// leaving help and unknown options ahead of a domain on the complete-tree path.
const selectionArgv = normalizeRootLogLevelArgv(argv);
const commandPath = getCommandPathWithRootOptions(selectionArgv, 2);
const primary = commandPath[0];
const commandArgs =
primary === "infer" || primary === "capability"
? getCommandArgsWithRootOptions(selectionArgv, {
commandPath: [primary],
mode: "command-path",
})
: undefined;
// The raw tail marks both leading and post-parent `--`; only the former retains a domain.
const selectedName = commandArgs?.[0] === FLAG_TERMINATOR ? commandPath[1] : commandArgs?.[0];
if (selectedName === "list" || selectedName === "inspect") {
return;
}
const selected = capabilityCommandGroups.find(([name]) => name === selectedName);
if (selected) {
const register = await selected[1]();
register(capability);
return;
}
const registrars = await Promise.all(capabilityCommandGroups.map(([, load]) => load()));
for (const register of registrars) {
register(capability);
}
}
export async function registerCapabilityCli(
program: Command,
argv: string[] = process.argv,
): Promise<void> {
removeCommandByName(program, "infer");
removeCommandByName(program, "capability");
const capability = program
.command("infer")
.alias("capability")
.description("Run provider-backed inference commands through a stable CLI surface")
.addHelpText(
"after",
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/infer", "docs.openclaw.ai/cli/infer")}\n`,
);
registerCapabilityListAndInspect(capability);
await registerCapabilityDomainCommands(capability, argv);
}
|