mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-13 19:10:39 +00:00
* 1、环境变量**:新增 `OPENCLAW_LOG_LEVEL`,可取值 `silent|fatal|error|warn|info|debug|trace`。设置后同时覆盖**文件日志**与**控制台**的级别,优先级高于配置文件。 2、启动参数**:在 `openclaw gateway run` 上新增 `--log-level <level>`,对该次进程同时生效于文件与控制台;未传时仍使用环境变量或配置文件。 * fix(logging): make log-level override global and precedence-safe --------- Co-authored-by: Peter Steinberger <steipete@gmail.com>
137 lines
4.9 KiB
TypeScript
137 lines
4.9 KiB
TypeScript
import type { Command } from "commander";
|
|
import { formatDocsLink } from "../../terminal/links.js";
|
|
import { isRich, theme } from "../../terminal/theme.js";
|
|
import { escapeRegExp } from "../../utils.js";
|
|
import { hasFlag, hasRootVersionAlias } from "../argv.js";
|
|
import { formatCliBannerLine, hasEmittedCliBanner } from "../banner.js";
|
|
import { replaceCliName, resolveCliName } from "../cli-name.js";
|
|
import { CLI_LOG_LEVEL_VALUES, parseCliLogLevelOption } from "../log-level-option.js";
|
|
import { getCoreCliCommandsWithSubcommands } from "./command-registry.js";
|
|
import type { ProgramContext } from "./context.js";
|
|
import { getSubCliCommandsWithSubcommands } from "./register.subclis.js";
|
|
|
|
const CLI_NAME = resolveCliName();
|
|
const CLI_NAME_PATTERN = escapeRegExp(CLI_NAME);
|
|
const ROOT_COMMANDS_WITH_SUBCOMMANDS = new Set([
|
|
...getCoreCliCommandsWithSubcommands(),
|
|
...getSubCliCommandsWithSubcommands(),
|
|
]);
|
|
const ROOT_COMMANDS_HINT =
|
|
"Hint: commands suffixed with * have subcommands. Run <command> --help for details.";
|
|
|
|
const EXAMPLES = [
|
|
["openclaw models --help", "Show detailed help for the models command."],
|
|
[
|
|
"openclaw channels login --verbose",
|
|
"Link personal WhatsApp Web and show QR + connection logs.",
|
|
],
|
|
[
|
|
'openclaw message send --target +15555550123 --message "Hi" --json',
|
|
"Send via your web session and print JSON result.",
|
|
],
|
|
["openclaw gateway --port 18789", "Run the WebSocket Gateway locally."],
|
|
["openclaw --dev gateway", "Run a dev Gateway (isolated state/config) on ws://127.0.0.1:19001."],
|
|
["openclaw gateway --force", "Kill anything bound to the default gateway port, then start it."],
|
|
["openclaw gateway ...", "Gateway control via WebSocket."],
|
|
[
|
|
'openclaw agent --to +15555550123 --message "Run summary" --deliver',
|
|
"Talk directly to the agent using the Gateway; optionally send the WhatsApp reply.",
|
|
],
|
|
[
|
|
'openclaw message send --channel telegram --target @mychat --message "Hi"',
|
|
"Send via your Telegram bot.",
|
|
],
|
|
] as const;
|
|
|
|
export function configureProgramHelp(program: Command, ctx: ProgramContext) {
|
|
program
|
|
.name(CLI_NAME)
|
|
.description("")
|
|
.version(ctx.programVersion)
|
|
.option(
|
|
"--dev",
|
|
"Dev profile: isolate state under ~/.openclaw-dev, default gateway port 19001, and shift derived ports (browser/canvas)",
|
|
)
|
|
.option(
|
|
"--profile <name>",
|
|
"Use a named profile (isolates OPENCLAW_STATE_DIR/OPENCLAW_CONFIG_PATH under ~/.openclaw-<name>)",
|
|
)
|
|
.option(
|
|
"--log-level <level>",
|
|
`Global log level override for file + console (${CLI_LOG_LEVEL_VALUES})`,
|
|
parseCliLogLevelOption,
|
|
);
|
|
|
|
program.option("--no-color", "Disable ANSI colors", false);
|
|
program.helpOption("-h, --help", "Display help for command");
|
|
program.helpCommand("help [command]", "Display help for command");
|
|
|
|
program.configureHelp({
|
|
// sort options and subcommands alphabetically
|
|
sortSubcommands: true,
|
|
sortOptions: true,
|
|
optionTerm: (option) => theme.option(option.flags),
|
|
subcommandTerm: (cmd) => {
|
|
const isRootCommand = cmd.parent === program;
|
|
const hasSubcommands = isRootCommand && ROOT_COMMANDS_WITH_SUBCOMMANDS.has(cmd.name());
|
|
return theme.command(hasSubcommands ? `${cmd.name()} *` : cmd.name());
|
|
},
|
|
});
|
|
|
|
const formatHelpOutput = (str: string) => {
|
|
let output = str;
|
|
const isRootHelp = new RegExp(
|
|
`^Usage:\\s+${CLI_NAME_PATTERN}\\s+\\[options\\]\\s+\\[command\\]\\s*$`,
|
|
"m",
|
|
).test(output);
|
|
if (isRootHelp && /^Commands:/m.test(output)) {
|
|
output = output.replace(/^Commands:/m, `Commands:\n ${theme.muted(ROOT_COMMANDS_HINT)}`);
|
|
}
|
|
|
|
return output
|
|
.replace(/^Usage:/gm, theme.heading("Usage:"))
|
|
.replace(/^Options:/gm, theme.heading("Options:"))
|
|
.replace(/^Commands:/gm, theme.heading("Commands:"));
|
|
};
|
|
|
|
program.configureOutput({
|
|
writeOut: (str) => {
|
|
process.stdout.write(formatHelpOutput(str));
|
|
},
|
|
writeErr: (str) => {
|
|
process.stderr.write(formatHelpOutput(str));
|
|
},
|
|
outputError: (str, write) => write(theme.error(str)),
|
|
});
|
|
|
|
if (
|
|
hasFlag(process.argv, "-V") ||
|
|
hasFlag(process.argv, "--version") ||
|
|
hasRootVersionAlias(process.argv)
|
|
) {
|
|
console.log(ctx.programVersion);
|
|
process.exit(0);
|
|
}
|
|
|
|
program.addHelpText("beforeAll", () => {
|
|
if (hasEmittedCliBanner()) {
|
|
return "";
|
|
}
|
|
const rich = isRich();
|
|
const line = formatCliBannerLine(ctx.programVersion, { richTty: rich });
|
|
return `\n${line}\n`;
|
|
});
|
|
|
|
const fmtExamples = EXAMPLES.map(
|
|
([cmd, desc]) => ` ${theme.command(replaceCliName(cmd, CLI_NAME))}\n ${theme.muted(desc)}`,
|
|
).join("\n");
|
|
|
|
program.addHelpText("afterAll", ({ command }) => {
|
|
if (command !== program) {
|
|
return "";
|
|
}
|
|
const docs = formatDocsLink("/cli", "docs.openclaw.ai/cli");
|
|
return `\n${theme.heading("Examples:")}\n${fmtExamples}\n\n${theme.muted("Docs:")} ${docs}\n`;
|
|
});
|
|
}
|