openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
127 lines (126 loc) • 7 kB
JavaScript
import { Y as getCoreCliCommandNamesCore, n as getCommandPathWithRootOptions, v as getSubCliEntriesCore } from "./argv-DNjh_yaF.js";
import { r as stripAnsi } from "./ansi-DrXAcdMD.js";
import { t as formatCliCommand } from "./command-format-C7YfyMTd.js";
import { t as formatDocsLink } from "./links-ClIwBcy4.js";
import { r as theme } from "./theme-vjDs9tao.js";
import { t as ExpectedCliError } from "./failure-output-Dc5ce9_F.js";
import { t as levenshteinDistance } from "./levenshtein-distance-C0TL9gUO.js";
//#region src/cli/program/command-suggestions.ts
const EXPLICIT_COMMAND_ALIASES = /* @__PURE__ */ new Map([["upgrade", "update"], ["udpate", "update"]]);
const MAX_SUGGESTIONS = 3;
function uniqueSortedCommandNames(commands) {
return [...new Set([...commands].filter(Boolean))].toSorted((left, right) => left.localeCompare(right));
}
function formatCliCommandSuggestions(input, commandPath = [], candidates) {
const normalizedInput = input.trim().toLowerCase();
if (!normalizedInput) return;
const knownCommands = uniqueSortedCommandNames(candidates ?? (commandPath.length === 0 ? [...getCoreCliCommandNamesCore(), ...getSubCliEntriesCore().map((entry) => entry.name)] : []));
const explicitAlias = EXPLICIT_COMMAND_ALIASES.get(normalizedInput);
if (explicitAlias && knownCommands.includes(explicitAlias)) return formatCliSuggestionLines([explicitAlias], commandPath);
const suggestions = findCliCommandSuggestions(normalizedInput, knownCommands);
if (suggestions.length === 0) return;
return formatCliSuggestionLines(suggestions, commandPath);
}
function findCliCommandSuggestions(input, candidates) {
const maxDistance = Math.max(1, Math.floor(input.length * .4));
return candidates.map((command) => ({
command,
distance: levenshteinDistance(input, command)
})).filter(({ command, distance }) => command !== input && distance <= maxDistance).toSorted((left, right) => left.distance - right.distance || left.command.localeCompare(right.command)).slice(0, MAX_SUGGESTIONS).map(({ command }) => command);
}
function formatCliSuggestionLines(suggestions, commandPath) {
const commandPrefix = ["openclaw", ...commandPath].join(" ");
return `Did you mean this?\n${suggestions.map((command) => ` ${formatCliCommand(`${commandPrefix} ${command}`)}`).join("\n")}`;
}
//#endregion
//#region src/cli/program/error-output.ts
function stripCommanderErrorPrefix(raw) {
return raw.trim().replace(/^error:\s*/i, "").trim();
}
function quote(value) {
return `"${value}"`;
}
function resolveHelpCommand(argv, options) {
const commandPath = options?.commandPath ?? (argv ? getCommandPathWithRootOptions(argv, 2) : []);
if (commandPath.length === 0) return formatCliCommand("openclaw --help");
return formatCliCommand(`openclaw ${commandPath.join(" ")} --help`);
}
function lines(...items) {
return `${items.filter((item) => Boolean(item)).join("\n")}\n`;
}
function formatHelpHint(argv, options) {
const command = resolveHelpCommand(argv, options);
return `${theme.muted("Try:")} ${theme.command(command)}`;
}
function formatDocsHint() {
return `${theme.muted("Docs:")} ${formatDocsLink("/cli", "docs.openclaw.ai/cli")}`;
}
function formatCliMachineOutput(humanOutput) {
const docs = `Docs: ${formatDocsLink("/cli", "docs.openclaw.ai/cli", { force: false })}`;
return stripAnsi(humanOutput).replace(/^Docs:.*$/mu, docs);
}
function formatUnknownCommandMessage(command, commandPath) {
return commandPath.length > 0 ? `OpenClaw ${commandPath.join(" ")} has no command ${quote(command)}.` : `OpenClaw does not know the command ${quote(command)}.`;
}
function formatCliUnknownCommandOutput(command, options = {}) {
const commandPath = options.commandPath ?? [];
const hasParentCommand = commandPath.length > 0;
return lines(theme.error(formatUnknownCommandMessage(command, commandPath)), formatCliCommandSuggestions(command, commandPath, options.commandNames), formatHelpHint(options.argv, { commandPath }), hasParentCommand ? void 0 : `${theme.muted("Plugin command?")} ${theme.command(formatCliCommand("openclaw plugins list"))}`, formatDocsHint());
}
function createCliParseError(raw, options = {}, errorOptions = {}) {
const message = stripCommanderErrorPrefix(raw);
const unknownCommand = message.match(/^unknown command ['"`](.+?)['"`]/i);
if (unknownCommand) {
const command = unknownCommand[1] ?? "";
const commandPath = options.commandPath ?? [];
const humanOutput = formatCliUnknownCommandOutput(command, options);
return new ExpectedCliError({
message: formatUnknownCommandMessage(command, commandPath),
humanOutput,
humanOutputWritten: errorOptions.humanOutputWritten,
machineOutput: formatCliMachineOutput(humanOutput)
});
}
const humanOutput = formatCliParseErrorOutput(raw, options);
return new ExpectedCliError({
message,
humanOutput,
humanOutputWritten: errorOptions.humanOutputWritten,
machineOutput: formatCliMachineOutput(humanOutput)
});
}
function createCliUnknownCommandError(command, options = {}) {
const commandPath = options.commandPath ?? [];
const humanOutput = formatCliUnknownCommandOutput(command, options);
return new ExpectedCliError({
message: formatUnknownCommandMessage(command, commandPath),
humanOutput,
machineOutput: formatCliMachineOutput(humanOutput)
});
}
/** Convert Commander parse errors into OpenClaw-specific help and docs guidance. */
function formatCliParseErrorOutput(raw, options = {}) {
const message = stripCommanderErrorPrefix(raw);
const unknownCommand = message.match(/^unknown command ['"`](.+?)['"`]/i);
if (unknownCommand) return formatCliUnknownCommandOutput(unknownCommand[1] ?? "", options);
const unknownOption = message.match(/^unknown option ['"`](.+?)['"`]/i);
if (unknownOption) {
const output = `OpenClaw does not recognize option ${quote(unknownOption[1] ?? "")}.`;
return lines(theme.error(output), formatHelpHint(options.argv, { commandPath: options.commandPath }));
}
const missingArgument = message.match(/^missing required argument ['"`](.+?)['"`]/i);
if (missingArgument) {
const output = `Missing required argument ${quote(missingArgument[1] ?? "")}.`;
return lines(theme.error(output), formatHelpHint(options.argv, { commandPath: options.commandPath }));
}
const missingOption = message.match(/^required option ['"`](.+?)['"`] not specified/i);
if (missingOption) {
const output = `Missing required option ${quote(missingOption[1] ?? "")}.`;
return lines(theme.error(output), formatHelpHint(options.argv, { commandPath: options.commandPath }));
}
if (/^too many arguments\b/i.test(message)) return lines(theme.error("Too many arguments for this command."), formatHelpHint(options.argv, { commandPath: options.commandPath }));
const output = `OpenClaw could not parse this command: ${message}`;
return lines(theme.error(output), formatHelpHint(options.argv, { commandPath: options.commandPath }));
}
//#endregion
export { createCliUnknownCommandError as n, formatCliParseErrorOutput as r, createCliParseError as t };