refactor(core): replace skipDefaultApiKeySetup with required auth field

Commands now declare their credential requirement explicitly via a
required `auth: "apiKey" | "console" | "none"` field instead of the
boolean `skipDefaultApiKeySetup`. The runtime prepares credentials
based on this declaration and skips API-key setup under --dry-run.

- core: add AuthRequirement type and required `auth` field to
  Command/CommandSpec; drop skipDefaultApiKeySetup
- runtime: gate API-key setup on `auth === "apiKey" && !dryRun`
- commands: annotate all 45 commands (apiKey 25 / console 11 / none 9)
This commit is contained in:
若麒
2026-06-24 16:41:09 +08:00
parent 61689ec0da
commit 7a0a083b2e
47 changed files with 62 additions and 26 deletions
@@ -217,6 +217,7 @@ function isEmptyResult(result: RecommendResult): boolean {
export default defineCommand({
description:
"Recommend the best models for your use case (intent analysis → candidate recall → LLM ranking)",
auth: "apiKey",
usageArgs: "<prompt> [flags]",
options: [
{
@@ -16,6 +16,7 @@ import { emitResult, emitBare } from "bailian-cli-runtime";
export default defineCommand({
description: "Call a Bailian application (agent or workflow)",
auth: "apiKey",
usageArgs: "--app-id <id> --prompt <text> [flags]",
options: [
{ flag: "--app-id <id>", description: "Application ID (required)", required: true },
+1 -1
View File
@@ -12,7 +12,7 @@ const APP_LIST_API = "zeldaEasy.broadscope-bailian.app-control.list";
export default defineCommand({
description: "List Bailian applications",
skipDefaultApiKeySetup: true,
auth: "console",
usageArgs: "[flags]",
options: [
{
+1 -1
View File
@@ -19,7 +19,7 @@ import {
export default defineCommand({
description: "Authenticate with API key or console browser login (credentials can coexist)",
skipDefaultApiKeySetup: true,
auth: "none",
usageArgs: "--api-key <key> | --console",
options: [
{ flag: "--api-key <key>", description: "DashScope API key to store" },
@@ -19,7 +19,7 @@ async function clearConsoleToken(): Promise<boolean> {
export default defineCommand({
description: "Clear stored credentials",
skipDefaultApiKeySetup: true,
auth: "none",
usageArgs: "[--console] [--yes] [--dry-run]",
options: [
{
@@ -140,6 +140,7 @@ function emitTextStatus(status: AuthStatusPayload, config: Config): void {
export default defineCommand({
description: "Show current authentication state",
auth: "none",
options: [
{ flag: "--console-region <region>", description: "Console region" },
{
+1 -1
View File
@@ -51,7 +51,7 @@ const KEY_ALIASES: Record<string, string> = {
export default defineCommand({
description: "Set a config value",
skipDefaultApiKeySetup: true,
auth: "none",
usageArgs: "--key <key> --value <value>",
options: [
{
@@ -11,7 +11,7 @@ import { emitResult } from "bailian-cli-runtime";
export default defineCommand({
description: "Display current configuration",
skipDefaultApiKeySetup: true,
auth: "none",
exampleArgs: ["", "--output json"],
async run(config: Config, _flags: GlobalFlags) {
const file = loadConfigFile();
@@ -14,7 +14,7 @@ import { emitResult } from "bailian-cli-runtime";
export default defineCommand({
description: "Call a Bailian console API via the CLI gateway",
skipDefaultApiKeySetup: true,
auth: "console",
usageArgs: "--api <api> --data <json> [flags]",
options: [
{
@@ -11,6 +11,7 @@ import { emitResult, emitBare } from "bailian-cli-runtime";
export default defineCommand({
description: "Upload a local file to DashScope temporary storage (48h)",
auth: "apiKey",
usageArgs: "--file <path> --model <model>",
options: [
{
@@ -28,6 +28,7 @@ import { BOOL_FLAG_PROMPT_EXTEND_CLI_TRUE, BOOL_FLAG_WATERMARK } from "bailian-c
export default defineCommand({
description: "Edit an existing image with text instructions (Qwen-Image)",
auth: "apiKey",
usageArgs: "--image <url> --prompt <text> [flags]",
options: [
{
@@ -39,6 +39,7 @@ function isSyncModel(model: string): boolean {
export default defineCommand({
description: "Generate images (Qwen-Image / wan2.x)",
auth: "apiKey",
usageArgs: "--prompt <text> [flags]",
options: [
{ flag: "--prompt <text>", description: "Image description", required: true },
@@ -24,7 +24,7 @@ const BAILIAN_HOST = "bailian.cn-beijing.aliyuncs.com";
export default defineCommand({
description: "Retrieve from a Bailian knowledge base",
skipDefaultApiKeySetup: true,
auth: "apiKey",
usageArgs: "--index-id <id> --query <text> [flags]",
options: [
{ flag: "--index-id <id>", description: "Knowledge base index ID (required)", required: true },
+1 -1
View File
@@ -31,7 +31,7 @@ function parseArgFlags(raw: string[]): Record<string, unknown> {
export default defineCommand({
description: "Call a tool on an MCP server (tools/call)",
skipDefaultApiKeySetup: true,
auth: "apiKey",
usageArgs: "<server-code>.<tool> [--arg k=v ...] [--json '{...}'] [--url <url>]",
options: [
{
+1 -1
View File
@@ -26,7 +26,7 @@ interface ServerSummary {
export default defineCommand({
description: "List MCP servers activated under your Bailian account",
skipDefaultApiKeySetup: true,
auth: "console",
usageArgs: "[flags]",
options: [
{ flag: "--name <text>", description: "Filter by server name (substring match)" },
+1 -1
View File
@@ -12,7 +12,7 @@ import { ensureApiKey } from "bailian-cli-runtime";
export default defineCommand({
description: "List tools exposed by an MCP server (tools/list)",
skipDefaultApiKeySetup: true,
auth: "apiKey",
usageArgs: "<server-code> [--url <url>]",
options: [
{
@@ -13,6 +13,7 @@ import { emitResult, emitBare } from "bailian-cli-runtime";
export default defineCommand({
description: "Add memory from messages or custom content",
auth: "apiKey",
usageArgs: "--user-id <id> [--messages <json>] [--content <text>] [flags]",
options: [
{ flag: "--user-id <id>", description: "User ID (required)", required: true },
@@ -11,6 +11,7 @@ import { emitResult, emitBare } from "bailian-cli-runtime";
export default defineCommand({
description: "Delete a memory node",
auth: "apiKey",
usageArgs: "--node-id <id> --user-id <id>",
options: [
{ flag: "--node-id <id>", description: "Memory node ID (required)", required: true },
@@ -12,6 +12,7 @@ import { emitResult, emitBare } from "bailian-cli-runtime";
export default defineCommand({
description: "List memory nodes for a user",
auth: "apiKey",
usageArgs: "--user-id <id> [flags]",
options: [
{ flag: "--user-id <id>", description: "User ID (required)", required: true },
@@ -13,6 +13,7 @@ import { emitResult, emitBare } from "bailian-cli-runtime";
export default defineCommand({
description: "Create a user profile schema for memory profiling",
auth: "apiKey",
usageArgs: "--name <name> --attributes <json> [flags]",
options: [
{ flag: "--name <name>", description: "Schema name (required)", required: true },
@@ -12,6 +12,7 @@ import { emitResult, emitBare } from "bailian-cli-runtime";
export default defineCommand({
description: "Get user profile by schema ID and user ID",
auth: "apiKey",
usageArgs: "--schema-id <id> --user-id <id>",
options: [
{ flag: "--schema-id <id>", description: "Profile schema ID (required)", required: true },
@@ -13,6 +13,7 @@ import { emitResult, emitBare } from "bailian-cli-runtime";
export default defineCommand({
description: "Search memory nodes by query or messages",
auth: "apiKey",
usageArgs: "--user-id <id> [--query <text>] [flags]",
options: [
{ flag: "--user-id <id>", description: "User ID (required)", required: true },
@@ -12,6 +12,7 @@ import { emitResult, emitBare } from "bailian-cli-runtime";
export default defineCommand({
description: "Update a memory node content",
auth: "apiKey",
usageArgs: "--node-id <id> --user-id <id> --content <text>",
options: [
{ flag: "--node-id <id>", description: "Memory node ID (required)", required: true },
@@ -86,6 +86,7 @@ function buildWavHeader(dataLength: number): Buffer {
export default defineCommand({
description: "Multimodal chat with text + audio output (Qwen-Omni)",
auth: "apiKey",
usageArgs: "--message <text> [flags]",
options: [
{
@@ -9,7 +9,7 @@ import { loadPipelineFile } from "./load-file.ts";
export default defineCommand({
description: "Run a pipeline workflow definition",
skipDefaultApiKeySetup: true,
auth: "none",
usageArgs: "<file> [flags]",
options: [
{ flag: "--input <json>", description: "Runtime input as inline JSON" },
@@ -7,7 +7,7 @@ import { loadPipelineFile } from "./load-file.ts";
export default defineCommand({
description: "Validate a pipeline definition without executing",
skipDefaultApiKeySetup: true,
auth: "none",
usageArgs: "<file>",
options: [],
exampleArgs: ["workflow.yaml", "workflow.json --output json"],
@@ -236,7 +236,7 @@ function printTable(rows: CheckRow[], noColor: boolean): void {
export default defineCommand({
description: "Check current usage against rate limits",
skipDefaultApiKeySetup: true,
auth: "console",
usageArgs: "[--model <model>] [flags]",
options: [
{
@@ -92,7 +92,7 @@ function printTable(records: LimitApplicationItem[], noColor: boolean, total: nu
export default defineCommand({
description: "View quota change history",
skipDefaultApiKeySetup: true,
auth: "console",
usageArgs: "[flags]",
options: [
{
+1 -1
View File
@@ -151,7 +151,7 @@ function printTable(models: ModelWithQpm[], noColor: boolean): void {
export default defineCommand({
description: "View model RPM/TPM rate limits",
skipDefaultApiKeySetup: true,
auth: "console",
usageArgs: "[--model <model>] [flags]",
options: [
{
@@ -79,7 +79,7 @@ async function fetchModelQpmInfo(
export default defineCommand({
description: "Request a temporary quota increase",
skipDefaultApiKeySetup: true,
auth: "console",
usageArgs: "--model <model> --tpm <value> [flags]",
options: [
{
@@ -13,6 +13,7 @@ import { emitResult } from "bailian-cli-runtime";
export default defineCommand({
description: "Search the web using DashScope MCP WebSearch service",
auth: "apiKey",
usageArgs: "--query <text> [flags]",
options: [
{ flag: "--query <text>", description: "Search query text", required: true },
@@ -24,6 +24,7 @@ import { emitResult, emitBare } from "bailian-cli-runtime";
export default defineCommand({
description: "Recognize speech from audio files (FunAudio-ASR)",
auth: "apiKey",
usageArgs: "--url <audio-url> [flags]",
options: [
{
@@ -143,6 +143,7 @@ function printVoiceList(model: string): void {
export default defineCommand({
description: "Synthesize speech from text (CosyVoice TTS)",
auth: "apiKey",
usageArgs: "--text <text> [flags]",
options: [
{ flag: "--text <text>", description: "Text to synthesize into speech", required: true },
@@ -69,6 +69,7 @@ function parseMessages(flags: GlobalFlags): ParsedMessages {
export default defineCommand({
description: "Send a chat completion (OpenAI compatible, DashScope)",
auth: "apiKey",
usageArgs: "--message <text> [flags]",
options: [
{ flag: "--model <model>", description: "Model ID (default: qwen3.7-max)" },
+1 -1
View File
@@ -29,7 +29,7 @@ function updateAgentSkill(colors: { green: string; yellow: string; reset: string
export default defineCommand({
description: "Update the CLI to the latest version",
skipDefaultApiKeySetup: true,
auth: "none",
exampleArgs: [""],
async run(config) {
const npmPackage = config.npmPackage!;
+1 -1
View File
@@ -185,7 +185,7 @@ async function fetchAllModels(config: Config, token: string): Promise<ModelInfo[
export default defineCommand({
description: "Query free-tier quota for models (all models if --model is omitted)",
skipDefaultApiKeySetup: true,
auth: "console",
usageArgs: "[--model <model>[,model2,...]] [flags]",
options: [
{
@@ -102,7 +102,7 @@ async function fetchAllModelNames(config: Config, token: string): Promise<string
export default defineCommand({
description:
"Enable or disable auto-stop for free-tier models. Enables by default; use --off to disable",
skipDefaultApiKeySetup: true,
auth: "console",
usageArgs: "<--model <model>[,model2,...] | --all> [--off] [flags]",
options: [
{
@@ -286,7 +286,7 @@ function printModelTable(
export default defineCommand({
description: "Query model usage statistics",
skipDefaultApiKeySetup: true,
auth: "console",
usageArgs: "[--model <model>] [--days <days>] [flags]",
options: [
{
@@ -15,6 +15,7 @@ import { emitResult, emitBare } from "bailian-cli-runtime";
export default defineCommand({
description: "Download a completed video by task ID",
auth: "none",
usageArgs: "--task-id <id> --out <path>",
options: [
{ flag: "--task-id <id>", description: "Task ID to download from" },
@@ -27,6 +27,7 @@ import { BOOL_FLAG_PROMPT_EXTEND_API_DEFAULT, BOOL_FLAG_WATERMARK } from "bailia
export default defineCommand({
description:
"Edit a video with happyhorse-1.0-video-edit (style transfer, object replacement, etc.)",
auth: "apiKey",
usageArgs: "--video <url> --prompt <text> [flags]",
options: [
{ flag: "--model <model>", description: "Model ID (default: happyhorse-1.0-video-edit)" },
@@ -28,6 +28,7 @@ import { BOOL_FLAG_PROMPT_EXTEND_API_DEFAULT, BOOL_FLAG_WATERMARK } from "bailia
export default defineCommand({
description:
"Generate a video from text or image (happyhorse-1.0-t2v / happyhorse-1.0-i2v / wan2.6-t2v)",
auth: "apiKey",
usageArgs: "--prompt <text> [--image <url>] [flags]",
options: [
{
@@ -27,6 +27,7 @@ import { BOOL_FLAG_PROMPT_EXTEND_API_DEFAULT, BOOL_FLAG_WATERMARK } from "bailia
export default defineCommand({
description:
"Reference-to-video generation (happyhorse-1.0-r2v / wan2.6-r2v): multi-subject, multi-shot with voice",
auth: "apiKey",
usageArgs: "--prompt <text> --image <url>... [--ref-video <url>...] [flags]",
options: [
{ flag: "--model <model>", description: "Model ID (default: happyhorse-1.0-r2v)" },
@@ -12,6 +12,7 @@ import { emitResult, emitBare } from "bailian-cli-runtime";
export default defineCommand({
description: "Query async task status",
auth: "apiKey",
usageArgs: "--task-id <id>",
options: [{ flag: "--task-id <id>", description: "Async task ID" }],
exampleArgs: [
@@ -58,6 +58,7 @@ async function toImageUrl(image: string): Promise<string> {
export default defineCommand({
description: "Describe an image or video using Qwen-VL",
auth: "apiKey",
usageArgs: "--image <path-or-url> [--video <url>] [--prompt <text>]",
options: [
{ flag: "--image <path-or-url>", description: "Local image path or URL" },
@@ -77,7 +77,7 @@ function printTable(workspaces: WorkspaceInfo[], noColor: boolean): void {
export default defineCommand({
description: "List all workspaces",
skipDefaultApiKeySetup: true,
auth: "console",
usageArgs: "[flags]",
options: [
{
+14 -3
View File
@@ -8,6 +8,15 @@ export interface OptionDef {
required?: boolean;
}
/**
* Credential a command requires. The runtime prepares it before execution.
* - "apiKey" : DashScope API Key. The runtime runs ensureApiKey beforehand,
* except under --dry-run (which only prints the request).
* - "console" : Console Gateway credential (usage / quota / app list / workspace, …).
* - "none" : No credential (config / auth login flow / pipeline validate / update, …).
*/
export type AuthRequirement = "apiKey" | "console" | "none";
export interface Command {
description: string;
/**
@@ -24,7 +33,8 @@ export interface Command {
* `<bin> <path>` per product when rendering help.
*/
exampleArgs?: string[];
skipDefaultApiKeySetup?: boolean;
/** Credential this command requires. See {@link AuthRequirement}. */
auth: AuthRequirement;
notes?: string[];
execute: (config: Config, flags: GlobalFlags) => Promise<void>;
}
@@ -36,7 +46,8 @@ export interface CommandSpec {
options?: OptionDef[];
/** See {@link Command.exampleArgs} — argument strings only, no `<bin> <path>` prefix. */
exampleArgs?: string[];
skipDefaultApiKeySetup?: boolean;
/** Credential this command requires. See {@link AuthRequirement}. */
auth: AuthRequirement;
notes?: string[];
run: (config: Config, flags: GlobalFlags) => Promise<void>;
}
@@ -47,7 +58,7 @@ export function defineCommand(spec: CommandSpec): Command {
usageArgs: spec.usageArgs,
options: spec.options,
exampleArgs: spec.exampleArgs,
skipDefaultApiKeySetup: spec.skipDefaultApiKeySetup,
auth: spec.auth,
notes: spec.notes,
execute: (config, flags) => spec.run(config, flags),
};
+3 -2
View File
@@ -123,8 +123,9 @@ export function createCli(commands: Record<string, Command>, opts: CliOptions):
config.binName = opts.binName;
config.npmPackage = npmPackage;
// 默认执行 ensureApiKey;自行处理鉴权或仅需 Console/AK-SK 等的命令在 defineCommand 上设 skipDefaultApiKeySetup
if (!command.skipDefaultApiKeySetup) {
// 仅 apiKey 类命令由框架统一准备 API Key;dry-run 时跳过(只打印请求,不要求凭证)。
// console 命令在命令体内解析 Console Gateway 凭证;none 命令无需凭证。
if (command.auth === "apiKey" && !config.dryRun) {
await ensureApiKey(config);
try {
const credential = await resolveCredential(config);