diff --git a/AGENTS.md b/AGENTS.md index 51afe94..0c52651 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -93,6 +93,18 @@ CLI 只为「自己能权威解释的错误」发出语义化信号,服务端的 不要扮演服务端错误的翻译官——我们没有最新的错误码体系认知,二次包装只会撒谎(详见 `docs/agents/error-hint-change.md` 中的反面 case)。 +### 4. Console Gateway 命令必须声明 console 全局 flags + +如果新命令使用了 `callConsoleGateway`,必须在 `options` 中添加以下三个全局 flag 的说明,以便 `--help` 中展示: + +```ts +{ flag: "--console-region ", description: "Console region (global flag)" }, +{ flag: "--console-site ", description: "Console site: domestic, international (global flag)" }, +{ flag: "--console-switch-agent ", description: "Switch agent UID (global flag)", type: "number" }, +``` + +这些 flag 已在 `GLOBAL_OPTIONS`(`packages/core/src/types/command.ts`)中注册,由 `loadConfig` 写入 `config.consoleRegion` / `config.consoleSite` / `config.consoleSwitchAgent`,`callConsoleGateway` 自动读取——命令无需手动提取或传递。 + ## 完成改动后的快速验证 ```sh diff --git a/packages/cli/src/commands/app/list.ts b/packages/cli/src/commands/app/list.ts index 904ad47..185ed24 100644 --- a/packages/cli/src/commands/app/list.ts +++ b/packages/cli/src/commands/app/list.ts @@ -29,9 +29,15 @@ export default defineCommand({ description: "Results per page (default: 30)", type: "number", }, + { flag: "--console-region ", description: "Console region (global flag)" }, { - flag: "--region ", - description: "API region (default: cn-beijing)", + flag: "--console-site ", + description: "Console site: domestic, international (global flag)", + }, + { + flag: "--console-switch-agent ", + description: "Switch agent UID (global flag)", + type: "number", }, ], examples: [ @@ -44,7 +50,6 @@ export default defineCommand({ const name = (flags.name as string) || ""; const pageNo = (flags.page as number) || 1; const pageSize = (flags.pageSize as number) || 30; - const region = (flags.region as string) || "cn-beijing"; const format = detectOutputFormat(config.output); const credential = await resolveConsoleGatewayCredential(config); @@ -61,17 +66,13 @@ export default defineCommand({ }; if (config.dryRun) { - emitResult( - { api: APP_LIST_API, data, region, token: credential.token.slice(0, 8) + "..." }, - format, - ); + emitResult({ api: APP_LIST_API, data, token: credential.token.slice(0, 8) + "..." }, format); return; } const result = (await callConsoleGateway(config, credential.token, { api: APP_LIST_API, data, - region, })) as any; const list: unknown[] = result?.data?.DataV2?.data?.data?.list ?? []; diff --git a/packages/cli/src/commands/auth/login-console.ts b/packages/cli/src/commands/auth/login-console.ts index f212325..bfe3193 100644 --- a/packages/cli/src/commands/auth/login-console.ts +++ b/packages/cli/src/commands/auth/login-console.ts @@ -5,18 +5,24 @@ import http from "node:http"; import { BailianError, ExitCode, + chatEndpoint, getConfigPath, readConfigFile, + requestJson, writeConfigFile, + type Config, } from "bailian-cli-core"; const CONSOLE_LOGIN_TIMEOUT_MS = 15 * 60 * 1000; const MAX_AUTH_CALLBACK_BODY = 65536; -const DEFAULT_CONSOLE_ORIGIN = "https://bailian.console.aliyun.com"; +const CONSOLE_ORIGINS: Record = { + domestic: "https://bailian.console.aliyun.com", + international: "https://modelstudio.console.alibabacloud.com", +}; -export function resolveConsoleOrigin(): string { - return process.env.BAILIAN_CONSOLE_ORIGIN || DEFAULT_CONSOLE_ORIGIN; +export function resolveConsoleOrigin(site?: string): string { + return (site && CONSOLE_ORIGINS[site]) || CONSOLE_ORIGINS.domestic!; } function readBodyBounded(req: http.IncomingMessage): Promise { @@ -210,9 +216,76 @@ function parseApiKeyFromRawBody(raw: string, contentType: string): string | null return null; } +type CallbackExtras = Pick< + CallbackCredentials, + "baseUrl" | "consoleSite" | "consoleRegion" | "consoleSwitchAgent" | "workspaceId" +>; + +function stringField(o: Record, ...keys: string[]): string | null { + for (const k of keys) { + const v = o[k]; + if (typeof v === "string" && v.trim()) return v.trim(); + } + return null; +} + +function parseExtrasFromRawBody(raw: string, contentType: string): CallbackExtras { + const empty: CallbackExtras = { + baseUrl: null, + consoleSite: null, + consoleRegion: null, + consoleSwitchAgent: null, + workspaceId: null, + }; + if (!raw.trim()) return empty; + + let obj: Record | null = null; + + const ct = contentType.toLowerCase(); + if (ct.includes("application/json") || ct.includes("text/json")) { + try { + const parsed = JSON.parse(raw.trim()); + if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) obj = parsed; + } catch { + /* */ + } + } + if (!obj && ct.includes("application/x-www-form-urlencoded")) { + try { + const params = new URLSearchParams(raw.trim()); + obj = Object.fromEntries(params); + } catch { + /* */ + } + } + if (!obj) { + try { + const parsed = JSON.parse(raw.trim()); + if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) obj = parsed; + } catch { + /* */ + } + } + + if (!obj) return empty; + + return { + baseUrl: stringField(obj, "base_url", "baseUrl"), + consoleSite: stringField(obj, "console_site", "consoleSite"), + consoleRegion: stringField(obj, "console_region", "consoleRegion"), + consoleSwitchAgent: stringField(obj, "console_switch_agent", "consoleSwitchAgent"), + workspaceId: stringField(obj, "workspace_id", "workspaceId"), + }; +} + interface CallbackCredentials { accessToken: string | null; apiKey: string | null; + baseUrl: string | null; + consoleSite: string | null; + consoleRegion: string | null; + consoleSwitchAgent: string | null; + workspaceId: string | null; } async function extractCredentialsFromRequest( @@ -222,12 +295,30 @@ async function extractCredentialsFromRequest( const accessTokenFromQuery = u.searchParams.get("access_token") ?? u.searchParams.get("accessToken"); const apiKeyFromQuery = u.searchParams.get("api_key") ?? u.searchParams.get("apiKey"); + const baseUrlFromQuery = u.searchParams.get("base_url") ?? u.searchParams.get("baseUrl"); + const consoleSiteFromQuery = + u.searchParams.get("console_site") ?? u.searchParams.get("consoleSite"); + const consoleRegionFromQuery = + u.searchParams.get("console_region") ?? u.searchParams.get("consoleRegion"); + const consoleSwitchAgentFromQuery = + u.searchParams.get("console_switch_agent") ?? u.searchParams.get("consoleSwitchAgent"); + const workspaceIdFromQuery = + u.searchParams.get("workspace_id") ?? u.searchParams.get("workspaceId"); + + const extras = { + baseUrl: baseUrlFromQuery?.trim() || null, + consoleSite: consoleSiteFromQuery?.trim() || null, + consoleRegion: consoleRegionFromQuery?.trim() || null, + consoleSwitchAgent: consoleSwitchAgentFromQuery?.trim() || null, + workspaceId: workspaceIdFromQuery?.trim() || null, + }; const m = req.method ?? "GET"; if (m !== "POST" && m !== "PUT" && m !== "PATCH") { return { accessToken: accessTokenFromQuery?.trim() || null, apiKey: apiKeyFromQuery?.trim() || null, + ...extras, }; } @@ -239,12 +330,24 @@ async function extractCredentialsFromRequest( return { accessToken: accessTokenFromQuery?.trim() || null, apiKey: apiKeyFromQuery?.trim() || null, + ...extras, }; } const accessToken = accessTokenFromQuery?.trim() || parseAccessTokenFromRawBody(raw, contentType); const apiKey = apiKeyFromQuery?.trim() || parseApiKeyFromRawBody(raw, contentType); - return { accessToken, apiKey }; + + const bodyExtras = parseExtrasFromRawBody(raw, contentType); + + return { + accessToken, + apiKey, + baseUrl: extras.baseUrl || bodyExtras.baseUrl, + consoleSite: extras.consoleSite || bodyExtras.consoleSite, + consoleRegion: extras.consoleRegion || bodyExtras.consoleRegion, + consoleSwitchAgent: extras.consoleSwitchAgent || bodyExtras.consoleSwitchAgent, + workspaceId: extras.workspaceId || bodyExtras.workspaceId, + }; } function listenServerOnFreeLocalPort(server: http.Server): Promise { @@ -276,9 +379,69 @@ function openInBrowser(url: string): Promise { }); } +const RETRY_DELAY_BASE_MS = 500; + +function canRetry(err: unknown): boolean { + if (err instanceof BailianError) { + if (err.exitCode === ExitCode.NETWORK || err.exitCode === ExitCode.TIMEOUT) return true; + const status = err.api?.httpStatus; + return status === 401 || (status !== undefined && status >= 500); + } + if (err instanceof Error) { + return ( + err.name === "AbortError" || + err.name === "TimeoutError" || + err.message.includes("timed out") || + err.message === "fetch failed" + ); + } + return false; +} + +export async function validateAndPersistApiKey( + config: Config, + key: string, + baseUrl: string, +): Promise { + process.stderr.write("Testing key... "); + const testConfig = { ...config, apiKey: key, baseUrl }; + const requestOpts = { + url: chatEndpoint(testConfig.baseUrl), + method: "POST", + timeout: Math.min(config.timeout, 30), + body: { + model: "qwen3.7-max", + messages: [{ role: "user", content: "hi" }], + max_tokens: 1, + }, + }; + + for (let attempt = 1; attempt <= 3; attempt++) { + try { + await requestJson(testConfig, requestOpts); + break; + } catch (err) { + if (attempt >= 3 || !canRetry(err)) { + process.stderr.write("Failed\n"); + throw new BailianError("API key validation failed", ExitCode.AUTH, "Invalid API key.", { + cause: err, + }); + } + const delayMs = RETRY_DELAY_BASE_MS * 2 ** (attempt - 1); + await new Promise((resolve) => setTimeout(resolve, delayMs)); + } + } + + process.stderr.write("Valid\n"); + const existing = readConfigFile() as Record; + existing.api_key = key; + await writeConfigFile(existing); +} + export async function runConsoleLogin( consoleOrigin: string, - opts?: { needApiKey?: boolean; onApiKey?: (key: string) => Promise }, + config: Config, + opts?: { needApiKey?: boolean }, ): Promise { const state = randomBytes(16).toString("hex"); let callbackError: unknown; @@ -301,18 +464,35 @@ export async function runConsoleLogin( return; } - const { accessToken, apiKey } = await extractCredentialsFromRequest(req); + const { + accessToken, + apiKey, + baseUrl, + consoleSite, + consoleRegion, + consoleSwitchAgent, + workspaceId, + } = await extractCredentialsFromRequest(req); + + const hasConfig = + accessToken || baseUrl || consoleSite || consoleRegion || consoleSwitchAgent || workspaceId; - if (accessToken || apiKey) { + if (hasConfig || apiKey) { try { - if (accessToken) { + if (hasConfig) { const existing = readConfigFile() as Record; - existing.access_token = accessToken; + if (accessToken) existing.access_token = accessToken; + if (baseUrl) existing.base_url = baseUrl; + if (consoleSite) existing.console_site = consoleSite; + if (consoleRegion) existing.console_region = consoleRegion; + if (consoleSwitchAgent) existing.console_switch_agent = Number(consoleSwitchAgent); + if (workspaceId) existing.workspace_id = workspaceId; await writeConfigFile(existing); - process.stderr.write(`access_token saved to ${getConfigPath()}\n`); + process.stderr.write(`Config saved to ${getConfigPath()}\n`); } - if (apiKey && opts?.onApiKey) { - await opts.onApiKey(apiKey); + if (apiKey) { + const testBaseUrl = baseUrl || config.baseUrl; + await validateAndPersistApiKey(config, apiKey, testBaseUrl); } } catch (err: unknown) { callbackError = err; @@ -329,7 +509,7 @@ export async function runConsoleLogin( }); res.end("OK\n"); - if (accessToken || apiKey) { + if (hasConfig || apiKey) { server.close(); } } catch { diff --git a/packages/cli/src/commands/auth/login.ts b/packages/cli/src/commands/auth/login.ts index 0fe05ed..809d5b3 100644 --- a/packages/cli/src/commands/auth/login.ts +++ b/packages/cli/src/commands/auth/login.ts @@ -1,13 +1,8 @@ import { - BailianError, - ExitCode, - chatEndpoint, defineCommand, - getConfigPath, isInteractive, maskToken, readConfigFile, - requestJson, writeConfigFile, type Config, type GlobalFlags, @@ -16,67 +11,11 @@ import { printQuickStart } from "../../output/banner.ts"; import { emitBare } from "../../output/output.ts"; import { promptConfirm } from "../../output/prompt.ts"; import { printCurrentCommandHelp } from "../../utils/command-help.ts"; -import { resolveConsoleOrigin, runConsoleLogin } from "./login-console.ts"; - -const RETRY_DELAY_BASE_MS = 500; - -function canRetry(err: unknown): boolean { - if (err instanceof BailianError) { - if (err.exitCode === ExitCode.NETWORK || err.exitCode === ExitCode.TIMEOUT) { - return true; - } - const status = err.api?.httpStatus; - return status === 401 || (status !== undefined && status >= 500); - } - if (err instanceof Error) { - return ( - err.name === "AbortError" || - err.name === "TimeoutError" || - err.message.includes("timed out") || - err.message === "fetch failed" - ); - } - return false; -} - -async function validateKeyAndPersist(config: Config, key: string): Promise { - process.stderr.write("Testing key... "); - const testConfig = { ...config, apiKey: key }; - const requestOpts = { - url: chatEndpoint(testConfig.baseUrl), - method: "POST", - timeout: Math.min(config.timeout, 30), - body: { - model: "qwen3.7-max", - messages: [{ role: "user", content: "hi" }], - max_tokens: 1, - }, - }; - - for (let attempt = 1; attempt <= 3; attempt++) { - try { - await requestJson(testConfig, requestOpts); - break; - } catch (err) { - if (attempt >= 3 || !canRetry(err)) { - process.stderr.write("\n"); - throw new BailianError("API key validation failed", ExitCode.AUTH, "Invalid API key.", { - cause: err, - }); - } - // retry delay: 500ms, 1000ms, 2000ms - const delayMs = RETRY_DELAY_BASE_MS * 2 ** (attempt - 1); - await new Promise((resolve) => setTimeout(resolve, delayMs)); - } - } - - process.stderr.write("Valid\n"); - - const existing = readConfigFile() as Record; - existing.api_key = key; - await writeConfigFile(existing); - process.stderr.write(`Saved to ${getConfigPath()}\n`); -} +import { + resolveConsoleOrigin, + runConsoleLogin, + validateAndPersistApiKey, +} from "./login-console.ts"; export default defineCommand({ name: "auth login", @@ -84,10 +23,14 @@ export default defineCommand({ usage: "bl auth login --api-key | bl auth login --console", options: [ { flag: "--api-key ", description: "DashScope API key to store" }, + { + flag: "--base-url ", + description: "DashScope API base URL (used with --api-key for validation)", + }, { flag: "--console", - description: "Sign in via browser; opens the console login URL in your default browser", - type: "boolean", + description: + "Sign in via browser; use --console-site to choose domestic (default) or international", }, ], examples: ["bl auth login --api-key sk-xxxxx", "bl auth login --console"], @@ -100,9 +43,8 @@ export default defineCommand({ return; } const hasApiKey = !!(config.apiKey || config.fileApiKey); - await runConsoleLogin(resolveConsoleOrigin(), { + await runConsoleLogin(resolveConsoleOrigin(config.consoleSite || "domestic"), config, { needApiKey: !hasApiKey, - onApiKey: (key) => validateKeyAndPersist(config, key), }); return; } @@ -130,8 +72,16 @@ export default defineCommand({ process.exit(0); } + const baseUrl = (flags.baseUrl as string) || undefined; + const effectiveConfig = baseUrl ? { ...config, baseUrl } : config; + if (!config.dryRun) { - await validateKeyAndPersist(config, key); + if (baseUrl) { + const existing = readConfigFile() as Record; + existing.base_url = baseUrl; + await writeConfigFile(existing); + } + await validateAndPersistApiKey(effectiveConfig, key, effectiveConfig.baseUrl); printQuickStart(); } else { emitBare("Would validate and save API key."); diff --git a/packages/cli/src/commands/auth/status.ts b/packages/cli/src/commands/auth/status.ts index 7ea9b85..5276638 100644 --- a/packages/cli/src/commands/auth/status.ts +++ b/packages/cli/src/commands/auth/status.ts @@ -142,6 +142,18 @@ export default defineCommand({ name: "auth status", description: "Show current authentication state", usage: "bl auth status", + options: [ + { flag: "--console-region ", description: "Console region (global flag)" }, + { + flag: "--console-site ", + description: "Console site: domestic, international (global flag)", + }, + { + flag: "--console-switch-agent ", + description: "Switch agent UID (global flag)", + type: "number", + }, + ], examples: ["bl auth status", "bl auth status --output json"], async run(config: Config, _flags: GlobalFlags) { const format = detectOutputFormat(config.output); diff --git a/packages/cli/src/commands/config/show.ts b/packages/cli/src/commands/config/show.ts index 6f268e2..37e590c 100644 --- a/packages/cli/src/commands/config/show.ts +++ b/packages/cli/src/commands/config/show.ts @@ -19,25 +19,21 @@ export default defineCommand({ const format = detectOutputFormat(config.output); const result: Record = { - region: config.region, + ...file, base_url: config.baseUrl, output: config.output, timeout: config.timeout, config_file: getConfigPath(), }; - // Mask API key if present - if (file.api_key) { - result.api_key = maskToken(file.api_key); + if (typeof result.api_key === "string") result.api_key = maskToken(result.api_key); + if (typeof result.access_token === "string") + result.access_token = maskToken(result.access_token); + if (typeof result.access_key_id === "string") + result.access_key_id = maskToken(result.access_key_id); + if (typeof result.access_key_secret === "string") { + result.access_key_secret = maskToken(result.access_key_secret); } - if (file.access_token) { - result.access_token = maskToken(file.access_token); - } - - // Default models - if (file.default_text_model) result.default_text_model = file.default_text_model; - if (file.default_video_model) result.default_video_model = file.default_video_model; - if (file.default_image_model) result.default_image_model = file.default_image_model; emitResult(result, format); }, diff --git a/packages/cli/src/commands/console/call.ts b/packages/cli/src/commands/console/call.ts index b3d01ba..b278fa5 100644 --- a/packages/cli/src/commands/console/call.ts +++ b/packages/cli/src/commands/console/call.ts @@ -1,6 +1,7 @@ import { defineCommand, callConsoleGateway, + effectiveConsoleGatewayConfig, resolveConsoleGatewayCredential, CONSOLE_GATEWAY_NO_TOKEN_MESSAGE, BailianError, @@ -26,14 +27,20 @@ export default defineCommand({ description: "Request data as JSON string", required: true, }, + { flag: "--console-region ", description: "Console region (global flag)" }, { - flag: "--region ", - description: "API region (default: cn-beijing)", + flag: "--console-site ", + description: "Console site: domestic, international (global flag)", + }, + { + flag: "--console-switch-agent ", + description: "Switch agent UID (global flag)", + type: "number", }, ], examples: [ `bl console call --api zeldaEasy.broadscope-bailian.freeTrial.queryFreeTierQuota --data '{"queryFreeTierQuotaRequest":{"models":["qwen3-max"]}}'`, - `bl console call --api some.api.name --data '{"key":"value"}' --region cn-beijing`, + `bl console call --api some.api.name --data '{"key":"value"}' --console-region cn-beijing`, ], async run(config: Config, flags: GlobalFlags) { const api = flags.api as string; @@ -50,7 +57,6 @@ export default defineCommand({ process.exit(1); } - const region = (flags.region as string) || "cn-beijing"; const format = detectOutputFormat(config.output); let token: string | undefined; @@ -63,14 +69,21 @@ export default defineCommand({ } if (config.dryRun) { - emitResult({ api, data, region, token: token ? token.slice(0, 8) + "..." : null }, format); + emitResult( + { + api, + data, + token: token ? token.slice(0, 8) + "..." : null, + ...effectiveConsoleGatewayConfig(config), + }, + format, + ); return; } const result = await callConsoleGateway(config, token, { api, data, - region, }); emitResult(result, format); diff --git a/packages/cli/src/commands/mcp/list.ts b/packages/cli/src/commands/mcp/list.ts index 561bd0e..48b7c42 100644 --- a/packages/cli/src/commands/mcp/list.ts +++ b/packages/cli/src/commands/mcp/list.ts @@ -1,6 +1,7 @@ import { defineCommand, callConsoleGateway, + effectiveConsoleGatewayConfig, resolveConsoleGatewayCredential, detectOutputFormat, BailianError, @@ -35,7 +36,16 @@ export default defineCommand({ }, { flag: "--page ", description: "Page number (default: 1)", type: "number" }, { flag: "--page-size ", description: "Results per page (default: 30)", type: "number" }, - { flag: "--region ", description: "API region (default: cn-beijing)" }, + { flag: "--console-region ", description: "Console region (global flag)" }, + { + flag: "--console-site ", + description: "Console site: domestic, international (global flag)", + }, + { + flag: "--console-switch-agent ", + description: "Switch agent UID (global flag)", + type: "number", + }, ], examples: ["bl mcp list", "bl mcp list --name 金融", "bl mcp list --output json"], async run(config: Config, flags: GlobalFlags) { @@ -43,7 +53,6 @@ export default defineCommand({ const type = (flags.type as string) || "OFFICIAL"; const pageNo = (flags.page as number) || 1; const pageSize = (flags.pageSize as number) || 30; - const region = (flags.region as string) || "cn-beijing"; const format = detectOutputFormat(config.output); const data = { @@ -58,7 +67,7 @@ export default defineCommand({ }; if (config.dryRun) { - emitResult({ api: MCP_LIST_API, data, region }, format); + emitResult({ api: MCP_LIST_API, data, ...effectiveConsoleGatewayConfig(config) }, format); return; } @@ -67,7 +76,6 @@ export default defineCommand({ const result = (await callConsoleGateway(config, credential.token, { api: MCP_LIST_API, data, - region, })) as Record; const dataField = (result?.data as Record | undefined) ?? {}; diff --git a/packages/cli/src/commands/quota/check.ts b/packages/cli/src/commands/quota/check.ts index 5c52fa8..09065cc 100644 --- a/packages/cli/src/commands/quota/check.ts +++ b/packages/cli/src/commands/quota/check.ts @@ -1,6 +1,7 @@ import { defineCommand, callConsoleGateway, + effectiveConsoleGatewayConfig, resolveConsoleGatewayCredential, detectOutputFormat, type Config, @@ -91,11 +92,7 @@ function extractResponseData(result: Record): Record { +async function fetchAllModelsWithQpm(config: Config, token: string): Promise { const allModels: ModelWithQpm[] = []; let pageNo = 1; @@ -112,7 +109,6 @@ async function fetchAllModelsWithQpm( supports: { selfServiceLimitIncrease: true }, }, }, - region, }); const resp = extractResponseData(raw as Record); @@ -130,7 +126,6 @@ async function fetchAllModelsWithQpm( async function fetchMonitorData( config: Config, token: string, - region: string, modelName: string, windowMinutes: number, ): Promise<{ rpm: number; tpm: number }> { @@ -155,7 +150,6 @@ async function fetchMonitorData( endTime: now, }, }, - region, }); const resp = extractResponseData(raw as Record); @@ -260,9 +254,15 @@ export default defineCommand({ flag: "--period ", description: "Query usage for the last N minutes (default: 2)", }, + { flag: "--console-region ", description: "Console region (global flag)" }, + { + flag: "--console-site ", + description: "Console site: domestic, international (global flag)", + }, { - flag: "--region ", - description: "API region (default: cn-beijing)", + flag: "--console-switch-agent ", + description: "Switch agent UID (global flag)", + type: "number", }, ], examples: [ @@ -280,7 +280,6 @@ export default defineCommand({ process.exit(1); } const windowMinutes = rawPeriod; - const region = (flags.region as string) || "cn-beijing"; const format = detectOutputFormat(config.output); const credential = await resolveConsoleGatewayCredential(config); @@ -289,14 +288,14 @@ export default defineCommand({ emitResult( { apis: [MODEL_LIST_API, MONITOR_API], - region, + ...effectiveConsoleGatewayConfig(config), }, format, ); return; } - let models = await fetchAllModelsWithQpm(config, credential.token, region); + let models = await fetchAllModelsWithQpm(config, credential.token); if (modelFlag) { const names = new Set( @@ -316,7 +315,7 @@ export default defineCommand({ } const monitorResults = await Promise.all( - models.map((m) => fetchMonitorData(config, credential.token, region, m.model, windowMinutes)), + models.map((m) => fetchMonitorData(config, credential.token, m.model, windowMinutes)), ); const checkRows: CheckRow[] = models.map((m, idx) => { diff --git a/packages/cli/src/commands/quota/history.ts b/packages/cli/src/commands/quota/history.ts index 99dd510..3d6593c 100644 --- a/packages/cli/src/commands/quota/history.ts +++ b/packages/cli/src/commands/quota/history.ts @@ -114,9 +114,15 @@ export default defineCommand({ flag: "--model ", description: "Filter by model name", }, + { flag: "--console-region ", description: "Console region (global flag)" }, { - flag: "--region ", - description: "API region (default: cn-beijing)", + flag: "--console-site ", + description: "Console site: domestic, international (global flag)", + }, + { + flag: "--console-switch-agent ", + description: "Switch agent UID (global flag)", + type: "number", }, ], examples: [ @@ -130,7 +136,6 @@ export default defineCommand({ const page = Number(flags.page) || 1; const pageSize = Number(flags.pageSize) || 10; const modelFilter = (flags.model as string) || undefined; - const region = (flags.region as string) || "cn-beijing"; const format = detectOutputFormat(config.output); const credential = await resolveConsoleGatewayCredential(config); @@ -140,7 +145,7 @@ export default defineCommand({ }; if (config.dryRun) { - emitResult({ api: HISTORY_API, data: requestData, region }, format); + emitResult({ api: HISTORY_API, data: requestData }, format); return; } @@ -149,7 +154,6 @@ export default defineCommand({ result = await callConsoleGateway(config, credential.token, { api: HISTORY_API, data: requestData, - region, }); } catch (err) { if (err instanceof BailianError && err.message.includes("NotLogined")) { diff --git a/packages/cli/src/commands/quota/list.ts b/packages/cli/src/commands/quota/list.ts index 3002757..06e2b2a 100644 --- a/packages/cli/src/commands/quota/list.ts +++ b/packages/cli/src/commands/quota/list.ts @@ -68,7 +68,6 @@ function extractResponseData(result: Record): Record { const allModels: ModelWithQpm[] = []; @@ -89,7 +88,6 @@ async function fetchAllModelsWithQpm( const raw = await callConsoleGateway(config, token, { api: MODEL_LIST_API, data: { input }, - region, }); const resp = extractResponseData(raw as Record); @@ -171,9 +169,15 @@ export default defineCommand({ flag: "--all", description: "Show all models, not just self-service ones", }, + { flag: "--console-region ", description: "Console region (global flag)" }, { - flag: "--region ", - description: "API region (default: cn-beijing)", + flag: "--console-site ", + description: "Console site: domestic, international (global flag)", + }, + { + flag: "--console-switch-agent ", + description: "Switch agent UID (global flag)", + type: "number", }, ], examples: [ @@ -186,7 +190,6 @@ export default defineCommand({ async run(config: Config, flags: GlobalFlags) { const modelFlag = (flags.model as string) || undefined; const showAll = Boolean(flags.all); - const region = (flags.region as string) || "cn-beijing"; const format = detectOutputFormat(config.output); const credential = await resolveConsoleGatewayCredential(config); @@ -200,11 +203,11 @@ export default defineCommand({ ignoreWorkspaceServiceSite: true, }; if (!showAll) input.supports = { selfServiceLimitIncrease: true }; - emitResult({ api: MODEL_LIST_API, data: { input }, region }, format); + emitResult({ api: MODEL_LIST_API, data: { input } }, format); return; } - let models = await fetchAllModelsWithQpm(config, credential.token, region, !showAll); + let models = await fetchAllModelsWithQpm(config, credential.token, !showAll); if (modelFlag) { const names = new Set( diff --git a/packages/cli/src/commands/quota/request.ts b/packages/cli/src/commands/quota/request.ts index 60f727b..89c7660 100644 --- a/packages/cli/src/commands/quota/request.ts +++ b/packages/cli/src/commands/quota/request.ts @@ -53,7 +53,6 @@ function extractResponseData(result: Record): Record } | undefined> { const raw = await callConsoleGateway(config, token, { @@ -69,7 +68,6 @@ async function fetchModelQpmInfo( supports: { selfServiceLimitIncrease: true }, }, }, - region, }); const resp = extractResponseData(raw as Record); @@ -98,9 +96,15 @@ export default defineCommand({ flag: "--yes", description: "Skip downgrade confirmation", }, + { flag: "--console-region ", description: "Console region (global flag)" }, { - flag: "--region ", - description: "API region (default: cn-beijing)", + flag: "--console-site ", + description: "Console site: domestic, international (global flag)", + }, + { + flag: "--console-switch-agent ", + description: "Switch agent UID (global flag)", + type: "number", }, ], examples: [ @@ -122,12 +126,11 @@ export default defineCommand({ } const autoConfirm = Boolean(flags.yes) || config.yes; - const region = (flags.region as string) || "cn-beijing"; const format = detectOutputFormat(config.output); const credential = await resolveConsoleGatewayCredential(config); - const modelInfo = await fetchModelQpmInfo(config, credential.token, region, modelName); + const modelInfo = await fetchModelQpmInfo(config, credential.token, modelName); if (!modelInfo) { process.stderr.write( `Error: model "${modelName}" not found or does not support self-service quota increase.\n`, @@ -160,7 +163,7 @@ export default defineCommand({ }; if (config.dryRun) { - emitResult({ api: UPDATE_LIMITS_API, data: requestData, region }, format); + emitResult({ api: UPDATE_LIMITS_API, data: requestData }, format); return; } @@ -172,7 +175,6 @@ export default defineCommand({ return await callConsoleGateway(config, credential.token, { api: UPDATE_LIMITS_API, data: requestData, - region, }); } catch (err) { if (err instanceof BailianError && err.message.includes("NotLogined")) { diff --git a/packages/cli/src/commands/usage/free.ts b/packages/cli/src/commands/usage/free.ts index 3dd11a0..d6ef941 100644 --- a/packages/cli/src/commands/usage/free.ts +++ b/packages/cli/src/commands/usage/free.ts @@ -207,9 +207,15 @@ export default defineCommand({ flag: "--sort ", description: "Sort by: remaining (ascending), expires (ascending)", }, + { flag: "--console-region ", description: "Console region (global flag)" }, { - flag: "--region ", - description: "API region (default: cn-beijing)", + flag: "--console-site ", + description: "Console site: domestic, international (global flag)", + }, + { + flag: "--console-switch-agent ", + description: "Switch agent UID (global flag)", + type: "number", }, ], examples: [ @@ -219,7 +225,7 @@ export default defineCommand({ "bl usage free --expiring 30", "bl usage free --sort remaining", "bl usage free --model qwen-turbo --output json", - "bl usage free --model qwen3-max --region cn-beijing", + "bl usage free --model qwen3-max --console-region cn-beijing", ], async run(config: Config, flags: GlobalFlags) { const modelFlag = (flags.model as string) || undefined; @@ -232,7 +238,6 @@ export default defineCommand({ ); process.exit(1); } - const region = (flags.region as string) || "cn-beijing"; const format = detectOutputFormat(config.output); const credential = await resolveConsoleGatewayCredential(config); @@ -275,7 +280,6 @@ export default defineCommand({ { api: FREE_TIER_API, data: requestData, - region, token: credential.token.slice(0, 8) + "...", }, format, @@ -287,12 +291,10 @@ export default defineCommand({ callConsoleGateway(config, credential.token, { api: FREE_TIER_API, data: requestData, - region, }), callConsoleGateway(config, credential.token, { api: FREE_TIER_ONLY_STATUS_API, data: { queryFreeTierOnlyStatusRequest: { models } }, - region, }), ]); diff --git a/packages/cli/src/commands/usage/freetier.ts b/packages/cli/src/commands/usage/freetier.ts index 8894b02..ec820ec 100644 --- a/packages/cli/src/commands/usage/freetier.ts +++ b/packages/cli/src/commands/usage/freetier.ts @@ -63,7 +63,6 @@ async function pollUntilDone( api: string, requestKey: string, models: string[], - region: string, ): Promise { let nextTaskId: string | undefined; @@ -75,7 +74,6 @@ async function pollUntilDone( const raw = await callConsoleGateway(config, token, { api, data: requestData, - region, }); const resp = extractResponseData(raw as Record); @@ -123,9 +121,15 @@ export default defineCommand({ flag: "--off", description: "Disable auto-stop", }, + { flag: "--console-region ", description: "Console region (global flag)" }, { - flag: "--region ", - description: "API region (default: cn-beijing)", + flag: "--console-site ", + description: "Console site: domestic, international (global flag)", + }, + { + flag: "--console-switch-agent ", + description: "Switch agent UID (global flag)", + type: "number", }, ], examples: [ @@ -140,7 +144,6 @@ export default defineCommand({ const modelFlag = (flags.model as string) || undefined; const all = Boolean(flags.all); const off = Boolean(flags.off); - const region = (flags.region as string) || "cn-beijing"; const format = detectOutputFormat(config.output); if (!modelFlag && !all) { @@ -176,7 +179,6 @@ export default defineCommand({ { api, data: { [requestKey]: { models } }, - region, token: credential.token.slice(0, 8) + "...", }, format, @@ -189,12 +191,10 @@ export default defineCommand({ callConsoleGateway(config, credential.token, { api: FREE_TIER_API, data: { queryFreeTierQuotaRequest: { models } }, - region, }), callConsoleGateway(config, credential.token, { api: FREE_TIER_ONLY_STATUS_API, data: { queryFreeTierOnlyStatusRequest: { models } }, - region, }), ]); @@ -218,7 +218,7 @@ export default defineCommand({ ); continue; } - await pollUntilDone(config, credential.token, api, requestKey, [name], region); + await pollUntilDone(config, credential.token, api, requestKey, [name]); process.stdout.write(`Disabled auto-stop for "${name}".\n`); } return; @@ -226,7 +226,7 @@ export default defineCommand({ const jsonResults: unknown[] = []; for (const name of models) { - const result = await pollUntilDone(config, credential.token, api, requestKey, [name], region); + const result = await pollUntilDone(config, credential.token, api, requestKey, [name]); if (format === "json") { jsonResults.push(result); continue; diff --git a/packages/cli/src/commands/usage/stats.ts b/packages/cli/src/commands/usage/stats.ts index fb5074b..46d0f49 100644 --- a/packages/cli/src/commands/usage/stats.ts +++ b/packages/cli/src/commands/usage/stats.ts @@ -70,7 +70,6 @@ async function pollTelemetryApi( token: string, api: string, reqDTO: Record, - region: string, ): Promise { let nextTaskId: string | undefined; @@ -82,7 +81,6 @@ async function pollTelemetryApi( const raw = await callConsoleGateway(config, token, { api, data: requestData, - region, }); const resp = extractResponseData(raw as Record); @@ -325,9 +323,15 @@ export default defineCommand({ flag: "--workspace-id ", description: "Workspace ID (env: BAILIAN_WORKSPACE_ID)", }, + { flag: "--console-region ", description: "Console region (global flag)" }, { - flag: "--region ", - description: "API region (default: cn-beijing)", + flag: "--console-site ", + description: "Console site: domestic, international (global flag)", + }, + { + flag: "--console-switch-agent ", + description: "Switch agent UID (global flag)", + type: "number", }, ], examples: [ @@ -343,7 +347,6 @@ export default defineCommand({ const modelFlag = (flags.model as string) || undefined; const daysFlag = Number(flags.days) || 7; const typeFlag = (flags.type as string) || undefined; - const region = (flags.region as string) || "cn-beijing"; const format = detectOutputFormat(config.output); const flagWorkspaceId = (flags.workspaceId as string) || undefined; @@ -378,7 +381,7 @@ export default defineCommand({ if (config.dryRun) { emitResult( - { api: LIST_API, data: { reqDTO: { ...baseReqDTO, model: models.join(",") } }, region }, + { api: LIST_API, data: { reqDTO: { ...baseReqDTO, model: models.join(",") } } }, format, ); return; @@ -386,7 +389,7 @@ export default defineCommand({ const results = await Promise.all( models.map((model) => - pollTelemetryApi(config, credential.token, LIST_API, { ...baseReqDTO, model }, region), + pollTelemetryApi(config, credential.token, LIST_API, { ...baseReqDTO, model }), ), ); @@ -415,11 +418,11 @@ export default defineCommand({ if (typeFlag) reqDTO.obsModelType = typeFlag; if (config.dryRun) { - emitResult({ api: OVERVIEW_API, data: { reqDTO }, region }, format); + emitResult({ api: OVERVIEW_API, data: { reqDTO } }, format); return; } - const result = await pollTelemetryApi(config, credential.token, OVERVIEW_API, reqDTO, region); + const result = await pollTelemetryApi(config, credential.token, OVERVIEW_API, reqDTO); if (!result) { process.stderr.write("Error: request timed out.\n"); process.exit(1); diff --git a/packages/cli/src/commands/workspace/list.ts b/packages/cli/src/commands/workspace/list.ts index b9f6edb..3a95362 100644 --- a/packages/cli/src/commands/workspace/list.ts +++ b/packages/cli/src/commands/workspace/list.ts @@ -93,28 +93,32 @@ export default defineCommand({ flag: "--list ", description: "Limit number of results", }, + { flag: "--console-region ", description: "Console region (global flag)" }, { - flag: "--region ", - description: "API region (default: cn-beijing)", + flag: "--console-site ", + description: "Console site: domestic, international (global flag)", + }, + { + flag: "--console-switch-agent ", + description: "Switch agent UID (global flag)", + type: "number", }, ], examples: ["bl workspace list", "bl workspace list --list 5", "bl workspace list --output json"], async run(config: Config, flags: GlobalFlags) { - const region = (flags.region as string) || "cn-beijing"; const limit = Number(flags.list) || 0; const format = detectOutputFormat(config.output); const credential = await resolveConsoleGatewayCredential(config); if (config.dryRun) { - emitResult({ api: LIST_WORKSPACES_API, data: {}, region }, format); + emitResult({ api: LIST_WORKSPACES_API, data: {} }, format); return; } const result = await callConsoleGateway(config, credential.token, { api: LIST_WORKSPACES_API, data: {}, - region, }); if (format === "json") { diff --git a/packages/cli/src/output/status-bar.ts b/packages/cli/src/output/status-bar.ts index 9797ead..54abbee 100644 --- a/packages/cli/src/output/status-bar.ts +++ b/packages/cli/src/output/status-bar.ts @@ -5,7 +5,6 @@ const reset = "\x1b[0m"; const dim = "\x1b[2m"; const bold = "\x1b[1m"; const mmBlue = "\x1b[38;2;43;82;255m"; -const mmCyan = "\x1b[38;2;6;184;212m"; const mmPink = "\x1b[38;2;236;72;153m"; function tildePath(p: string): string { @@ -20,7 +19,6 @@ export function maybeShowStatusBar( if (config.quiet || !process.stderr.isTTY) return; const filePath = config.configPath ? tildePath(config.configPath) : "~/.bailian/config.json"; - const regionSrc = config.fileRegion ? `${config.fileRegion} (file)` : "cn (default)"; const authTag = resolved ? `${resolved.source} · ${resolved.method}` : config.apiKey @@ -32,8 +30,6 @@ export function maybeShowStatusBar( `${bold}${mmBlue}BAILIAN${reset} ` + `${dim}${filePath}${reset} ` + `${dim}|${reset} ` + - `${dim}Region:${reset} ${mmCyan}${regionSrc}${reset} ` + - `${dim}|${reset} ` + `${dim}Auth:${reset} ${mmPink}${maskedKey}${reset} ${dim}${authTag}${reset}\n`, ); } diff --git a/packages/cli/tests/e2e/auth.e2e.test.ts b/packages/cli/tests/e2e/auth.e2e.test.ts index 3946e75..339383c 100644 --- a/packages/cli/tests/e2e/auth.e2e.test.ts +++ b/packages/cli/tests/e2e/auth.e2e.test.ts @@ -17,6 +17,7 @@ describe("e2e: auth", () => { const { stderr, exitCode } = await runCli(["auth", "login", "--help"]); expect(exitCode, stderr).toBe(0); expect(stderr).toMatch(/login|api-key/i); + expect(stderr).toMatch(/--console-site/); }); test("auth logout --help 正常退出", async () => { diff --git a/packages/cli/tests/e2e/config.e2e.test.ts b/packages/cli/tests/e2e/config.e2e.test.ts index f024174..5527e32 100644 --- a/packages/cli/tests/e2e/config.e2e.test.ts +++ b/packages/cli/tests/e2e/config.e2e.test.ts @@ -41,12 +41,10 @@ describe("e2e: config", () => { ]); expect(exitCode, stderr).toBe(0); const data = parseStdoutJson<{ - region?: string; config_file?: string; base_url?: string; timeout?: number; }>(stdout); - expect(data.region).toBeDefined(); expect(data.config_file).toBeDefined(); expect(data.base_url).toBeDefined(); expect(data.timeout).toBeDefined(); @@ -62,7 +60,7 @@ describe("e2e: config", () => { "--no-color", ]); expect(exitCode, stderr).toBe(0); - expect(stdout).toMatch(/region|config_file|timeout|base_url/i); + expect(stdout).toMatch(/config_file|timeout|base_url/i); }); test("config set 缺少 --key / --value 时退出为用法错误 (2)", async () => { @@ -85,20 +83,6 @@ describe("e2e: config", () => { expect(stderr).toMatch(/Invalid config key|not-a-real-key/i); }); - test("config set 非法 region", async () => { - const { stderr, exitCode } = await runCli([ - "config", - "set", - "--non-interactive", - "--key", - "region", - "--value", - "invalid-region", - ]); - expect(exitCode).toBe(2); - expect(stderr).toMatch(/Invalid region|cn, us, intl/i); - }); - test("config set 非法 output", async () => { const { stderr, exitCode } = await runCli([ "config", diff --git a/packages/cli/tests/e2e/console-flags.e2e.test.ts b/packages/cli/tests/e2e/console-flags.e2e.test.ts new file mode 100644 index 0000000..07ca49f --- /dev/null +++ b/packages/cli/tests/e2e/console-flags.e2e.test.ts @@ -0,0 +1,152 @@ +import { describe, expect, test } from "vite-plus/test"; +import { parseStdoutJson, runCli } from "./helpers.ts"; + +type ConsoleDryRunMeta = { + consoleRegion?: string; + consoleSite?: string; + consoleSwitchAgent?: number; +}; + +/** + * E2E for global console flags (`--console-region`, `--console-site`, + * `--console-switch-agent`) vs DashScope `--region`. + */ + +describe("e2e: console global flags", () => { + test("根帮助展示 --console-region / --console-site / --console-switch-agent", async () => { + const { stderr, exitCode } = await runCli(["--help"]); + expect(exitCode, stderr).toBe(0); + expect(stderr).toMatch(/--console-region/); + expect(stderr).toMatch(/--console-site/); + expect(stderr).toMatch(/--console-switch-agent/); + expect(stderr).toMatch(/--region.*cn.*us.*intl/i); + }); + + test("quota check --help 不重复命令级 region,并提示全局 flags", async () => { + const { stderr, exitCode } = await runCli(["quota", "check", "--help"]); + expect(exitCode, stderr).toBe(0); + expect(stderr).toMatch(/Global flags.*always available/i); + expect(stderr).toMatch(/--model /); + expect(stderr).toMatch(/--period /); + expect(stderr).not.toMatch(/API region \(default: cn-beijing\)/); + }); + + test("console call --help 不暴露命令级 region/site,示例使用 --console-region", async () => { + const { stderr, exitCode } = await runCli(["console", "call", "--help"]); + expect(exitCode, stderr).toBe(0); + expect(stderr).toMatch(/--api /); + expect(stderr).toMatch(/--data /); + expect(stderr).not.toMatch(/^\s*--region\s/m); + expect(stderr).not.toMatch(/^\s*--site\s/m); + expect(stderr).toMatch(/--console-region cn-beijing/); + }); + + test("auth login --help 描述 --console 与 --console-site 配合", async () => { + const { stderr, exitCode } = await runCli(["auth", "login", "--help"]); + expect(exitCode, stderr).toBe(0); + expect(stderr).toMatch(/--console-site/); + expect(stderr).toMatch(/--console.*console-site|console-site.*domestic|international/i); + }); + + test("console call --dry-run 默认 consoleRegion 为 cn-beijing", async () => { + const { stdout, stderr, exitCode } = await runCli([ + "console", + "call", + "--api", + "some.api.name", + "--data", + "{}", + "--dry-run", + "--non-interactive", + "--output", + "json", + ]); + expect(exitCode, stderr).toBe(0); + const data = parseStdoutJson(stdout); + expect(data.consoleRegion).toBe("cn-beijing"); + expect(data.consoleSite).toBe("domestic"); + }); + + test("console call --dry-run --console-region / --console-site / --console-switch-agent 透传", async () => { + const { stdout, stderr, exitCode } = await runCli([ + "console", + "call", + "--api", + "some.api.name", + "--data", + "{}", + "--dry-run", + "--non-interactive", + "--output", + "json", + "--console-region", + "ap-southeast-1", + "--console-site", + "international", + "--console-switch-agent", + "12345", + ]); + expect(exitCode, stderr).toBe(0); + const data = parseStdoutJson(stdout); + expect(data.consoleRegion).toBe("ap-southeast-1"); + expect(data.consoleSite).toBe("international"); + expect(data.consoleSwitchAgent).toBe(12345); + }); + + test("console call --dry-run --region cn-beijing 不改变 consoleRegion", async () => { + const { stdout, stderr, exitCode } = await runCli([ + "console", + "call", + "--api", + "some.api.name", + "--data", + "{}", + "--dry-run", + "--non-interactive", + "--output", + "json", + "--region", + "cn-beijing", + "--console-region", + "ap-southeast-1", + ]); + expect(exitCode, stderr).toBe(0); + const data = parseStdoutJson(stdout); + expect(data.consoleRegion).toBe("ap-southeast-1"); + }); + + test("mcp list --dry-run --console-region 透传", async () => { + const { stdout, stderr, exitCode } = await runCli([ + "mcp", + "list", + "--dry-run", + "--non-interactive", + "--output", + "json", + "--console-region", + "cn-hangzhou", + ]); + expect(exitCode, stderr).toBe(0); + const data = parseStdoutJson(stdout); + expect(data.consoleRegion).toBe("cn-hangzhou"); + }); + + test("quota check --dry-run --console-region 透传", async () => { + const { stdout, stderr, exitCode } = await runCli([ + "quota", + "check", + "--dry-run", + "--non-interactive", + "--output", + "json", + "--console-region", + "cn-hangzhou", + "--console-site", + "international", + ]); + expect(exitCode, stderr).toBe(0); + const data = parseStdoutJson(stdout); + expect(data.consoleRegion).toBe("cn-hangzhou"); + expect(data.consoleSite).toBe("international"); + }); +}); diff --git a/packages/cli/tests/e2e/mcp.e2e.test.ts b/packages/cli/tests/e2e/mcp.e2e.test.ts index bc5ef52..ee56cf4 100644 --- a/packages/cli/tests/e2e/mcp.e2e.test.ts +++ b/packages/cli/tests/e2e/mcp.e2e.test.ts @@ -79,7 +79,6 @@ describe("e2e: mcp", () => { }; }>(stdout); expect(data.api).toBe("zeldaEasy.broadscope-bailian.mcp-server.PageList"); - expect(data.region).toBe("cn-beijing"); expect(data.data?.reqDTO?.activated).toBe(1); expect(data.data?.reqDTO?.displayTools).toBe(false); expect(data.data?.reqDTO?.type).toBe("OFFICIAL"); @@ -88,7 +87,7 @@ describe("e2e: mcp", () => { expect(data.data?.reqDTO?.pageSize).toBe(5); }); - test("mcp list --dry-run 自定义 --region 透传", async () => { + test("mcp list --dry-run 自定义 --console-region 透传", async () => { const { stdout, stderr, exitCode } = await runCli([ "mcp", "list", @@ -96,12 +95,12 @@ describe("e2e: mcp", () => { "--non-interactive", "--output", "json", - "--region", + "--console-region", "cn-hangzhou", ]); expect(exitCode, stderr).toBe(0); - const data = parseStdoutJson<{ region?: string }>(stdout); - expect(data.region).toBe("cn-hangzhou"); + const data = parseStdoutJson<{ consoleRegion?: string }>(stdout); + expect(data.consoleRegion).toBe("cn-hangzhou"); }); test("mcp tools --dry-run 输出 /api/v1/mcps//mcp 形态 URL", async () => { diff --git a/packages/cli/tests/e2e/quota.e2e.test.ts b/packages/cli/tests/e2e/quota.e2e.test.ts index 19e537d..4e54fbb 100644 --- a/packages/cli/tests/e2e/quota.e2e.test.ts +++ b/packages/cli/tests/e2e/quota.e2e.test.ts @@ -228,11 +228,28 @@ describe.skipIf(!isConsoleE2EReady())("e2e: quota(Console)", () => { "json", ]); expect(exitCode, stderr).toBe(0); - const data = parseStdoutJson<{ apis?: string[] }>(stdout); + const data = parseStdoutJson<{ apis?: string[]; consoleRegion?: string }>(stdout); expect(data.apis).toContain( "zeldaHttp.dashscopeModel./zelda/api/v1/modelCenter/listFoundationModels", ); expect(data.apis).toContain("zeldaEasy.bailian-telemetry.monitor.getMonitorData"); + expect(data.consoleRegion).toBe("cn-beijing"); + }); + + test("quota check --dry-run --console-region 透传", async () => { + const { stdout, stderr, exitCode } = await runCli([ + "quota", + "check", + "--dry-run", + "--non-interactive", + "--output", + "json", + "--console-region", + "cn-hangzhou", + ]); + expect(exitCode, stderr).toBe(0); + const data = parseStdoutJson<{ consoleRegion?: string }>(stdout); + expect(data.consoleRegion).toBe("cn-hangzhou"); }); test("quota check 文本输出包含双行表头", async () => { diff --git a/packages/cli/tests/e2e/usage-free.e2e.test.ts b/packages/cli/tests/e2e/usage-free.e2e.test.ts index 064f027..589239b 100644 --- a/packages/cli/tests/e2e/usage-free.e2e.test.ts +++ b/packages/cli/tests/e2e/usage-free.e2e.test.ts @@ -264,13 +264,13 @@ describe.skipIf(!isConsoleE2EReady())("e2e: usage free(Console)", () => { expect(hasAutoStop).toBe(true); }); - test("usage free --model --region cn-beijing 指定区域查询", async () => { + test("usage free --model --console-region cn-beijing 指定区域查询", async () => { const { stdout, stderr, exitCode } = await runCli([ "usage", "free", "--model", "qwen3-max", - "--region", + "--console-region", "cn-beijing", "--output", "json", diff --git a/packages/core/src/config/loader.ts b/packages/core/src/config/loader.ts index 30ce611..12d4d3b 100644 --- a/packages/core/src/config/loader.ts +++ b/packages/core/src/config/loader.ts @@ -42,8 +42,8 @@ export function loadConfig(flags: GlobalFlags): Config { const baseUrl = flags.baseUrl || - process.env.DASHSCOPE_BASE_URL || file.base_url || + process.env.DASHSCOPE_BASE_URL || REGIONS[region] || REGIONS.cn; @@ -84,10 +84,10 @@ export function loadConfig(flags: GlobalFlags): Config { accessKeySecret: process.env.ALIBABA_CLOUD_ACCESS_KEY_SECRET || file.access_key_secret || undefined, workspaceId: process.env.BAILIAN_WORKSPACE_ID || file.workspace_id || undefined, - consoleGatewayUrl: - process.env.BAILIAN_CONSOLE_GATEWAY_URL || - file.console_gateway_url || - "https://bailian-cs.console.aliyun.com", + consoleSite: (flags.consoleSite as Config["consoleSite"]) || file.console_site || undefined, + consoleRegion: (flags.consoleRegion as string) || file.console_region || undefined, + consoleSwitchAgent: + (flags.consoleSwitchAgent as number) || file.console_switch_agent || undefined, verbose: flags.verbose || process.env.DASHSCOPE_VERBOSE === "1", quiet: flags.quiet || false, noColor: flags.noColor || process.env.NO_COLOR !== undefined || !process.stdout.isTTY, diff --git a/packages/core/src/config/schema.ts b/packages/core/src/config/schema.ts index 7fad89f..76275a6 100644 --- a/packages/core/src/config/schema.ts +++ b/packages/core/src/config/schema.ts @@ -31,16 +31,19 @@ export interface ConfigFile { access_key_id?: string; access_key_secret?: string; workspace_id?: string; - console_gateway_url?: string; + console_site?: "domestic" | "international"; + console_region?: string; + console_switch_agent?: number; telemetry?: boolean; } const VALID_REGIONS = new Set(["cn", "us", "intl"]); const VALID_OUTPUTS = new Set(["text", "json"]); +const VALID_CONSOLE_SITES = new Set(["domestic", "international"]); /** - * A syntactically valid absolute http(s) URL. Used to validate `base_url` and - * `console_gateway_url` from the config file: the credential-bearing client + * A syntactically valid absolute http(s) URL. Used to validate `base_url` + * from the config file: the credential-bearing client * sends the Bearer token to these origins, so a bare `startsWith("http")` check * (which also accepts e.g. "httpfoo://…") is too loose. */ @@ -87,8 +90,12 @@ export function parseConfigFile(raw: unknown): ConfigFile { out.access_key_secret = obj.access_key_secret; if (typeof obj.workspace_id === "string" && obj.workspace_id.length > 0) out.workspace_id = obj.workspace_id; - if (typeof obj.console_gateway_url === "string" && isHttpUrl(obj.console_gateway_url)) - out.console_gateway_url = obj.console_gateway_url; + if (typeof obj.console_site === "string" && VALID_CONSOLE_SITES.has(obj.console_site)) + out.console_site = obj.console_site as ConfigFile["console_site"]; + if (typeof obj.console_region === "string" && obj.console_region.length > 0) + out.console_region = obj.console_region; + if (typeof obj.console_switch_agent === "number" && obj.console_switch_agent > 0) + out.console_switch_agent = obj.console_switch_agent; if (typeof obj.telemetry === "boolean") out.telemetry = obj.telemetry; return out; @@ -118,7 +125,9 @@ export interface Config { accessKeyId?: string; accessKeySecret?: string; workspaceId?: string; - consoleGatewayUrl: string; + consoleSite?: "domestic" | "international"; + consoleRegion?: string; + consoleSwitchAgent?: number; verbose: boolean; quiet: boolean; noColor: boolean; diff --git a/packages/core/src/console/gateway.ts b/packages/core/src/console/gateway.ts index a698d12..3a636db 100644 --- a/packages/core/src/console/gateway.ts +++ b/packages/core/src/console/gateway.ts @@ -2,18 +2,70 @@ import type { Config } from "../config/schema.ts"; import { BailianError } from "../errors/base.ts"; import { ExitCode } from "../errors/codes.ts"; -const GATEWAY_ACTION = "BroadScopeAspnGateway"; const GATEWAY_PRODUCT = "sfm_bailian"; +export type ConsoleSite = "domestic" | "international"; + +interface ConsoleGatewayInfo { + csGateway: string; + action: string; +} + +const REGION_GATEWAYS: Record> = { + "cn-beijing": { + domestic: { csGateway: "bailian-cs.console.aliyun.com", action: "BroadScopeAspnGateway" }, + international: { + csGateway: "bailian-cs.console.alibabacloud.com", + action: "BroadScopeAspnGateway", + }, + }, + "ap-southeast-1": { + domestic: { + csGateway: "modelstudio-cs.console.aliyun.com", + action: "IntlBroadScopeAspnGateway", + }, + international: { + csGateway: "bailian-singapore-cs.alibabacloud.com", + action: "IntlBroadScopeAspnGateway", + }, + }, +}; + +function resolveGateway(region: string, site: ConsoleSite): ConsoleGatewayInfo { + return REGION_GATEWAYS[region]?.[site] ?? REGION_GATEWAYS["cn-beijing"]![site]; +} + +/** Resolved console gateway settings (same defaults as {@link callConsoleGateway}). */ +export function effectiveConsoleGatewayConfig(config: Config): { + consoleRegion: string; + consoleSite: ConsoleSite; + consoleSwitchAgent?: number; +} { + const consoleRegion = config.consoleRegion ?? "cn-beijing"; + const consoleSite = config.consoleSite ?? "domestic"; + const consoleSwitchAgent = config.consoleSwitchAgent; + return consoleSwitchAgent != null + ? { consoleRegion, consoleSite, consoleSwitchAgent } + : { consoleRegion, consoleSite }; +} + export interface ConsoleGatewayRequest { /** Console API name, e.g. zeldaEasy.broadscope-bailian.freeTrial.queryFreeTierQuota */ api: string; data: Record; - /** Console region (default: cn-beijing), distinct from DashScope `config.region`. */ + /** Console region (e.g. cn-beijing, ap-southeast-1). Falls back to config.consoleRegion, then "cn-beijing". */ region?: string; + /** Console site. Falls back to config.consoleSite, then "domestic". */ + site?: ConsoleSite; + /** Switch-agent UID for delegated access. Falls back to config.consoleSwitchAgent. */ + switchAgent?: number; } -function buildGatewayParams(api: string, data: Record): string { +function buildGatewayParams( + api: string, + data: Record, + switchAgent?: number, +): string { return JSON.stringify({ Api: api, V: "1.0", @@ -24,6 +76,7 @@ function buildGatewayParams(api: string, data: Record): string console: "ONE_CONSOLE", productCode: "p_efm", consoleSite: "BAILIAN_ALIYUN", + ...(switchAgent != null ? { switchAgent } : {}), ...(typeof data.cornerstoneParam === "object" && data.cornerstoneParam !== null ? (data.cornerstoneParam as Record) : {}), @@ -37,17 +90,28 @@ function buildGatewayParams(api: string, data: Record): string * `token` is the console `access_token` (from `bl auth login --console`); when * omitted the request is sent without an Authorization header, which works for * public console APIs that don't require a login session. + * + * Gateway URL and action are resolved from `region + site` via {@link REGION_GATEWAYS}. + * Each parameter falls back to the corresponding config value, then to a hardcoded default. */ export async function callConsoleGateway( config: Config, token: string | undefined, - { api, data, region = "cn-beijing" }: ConsoleGatewayRequest, + { api, data }: ConsoleGatewayRequest, ): Promise { - const params = buildGatewayParams(api, data); - const body = new URLSearchParams({ params, region }); - const timeoutMs = config.timeout * 1000; + const { + consoleRegion: effectiveRegion, + consoleSite: effectiveSite, + consoleSwitchAgent: effectiveSwitchAgent, + } = effectiveConsoleGatewayConfig(config); + + const resolved = resolveGateway(effectiveRegion, effectiveSite); + const gatewayBase = `https://${resolved.csGateway}`; + const action = resolved.action; - const gatewayBase = config.consoleGatewayUrl; + const params = buildGatewayParams(api, data, effectiveSwitchAgent); + const body = new URLSearchParams({ params, region: effectiveRegion }); + const timeoutMs = config.timeout * 1000; const headers: Record = { Accept: "*/*", @@ -56,7 +120,7 @@ export async function callConsoleGateway( if (token) headers.Authorization = `Bearer ${token}`; const res = await fetch( - `${gatewayBase}/cli/api.json?action=${GATEWAY_ACTION}&product=${GATEWAY_PRODUCT}&api=${encodeURIComponent(api)}`, + `${gatewayBase}/cli/api.json?action=${action}&product=${GATEWAY_PRODUCT}&api=${encodeURIComponent(api)}`, { method: "POST", headers, diff --git a/packages/core/src/console/index.ts b/packages/core/src/console/index.ts index e08e08a..948e878 100644 --- a/packages/core/src/console/index.ts +++ b/packages/core/src/console/index.ts @@ -1,4 +1,4 @@ -export type { ConsoleGatewayRequest } from "./gateway.ts"; -export { callConsoleGateway } from "./gateway.ts"; +export type { ConsoleGatewayRequest, ConsoleSite } from "./gateway.ts"; +export { callConsoleGateway, effectiveConsoleGatewayConfig } from "./gateway.ts"; export type { ModelListParams, ModelListResult } from "./models.ts"; export { fetchModelList } from "./models.ts"; diff --git a/packages/core/src/console/models.ts b/packages/core/src/console/models.ts index 0711790..8366a2f 100644 --- a/packages/core/src/console/models.ts +++ b/packages/core/src/console/models.ts @@ -22,14 +22,7 @@ export async function fetchModelList( token: string, params: ModelListParams = {}, ): Promise { - const { - pageNo = 1, - pageSize = 50, - name = "", - providers = [], - capabilities = [], - region = "cn-beijing", - } = params; + const { pageNo = 1, pageSize = 50, name = "", providers = [], capabilities = [] } = params; const result = (await callConsoleGateway(config, token, { api: MODEL_LIST_API, @@ -46,7 +39,6 @@ export async function fetchModelList( contextWindows: [], }, }, - region, })) as any; const responseData = result?.data?.DataV2?.data ?? result?.data ?? {}; diff --git a/packages/core/src/types/command.ts b/packages/core/src/types/command.ts index 02bbcf5..cff3bc1 100644 --- a/packages/core/src/types/command.ts +++ b/packages/core/src/types/command.ts @@ -50,6 +50,16 @@ export const GLOBAL_OPTIONS: OptionDef[] = [ { flag: "--dry-run", description: "Dry run mode" }, { flag: "--non-interactive", description: "Disable interactive prompts" }, { flag: "--concurrent ", description: "Run N parallel requests (default: 1)", type: "number" }, + { + flag: "--console-region ", + description: "Console gateway region (e.g. cn-beijing, ap-southeast-1)", + }, + { flag: "--console-site ", description: "Console site: domestic, international" }, + { + flag: "--console-switch-agent ", + description: "Switch agent UID for delegated access", + type: "number", + }, { flag: "--help", description: "Show help" }, { flag: "--version", description: "Print version" }, ]; diff --git a/packages/core/src/types/flags.ts b/packages/core/src/types/flags.ts index 4f29f85..41e1a5a 100644 --- a/packages/core/src/types/flags.ts +++ b/packages/core/src/types/flags.ts @@ -11,5 +11,8 @@ export interface GlobalFlags { help: boolean; nonInteractive: boolean; async: boolean; + consoleRegion?: string; + consoleSite?: string; + consoleSwitchAgent?: number; [key: string]: unknown; } diff --git a/packages/core/tests/index.test.ts b/packages/core/tests/index.test.ts index 5514413..fd433e1 100644 --- a/packages/core/tests/index.test.ts +++ b/packages/core/tests/index.test.ts @@ -22,7 +22,6 @@ function testConfig(overrides: Partial = {}): Config { nonInteractive: true, async: false, telemetry: true, - consoleGatewayUrl: "https://bailian-cs.console.aliyun.com", ...overrides, }; } @@ -200,7 +199,7 @@ test("parseBooleanValue accepts only true and false strings (case-insensitive)", expect(() => parseBooleanValue("maybe")).toThrow(BailianError); }); -test("parseConfigFile accepts only well-formed http(s) base_url / console_gateway_url", () => { +test("parseConfigFile accepts only well-formed http(s) base_url", () => { expect(parseConfigFile({ base_url: "https://dashscope.aliyuncs.com" }).base_url).toBe( "https://dashscope.aliyuncs.com", ); @@ -210,5 +209,4 @@ test("parseConfigFile accepts only well-formed http(s) base_url / console_gatewa // Previously accepted because the value merely "starts with http". expect(parseConfigFile({ base_url: "httpfoo://evil" }).base_url).toBeUndefined(); expect(parseConfigFile({ base_url: "not a url" }).base_url).toBeUndefined(); - expect(parseConfigFile({ console_gateway_url: "ftp://x" }).console_gateway_url).toBeUndefined(); }); diff --git a/skills/bailian-cli/reference/app.md b/skills/bailian-cli/reference/app.md index e486673..7a1bc95 100644 --- a/skills/bailian-cli/reference/app.md +++ b/skills/bailian-cli/reference/app.md @@ -73,12 +73,14 @@ bl app call --app-id abc123 --prompt "开始" --biz-params '{"key":"value"}' #### Options -| Flag | Type | Required | Description | -| ------------------- | ------ | -------- | ----------------------------------- | -| `--name ` | string | no | Filter by app name (keyword search) | -| `--page ` | number | no | Page number (default: 1) | -| `--page-size ` | number | no | Results per page (default: 30) | -| `--region ` | string | no | API region (default: cn-beijing) | +| Flag | Type | Required | Description | +| ------------------------------ | ------ | -------- | --------------------------------------------------- | +| `--name ` | string | no | Filter by app name (keyword search) | +| `--page ` | number | no | Page number (default: 1) | +| `--page-size ` | number | no | Results per page (default: 30) | +| `--console-region ` | string | no | Console region (global flag) | +| `--console-site ` | string | no | Console site: domestic, international (global flag) | +| `--console-switch-agent ` | number | no | Switch agent UID (global flag) | #### Examples diff --git a/skills/bailian-cli/reference/auth.md b/skills/bailian-cli/reference/auth.md index 3790ae5..f0e5f4f 100644 --- a/skills/bailian-cli/reference/auth.md +++ b/skills/bailian-cli/reference/auth.md @@ -25,10 +25,11 @@ Index: [index.md](index.md) #### Options -| Flag | Type | Required | Description | -| ----------------- | ------- | -------- | ------------------------------------------------------------------------ | -| `--api-key ` | string | no | DashScope API key to store | -| `--console` | boolean | no | Sign in via browser; opens the console login URL in your default browser | +| Flag | Type | Required | Description | +| ------------------ | ------- | -------- | ------------------------------------------------------------------------------------- | +| `--api-key ` | string | no | DashScope API key to store | +| `--base-url ` | string | no | DashScope API base URL (used with --api-key for validation) | +| `--console` | boolean | no | Sign in via browser; use --console-site to choose domestic (default) or international | #### Examples @@ -83,7 +84,11 @@ bl auth logout --yes #### Options -_No command-specific options._ +| Flag | Type | Required | Description | +| ------------------------------ | ------ | -------- | --------------------------------------------------- | +| `--console-region ` | string | no | Console region (global flag) | +| `--console-site ` | string | no | Console site: domestic, international (global flag) | +| `--console-switch-agent ` | number | no | Switch agent UID (global flag) | #### Examples diff --git a/skills/bailian-cli/reference/console.md b/skills/bailian-cli/reference/console.md index 50e5ea1..e6b6b57 100644 --- a/skills/bailian-cli/reference/console.md +++ b/skills/bailian-cli/reference/console.md @@ -23,11 +23,13 @@ Index: [index.md](index.md) #### Options -| Flag | Type | Required | Description | -| ------------------- | ------ | -------- | ------------------------------------------------------------------------ | -| `--api ` | string | yes | API name (e.g. zeldaEasy.broadscope-bailian.memory-library.getLibraries) | -| `--data ` | string | yes | Request data as JSON string | -| `--region ` | string | no | API region (default: cn-beijing) | +| Flag | Type | Required | Description | +| ------------------------------ | ------ | -------- | ------------------------------------------------------------------------ | +| `--api ` | string | yes | API name (e.g. zeldaEasy.broadscope-bailian.memory-library.getLibraries) | +| `--data ` | string | yes | Request data as JSON string | +| `--console-region ` | string | no | Console region (global flag) | +| `--console-site ` | string | no | Console site: domestic, international (global flag) | +| `--console-switch-agent ` | number | no | Switch agent UID (global flag) | #### Examples @@ -36,5 +38,5 @@ bl console call --api zeldaEasy.broadscope-bailian.freeTrial.queryFreeTierQuota ``` ```bash -bl console call --api some.api.name --data '{"key":"value"}' --region cn-beijing +bl console call --api some.api.name --data '{"key":"value"}' --console-region cn-beijing ``` diff --git a/skills/bailian-cli/reference/index.md b/skills/bailian-cli/reference/index.md index 0da2213..5a19012 100644 --- a/skills/bailian-cli/reference/index.md +++ b/skills/bailian-cli/reference/index.md @@ -87,21 +87,24 @@ Use this index for the full quick index and global flags. Available on every command (in addition to command-specific options): -| Flag | Type | Required | Description | -| --------------------- | ------- | -------- | ------------------------------------ | -| `--api-key ` | string | no | API key | -| `--region ` | string | no | API region: cn (default), us, intl | -| `--base-url ` | string | no | API base URL | -| `--output ` | string | no | Output format: text, json | -| `--timeout ` | number | no | Request timeout | -| `--quiet` | boolean | no | Suppress non-essential output | -| `--verbose` | boolean | no | Print HTTP request/response details | -| `--no-color` | boolean | no | Disable ANSI colors | -| `--dry-run` | boolean | no | Dry run mode | -| `--non-interactive` | boolean | no | Disable interactive prompts | -| `--concurrent ` | number | no | Run N parallel requests (default: 1) | -| `--help` | boolean | no | Show help | -| `--version` | boolean | no | Print version | +| Flag | Type | Required | Description | +| ------------------------------ | ------- | -------- | -------------------------------------------------------- | +| `--api-key ` | string | no | API key | +| `--region ` | string | no | API region: cn (default), us, intl | +| `--base-url ` | string | no | API base URL | +| `--output ` | string | no | Output format: text, json | +| `--timeout ` | number | no | Request timeout | +| `--quiet` | boolean | no | Suppress non-essential output | +| `--verbose` | boolean | no | Print HTTP request/response details | +| `--no-color` | boolean | no | Disable ANSI colors | +| `--dry-run` | boolean | no | Dry run mode | +| `--non-interactive` | boolean | no | Disable interactive prompts | +| `--concurrent ` | number | no | Run N parallel requests (default: 1) | +| `--console-region ` | string | no | Console gateway region (e.g. cn-beijing, ap-southeast-1) | +| `--console-site ` | string | no | Console site: domestic, international | +| `--console-switch-agent ` | number | no | Switch agent UID for delegated access | +| `--help` | boolean | no | Show help | +| `--version` | boolean | no | Print version | ## Notes diff --git a/skills/bailian-cli/reference/mcp.md b/skills/bailian-cli/reference/mcp.md index 9c71795..bd22232 100644 --- a/skills/bailian-cli/reference/mcp.md +++ b/skills/bailian-cli/reference/mcp.md @@ -57,13 +57,15 @@ bl mcp call market-cmapi00073529.SmartFundSelection --arg riskLevel=R3 --arg min #### Options -| Flag | Type | Required | Description | -| ------------------- | ------ | -------- | ---------------------------------------------------- | -| `--name ` | string | no | Filter by server name (substring match) | -| `--type ` | string | no | Server type: OFFICIAL \| PRIVATE (default: OFFICIAL) | -| `--page ` | number | no | Page number (default: 1) | -| `--page-size ` | number | no | Results per page (default: 30) | -| `--region ` | string | no | API region (default: cn-beijing) | +| Flag | Type | Required | Description | +| ------------------------------ | ------ | -------- | ---------------------------------------------------- | +| `--name ` | string | no | Filter by server name (substring match) | +| `--type ` | string | no | Server type: OFFICIAL \| PRIVATE (default: OFFICIAL) | +| `--page ` | number | no | Page number (default: 1) | +| `--page-size ` | number | no | Results per page (default: 30) | +| `--console-region ` | string | no | Console region (global flag) | +| `--console-site ` | string | no | Console site: domestic, international (global flag) | +| `--console-switch-agent ` | number | no | Switch agent UID (global flag) | #### Examples diff --git a/skills/bailian-cli/reference/quota.md b/skills/bailian-cli/reference/quota.md index 86aa355..9f7a68c 100644 --- a/skills/bailian-cli/reference/quota.md +++ b/skills/bailian-cli/reference/quota.md @@ -26,11 +26,13 @@ Index: [index.md](index.md) #### Options -| Flag | Type | Required | Description | -| -------------------- | ------ | -------- | ----------------------------------------------- | -| `--model ` | string | no | Model name(s), comma-separated | -| `--period ` | string | no | Query usage for the last N minutes (default: 2) | -| `--region ` | string | no | API region (default: cn-beijing) | +| Flag | Type | Required | Description | +| ------------------------------ | ------ | -------- | --------------------------------------------------- | +| `--model ` | string | no | Model name(s), comma-separated | +| `--period ` | string | no | Query usage for the last N minutes (default: 2) | +| `--console-region ` | string | no | Console region (global flag) | +| `--console-site ` | string | no | Console site: domestic, international (global flag) | +| `--console-switch-agent ` | number | no | Switch agent UID (global flag) | #### Examples @@ -64,12 +66,14 @@ bl quota check --output json #### Options -| Flag | Type | Required | Description | -| ------------------- | ------ | -------- | -------------------------------- | -| `--page ` | string | no | Page number (default: 1) | -| `--page-size ` | string | no | Page size (default: 10) | -| `--model ` | string | no | Filter by model name | -| `--region ` | string | no | API region (default: cn-beijing) | +| Flag | Type | Required | Description | +| ------------------------------ | ------ | -------- | --------------------------------------------------- | +| `--page ` | string | no | Page number (default: 1) | +| `--page-size ` | string | no | Page size (default: 10) | +| `--model ` | string | no | Filter by model name | +| `--console-region ` | string | no | Console region (global flag) | +| `--console-site ` | string | no | Console site: domestic, international (global flag) | +| `--console-switch-agent ` | number | no | Switch agent UID (global flag) | #### Examples @@ -103,11 +107,13 @@ bl quota history --output json #### Options -| Flag | Type | Required | Description | -| ------------------- | ------- | -------- | ------------------------------------------- | -| `--model ` | string | no | Model name(s), comma-separated | -| `--all` | boolean | no | Show all models, not just self-service ones | -| `--region ` | string | no | API region (default: cn-beijing) | +| Flag | Type | Required | Description | +| ------------------------------ | ------- | -------- | --------------------------------------------------- | +| `--model ` | string | no | Model name(s), comma-separated | +| `--all` | boolean | no | Show all models, not just self-service ones | +| `--console-region ` | string | no | Console region (global flag) | +| `--console-site ` | string | no | Console site: domestic, international (global flag) | +| `--console-switch-agent ` | number | no | Switch agent UID (global flag) | #### Examples @@ -141,12 +147,14 @@ bl quota list --output json #### Options -| Flag | Type | Required | Description | -| ------------------- | ------- | -------- | -------------------------------- | -| `--model ` | string | yes | Model name (required) | -| `--tpm ` | string | yes | Target TPM value (required) | -| `--yes` | boolean | no | Skip downgrade confirmation | -| `--region ` | string | no | API region (default: cn-beijing) | +| Flag | Type | Required | Description | +| ------------------------------ | ------- | -------- | --------------------------------------------------- | +| `--model ` | string | yes | Model name (required) | +| `--tpm ` | string | yes | Target TPM value (required) | +| `--yes` | boolean | no | Skip downgrade confirmation | +| `--console-region ` | string | no | Console region (global flag) | +| `--console-site ` | string | no | Console site: domestic, international (global flag) | +| `--console-switch-agent ` | number | no | Switch agent UID (global flag) | #### Examples diff --git a/skills/bailian-cli/reference/usage.md b/skills/bailian-cli/reference/usage.md index 52ccd11..66f6256 100644 --- a/skills/bailian-cli/reference/usage.md +++ b/skills/bailian-cli/reference/usage.md @@ -25,12 +25,14 @@ Index: [index.md](index.md) #### Options -| Flag | Type | Required | Description | -| ------------------- | ------ | -------- | ------------------------------------------------------------------------- | -| `--model ` | string | no | Model name(s) to query, comma-separated for multiple; omit for all models | -| `--expiring ` | string | no | Only show quotas expiring within N days | -| `--sort ` | string | no | Sort by: remaining (ascending), expires (ascending) | -| `--region ` | string | no | API region (default: cn-beijing) | +| Flag | Type | Required | Description | +| ------------------------------ | ------ | -------- | ------------------------------------------------------------------------- | +| `--model ` | string | no | Model name(s) to query, comma-separated for multiple; omit for all models | +| `--expiring ` | string | no | Only show quotas expiring within N days | +| `--sort ` | string | no | Sort by: remaining (ascending), expires (ascending) | +| `--console-region ` | string | no | Console region (global flag) | +| `--console-site ` | string | no | Console site: domestic, international (global flag) | +| `--console-switch-agent ` | number | no | Switch agent UID (global flag) | #### Examples @@ -59,7 +61,7 @@ bl usage free --model qwen-turbo --output json ``` ```bash -bl usage free --model qwen3-max --region cn-beijing +bl usage free --model qwen3-max --console-region cn-beijing ``` ### `bl usage freetier` @@ -72,13 +74,15 @@ bl usage free --model qwen3-max --region cn-beijing #### Options -| Flag | Type | Required | Description | -| ------------------- | ------- | -------- | ------------------------------------------- | -| `--model ` | string | no | Model name(s), comma-separated for multiple | -| `--all` | boolean | no | Apply to all free-tier models | -| `--on` | boolean | no | Enable auto-stop (default behavior) | -| `--off` | boolean | no | Disable auto-stop | -| `--region ` | string | no | API region (default: cn-beijing) | +| Flag | Type | Required | Description | +| ------------------------------ | ------- | -------- | --------------------------------------------------- | +| `--model ` | string | no | Model name(s), comma-separated for multiple | +| `--all` | boolean | no | Apply to all free-tier models | +| `--on` | boolean | no | Enable auto-stop (default behavior) | +| `--off` | boolean | no | Disable auto-stop | +| `--console-region ` | string | no | Console region (global flag) | +| `--console-site ` | string | no | Console site: domestic, international (global flag) | +| `--console-switch-agent ` | number | no | Switch agent UID (global flag) | #### Examples @@ -116,13 +120,15 @@ bl usage freetier --off --all #### Options -| Flag | Type | Required | Description | -| --------------------- | ------ | -------- | ------------------------------------------------------ | -| `--model ` | string | no | Model name(s), comma-separated; omit for overview | -| `--days ` | string | no | Number of days (default: 7) | -| `--type ` | string | no | Model type: Text, Vision, Multimodal, Audio, Embedding | -| `--workspace-id ` | string | no | Workspace ID (env: BAILIAN_WORKSPACE_ID) | -| `--region ` | string | no | API region (default: cn-beijing) | +| Flag | Type | Required | Description | +| ------------------------------ | ------ | -------- | ------------------------------------------------------ | +| `--model ` | string | no | Model name(s), comma-separated; omit for overview | +| `--days ` | string | no | Number of days (default: 7) | +| `--type ` | string | no | Model type: Text, Vision, Multimodal, Audio, Embedding | +| `--workspace-id ` | string | no | Workspace ID (env: BAILIAN_WORKSPACE_ID) | +| `--console-region ` | string | no | Console region (global flag) | +| `--console-site ` | string | no | Console site: domestic, international (global flag) | +| `--console-switch-agent ` | number | no | Switch agent UID (global flag) | #### Examples diff --git a/skills/bailian-cli/reference/workspace.md b/skills/bailian-cli/reference/workspace.md index 2428721..82404a0 100644 --- a/skills/bailian-cli/reference/workspace.md +++ b/skills/bailian-cli/reference/workspace.md @@ -23,10 +23,12 @@ Index: [index.md](index.md) #### Options -| Flag | Type | Required | Description | -| ------------------- | ------ | -------- | -------------------------------- | -| `--list ` | string | no | Limit number of results | -| `--region ` | string | no | API region (default: cn-beijing) | +| Flag | Type | Required | Description | +| ------------------------------ | ------ | -------- | --------------------------------------------------- | +| `--list ` | string | no | Limit number of results | +| `--console-region ` | string | no | Console region (global flag) | +| `--console-site ` | string | no | Console site: domestic, international (global flag) | +| `--console-switch-agent ` | number | no | Switch agent UID (global flag) | #### Examples