fix(runtime): tailor root help to product entrypoints

- render auth flag sections only for auth domains used by registered commands
- make quick-start prompts opt-in through createCli options
- keep the existing quick-start prompts wired only for bl
This commit is contained in:
若麒
2026-07-09 15:28:08 +08:00
parent 2debfdba6b
commit bd4b0ad9a5
4 changed files with 66 additions and 26 deletions
+8
View File
@@ -2,9 +2,17 @@ import { createCli } from "bailian-cli-runtime";
import { commands } from "./commands.ts";
import pkg from "../package.json" with { type: "json" };
const quickStartTasks = [
"Help me generate a set of Amazon e-commerce main images for baseball caps (white background + lifestyle shots + model wear shots)",
"Help me generate a 3-minute humorous crosstalk audio clip",
"Help me generate a Little Red Riding Hood picture-book PDF (with illustrations)",
"Help me analyze this video and write a Xiaohongshu-style post",
] as const;
void createCli(commands, {
binName: "bl",
version: pkg.version,
clientName: "bailian-cli",
npmPackage: "bailian-cli",
quickStartTasks,
}).run();
+7 -2
View File
@@ -40,6 +40,8 @@ export interface CliOptions {
clientName: string;
/** npm package name for self-update (e.g. "bailian-cli", "bailian-cli-rag"). */
npmPackage: string;
/** Root-help suggestions shown after credentials are configured. */
quickStartTasks?: readonly string[];
}
export interface Cli {
@@ -112,8 +114,11 @@ export function createCli(commands: Record<string, AnyCommand>, opts: CliOptions
} catch {
/* unparseable global flags on the bare invocation — fall through to welcome */
}
if (hasKey) printQuickStart();
else printWelcomeBanner(binName);
if (hasKey) {
if (opts.quickStartTasks?.length) printQuickStart(opts.quickStartTasks);
} else {
printWelcomeBanner(binName);
}
}
async function dispatch(argv: string[]): Promise<void> {
+2 -9
View File
@@ -1,13 +1,6 @@
import { API_KEY_PAGE } from "../urls.ts";
import { ansi } from "./color.ts";
const QUICK_START_TASKS = [
"Help me generate a set of Amazon e-commerce main images for baseball caps (white background + lifestyle shots + model wear shots)",
"Help me generate a 3-minute humorous crosstalk audio clip",
"Help me generate a Little Red Riding Hood picture-book PDF (with illustrations)",
"Help me analyze this video and write a Xiaohongshu-style post",
];
export function printWelcomeBanner(cliName: string): void {
const color = ansi(process.stderr);
process.stderr.write(`\n Welcome to ${color.purple("Bailian")} CLI!\n\n`);
@@ -16,10 +9,10 @@ export function printWelcomeBanner(cliName: string): void {
process.stderr.write(` 2. Login: ${cliName} auth login --api-key <your-key>\n\n`);
}
export function printQuickStart(): void {
export function printQuickStart(tasks: readonly string[]): void {
const color = ansi(process.stderr);
process.stderr.write("\n🎯 Try these with your AI coding assistant:\n\n");
QUICK_START_TASKS.forEach((task, i) => {
tasks.forEach((task, i) => {
process.stderr.write(`${color.dim(String(i + 1))} ${task}\n`);
});
process.stderr.write("\n");
+49 -15
View File
@@ -1,4 +1,4 @@
import type { AnyCommand, FlagDef } from "bailian-cli-core";
import type { AnyCommand, AuthRequirement, FlagDef, FlagsDef } from "bailian-cli-core";
import { UsageError } from "bailian-cli-core";
import {
CONSOLE_AUTH_FLAGS,
@@ -42,6 +42,7 @@ export class CommandRegistry {
private root: CommandNode = { children: new Map() };
/** Binary name shown in usage/help/error strings (e.g. "bl", "rag"). */
private readonly cliName: string;
private readonly authRequirements = new Set<AuthRequirement>();
constructor(commands: Record<string, AnyCommand>, cliName: string) {
this.cliName = cliName;
@@ -67,6 +68,7 @@ export class CommandRegistry {
node = node.children.get(part)!;
}
node.command = command;
this.authRequirements.add(command.auth);
}
getAllCommands(): AnyCommand[] {
@@ -176,7 +178,7 @@ export class CommandRegistry {
}
private buildFlagLines(
defs: Record<string, FlagDef>,
defs: FlagsDef,
a: (s: string) => string,
d: (s: string) => string,
): string {
@@ -188,6 +190,19 @@ export class CommandRegistry {
return lines.map((l) => ` ${a(l.flag.padEnd(maxLen + 2))} ${d(l.desc)}`).join("\n");
}
private buildAuthFlagSection(
auth: AuthRequirement,
label: string,
scope: string,
defs: FlagsDef,
b: (s: string) => string,
a: (s: string) => string,
d: (s: string) => string,
): string | null {
if (!this.authRequirements.has(auth)) return null;
return `${b(label)} ${d(scope)}\n${this.buildFlagLines(defs, a, d)}`;
}
// Color helpers — no-ops when output is not a TTY.
private bold = (s: string, out: NodeJS.WriteStream) => ansi(out).bold(s);
private accent = (s: string, out: NodeJS.WriteStream) => ansi(out).accent(s);
@@ -268,9 +283,37 @@ ${d(` ${this.cliName} pipeline run workflow.yaml --dry-run --output json`)}
const commandLines = this.buildResourceLines(a, d);
const globalFlagLines = this.buildFlagLines(GLOBAL_FLAGS, a, d);
const modelFlagLines = this.buildFlagLines(MODEL_AUTH_FLAGS, a, d);
const consoleFlagLines = this.buildFlagLines(CONSOLE_AUTH_FLAGS, a, d);
const openapiFlagLines = this.buildFlagLines(OPENAPI_AUTH_FLAGS, a, d);
const authFlagSections = [
this.buildAuthFlagSection(
"apiKey",
"Model Auth Flags:",
"(model-domain commands)",
MODEL_AUTH_FLAGS,
b,
a,
d,
),
this.buildAuthFlagSection(
"console",
"Console Auth Flags:",
"(console-domain commands)",
CONSOLE_AUTH_FLAGS,
b,
a,
d,
),
this.buildAuthFlagSection(
"openapi",
"OpenAPI Auth Flags:",
"(openapi-domain commands)",
OPENAPI_AUTH_FLAGS,
b,
a,
d,
),
]
.filter((section): section is string => section !== null)
.join("\n\n");
out.write(`
${b("Usage:")} ${this.cliName} <resource> <command> [flags]
@@ -281,16 +324,7 @@ ${commandLines}
${b("Global Flags:")}
${globalFlagLines}
${b("Model Auth Flags:")} ${d("(model-domain commands)")}
${modelFlagLines}
${b("Console Auth Flags:")} ${d("(console-domain commands)")}
${consoleFlagLines}
${b("OpenAPI Auth Flags:")} ${d("(openapi-domain commands)")}
${openapiFlagLines}
${b("Getting Help:")}
${authFlagSections ? `${authFlagSections}\n\n` : ""}${b("Getting Help:")}
${d("Add --help after any command to see its full list of flags, defaults,")}
${d("and usage examples. For example:")} ${this.cliName} ${this.helpExample()} --help
`);