refactor(commands): decouple command paths from binary name; drop path presets

Commands no longer hardcode "bl" or their path — the runtime renders the
`<bin> <path>` prefix from each product's registry key, so shared commands
show `bl knowledge retrieve` / `rag retrieve` from one codebase. commands
package now exports only individual commands (no groups/catalog); bl and rag
each spell out their own path map. Also removes the unused export-schema command.
This commit is contained in:
若麒
2026-06-24 14:40:08 +08:00
parent ad236e9b11
commit 24abdbf450
82 changed files with 620 additions and 872 deletions
+7 -1
View File
@@ -22,7 +22,13 @@ export { BAILIAN_CONSOLE_ROOT, BAILIAN_CONSOLE, API_KEY_PAGE } from "./urls.ts";
// Output facilities consumed by commands
export { emitResult, emitBare } from "./output/output.ts";
export { promptText, promptSelect, promptConfirm, failIfMissing } from "./output/prompt.ts";
export {
promptText,
promptSelect,
promptConfirm,
failIfMissing,
cmdUsage,
} from "./output/prompt.ts";
export { createSpinner, createProgressBar } from "./output/progress.ts";
export { printWelcomeBanner, printQuickStart } from "./output/banner.ts";
export { maybeShowStatusBar } from "./output/status-bar.ts";
+12 -1
View File
@@ -10,9 +10,20 @@
* case explicitly.
*/
import { BailianError, ExitCode, isInteractive } from "bailian-cli-core";
import { BailianError, ExitCode, isInteractive, type Config } from "bailian-cli-core";
import { printCurrentCommandHelp, getExecutingCommandPath } from "../utils/command-help.ts";
/**
* Build a command-usage string for the running command: `<binName> <path> <args>`.
* Both the product binary name and the command path come from the runtime, so
* callers never hardcode "bl" or their own path — the same code renders as
* `bl knowledge retrieve …` under bl and `rag retrieve …` under rag.
*/
export function cmdUsage(config: Config, args = ""): string {
const parts = [config.binName, ...getExecutingCommandPath()].filter(Boolean);
return args ? `${parts.join(" ")} ${args}` : parts.join(" ");
}
// Dynamic import to avoid loading @clack/prompts in non-interactive envs unnecessarily
// (though for CLI tools the startup cost is usually acceptable)
+10 -6
View File
@@ -165,7 +165,7 @@ export class CommandRegistry {
}
if (node.command) {
this.printCommandHelp(node.command, out);
this.printCommandHelp(node.command, commandPath, out);
return;
}
@@ -244,13 +244,17 @@ ${b("Getting Help:")}
`);
}
private printCommandHelp(cmd: Command, out: NodeJS.WriteStream): void {
private printCommandHelp(cmd: Command, commandPath: string[], out: NodeJS.WriteStream): void {
const b = (s: string) => this.bold(s, out);
const a = (s: string) => this.accent(s, out);
const d = (s: string) => this.dim(s, out);
// `<bin> <path>` prefix is rendered here, not stored in the command, so the
// same command shows the right invocation under any product (bl / rag / …).
const prefix = [this.cliName, ...commandPath].join(" ");
out.write(`\n${cmd.description}\n`);
if (cmd.usage) out.write(`${b("Usage:")} ${cmd.usage}\n`);
out.write(`${b("Usage:")} ${prefix}${cmd.usageArgs ? ` ${cmd.usageArgs}` : ""}\n`);
if (cmd.options && cmd.options.length > 0) {
const maxLen = Math.max(...cmd.options.map((o) => o.flag.length));
out.write(`\n${b("Options:")}\n`);
@@ -264,10 +268,10 @@ ${b("Getting Help:")}
out.write(` ${note}\n`);
}
}
if (cmd.examples && cmd.examples.length > 0) {
if (cmd.exampleArgs && cmd.exampleArgs.length > 0) {
out.write(`\n${b("Examples:")}\n`);
for (const ex of cmd.examples) {
out.write(` ${d(ex)}\n`);
for (const ex of cmd.exampleArgs) {
out.write(` ${d(ex ? `${prefix} ${ex}` : prefix)}\n`);
}
}
out.write(