diff --git a/AGENTS.md b/AGENTS.md index 51afe94..98c6dd8 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" }, +{ flag: "--console-site ", description: "Console site: domestic, international" }, +{ flag: "--console-switch-agent ", description: "Switch agent UID", type: "number" }, +``` + +这些 flag 已在 `GLOBAL_OPTIONS`(`packages/core/src/types/command.ts`)中注册,由 `loadConfig` 写入 `config.consoleRegion` / `config.consoleSite` / `config.consoleSwitchAgent`,`callConsoleGateway` 自动读取——命令无需手动提取或传递。 + ## 完成改动后的快速验证 ```sh diff --git a/INSTALL.md b/INSTALL.md index 8d62f19..75ffab2 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -102,7 +102,7 @@ bl auth status --output json bl text chat --message "ping" --non-interactive --output json ``` -若失败:根据 stderr / JSON 中的 `hint` 或 `message` 排查(网络、Key 无效、region 等)。全局 region:`--region cn|us|intl`,默认 `cn`。 +若失败:根据 stderr / JSON 中的 `hint` 或 `message` 排查(网络、Key 无效、`base_url` 等)。DashScope 端点:使用 `--base-url` / `bl config set --key base_url` / `DASHSCOPE_BASE_URL`,默认中国大陆 `https://dashscope.aliyuncs.com`。 --- diff --git a/README.md b/README.md index c1a6177..5efd3e0 100644 --- a/README.md +++ b/README.md @@ -172,7 +172,7 @@ export BAILIAN_WORKSPACE_ID=ws-... bl config show # Set defaults -bl config set --key region --value us +bl config set --key base_url --value https://dashscope-us.aliyuncs.com bl config set --key default_text_model --value qwen-turbo bl config set --key timeout --value 600 diff --git a/README.zh.md b/README.zh.md index 4d9a101..f92a9ae 100644 --- a/README.zh.md +++ b/README.zh.md @@ -167,7 +167,7 @@ export BAILIAN_WORKSPACE_ID=ws-... bl config show # 设置默认值 -bl config set --key region --value us +bl config set --key base_url --value https://dashscope-us.aliyuncs.com bl config set --key default_text_model --value qwen-turbo bl config set --key timeout --value 600 diff --git a/packages/cli/README.md b/packages/cli/README.md index c1a6177..5efd3e0 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -172,7 +172,7 @@ export BAILIAN_WORKSPACE_ID=ws-... bl config show # Set defaults -bl config set --key region --value us +bl config set --key base_url --value https://dashscope-us.aliyuncs.com bl config set --key default_text_model --value qwen-turbo bl config set --key timeout --value 600 diff --git a/packages/cli/README.zh.md b/packages/cli/README.zh.md index 4d9a101..f92a9ae 100644 --- a/packages/cli/README.zh.md +++ b/packages/cli/README.zh.md @@ -167,7 +167,7 @@ export BAILIAN_WORKSPACE_ID=ws-... bl config show # 设置默认值 -bl config set --key region --value us +bl config set --key base_url --value https://dashscope-us.aliyuncs.com bl config set --key default_text_model --value qwen-turbo bl config set --key timeout --value 600 diff --git a/packages/cli/src/commands/app/list.ts b/packages/cli/src/commands/app/list.ts index 904ad47..b87694f 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" }, { - flag: "--region ", - description: "API region (default: cn-beijing)", + flag: "--console-site ", + description: "Console site: domestic, international", + }, + { + flag: "--console-switch-agent ", + description: "Switch agent UID", + 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..6078037 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" }, + { + flag: "--console-site ", + description: "Console site: domestic, international", + }, + { + flag: "--console-switch-agent ", + description: "Switch agent UID", + 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/set.ts b/packages/cli/src/commands/config/set.ts index 9a0288e..2443fb4 100644 --- a/packages/cli/src/commands/config/set.ts +++ b/packages/cli/src/commands/config/set.ts @@ -12,7 +12,6 @@ import { import { emitResult } from "../../output/output.ts"; const VALID_KEYS = [ - "region", "base_url", "output", "output_dir", @@ -58,7 +57,7 @@ export default defineCommand({ { flag: "--key ", description: - "Config key (region, base_url, output, output_dir, timeout, api_key, access_token, default_*_model, access_key_id, access_key_secret, workspace_id)", + "Config key (base_url, output, output_dir, timeout, api_key, access_token, default_*_model, access_key_id, access_key_secret, workspace_id)", }, { flag: "--value ", description: "Value to set" }, ], @@ -90,13 +89,6 @@ export default defineCommand({ } // Validate specific values - if (resolvedKey === "region" && !["cn", "us", "intl"].includes(value)) { - throw new BailianError( - `Invalid region "${value}". Valid values: cn, us, intl`, - ExitCode.USAGE, - ); - } - if (resolvedKey === "output" && !["text", "json"].includes(value)) { throw new BailianError( `Invalid output format "${value}". Valid values: text, json`, 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..aeb03da 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" }, { - flag: "--region ", - description: "API region (default: cn-beijing)", + flag: "--console-site ", + description: "Console site: domestic, international", + }, + { + flag: "--console-switch-agent ", + description: "Switch agent UID", + 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..400a468 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" }, + { + flag: "--console-site ", + description: "Console site: domestic, international", + }, + { + flag: "--console-switch-agent ", + description: "Switch agent UID", + 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..6e54e4d 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" }, + { + flag: "--console-site ", + description: "Console site: domestic, international", + }, { - flag: "--region ", - description: "API region (default: cn-beijing)", + flag: "--console-switch-agent ", + description: "Switch agent UID", + type: "number", }, ], examples: [ @@ -280,23 +280,22 @@ 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); - if (config.dryRun) { emitResult( { apis: [MODEL_LIST_API, MONITOR_API], - region, + ...effectiveConsoleGatewayConfig(config), }, format, ); return; } - let models = await fetchAllModelsWithQpm(config, credential.token, region); + const credential = await resolveConsoleGatewayCredential(config); + + 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..34e62bd 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" }, { - flag: "--region ", - description: "API region (default: cn-beijing)", + flag: "--console-site ", + description: "Console site: domestic, international", + }, + { + flag: "--console-switch-agent ", + description: "Switch agent UID", + type: "number", }, ], examples: [ @@ -130,26 +136,24 @@ 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); - const requestData = { input: { pageNo: page, pageSize }, }; if (config.dryRun) { - emitResult({ api: HISTORY_API, data: requestData, region }, format); + emitResult({ api: HISTORY_API, data: requestData }, format); return; } + const credential = await resolveConsoleGatewayCredential(config); + let result: unknown; try { 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..3f2b983 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" }, { - flag: "--region ", - description: "API region (default: cn-beijing)", + flag: "--console-site ", + description: "Console site: domestic, international", + }, + { + flag: "--console-switch-agent ", + description: "Switch agent UID", + type: "number", }, ], examples: [ @@ -186,11 +190,8 @@ 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); - if (config.dryRun) { const input: Record = { pageNo: 1, @@ -200,11 +201,13 @@ 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); + const credential = await resolveConsoleGatewayCredential(config); + + 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..0683e92 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" }, { - flag: "--region ", - description: "API region (default: cn-beijing)", + flag: "--console-site ", + description: "Console site: domestic, international", + }, + { + flag: "--console-switch-agent ", + description: "Switch agent UID", + type: "number", }, ], examples: [ @@ -122,12 +126,22 @@ export default defineCommand({ } const autoConfirm = Boolean(flags.yes) || config.yes; - const region = (flags.region as string) || "cn-beijing"; const format = detectOutputFormat(config.output); + if (config.dryRun) { + const requestData = { + input: { + model: modelName, + limit: { usage_limit: tpmValue }, + }, + }; + emitResult({ api: UPDATE_LIMITS_API, data: requestData }, format); + return; + } + 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`, @@ -159,11 +173,6 @@ export default defineCommand({ } as Record, }; - if (config.dryRun) { - emitResult({ api: UPDATE_LIMITS_API, data: requestData, region }, format); - return; - } - const submitRequest = async (confirmedDowngrade?: boolean): Promise => { if (confirmedDowngrade) { requestData.input.confirmedDowngrade = true; @@ -172,7 +181,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..8c505a6 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" }, { - flag: "--region ", - description: "API region (default: cn-beijing)", + flag: "--console-site ", + description: "Console site: domestic, international", + }, + { + flag: "--console-switch-agent ", + description: "Switch agent UID", + 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,11 +238,8 @@ export default defineCommand({ ); process.exit(1); } - const region = (flags.region as string) || "cn-beijing"; const format = detectOutputFormat(config.output); - const credential = await resolveConsoleGatewayCredential(config); - let models: string[]; const typeMap = new Map(); @@ -249,21 +252,8 @@ export default defineCommand({ .filter(Boolean), ), ]; - const searchResults = await Promise.all( - models.map((name) => fetchModelList(config, credential.token, { name, pageSize: 50 })), - ); - for (let idx = 0; idx < models.length; idx++) { - const matched = searchResults[idx].models.find((item) => item.model === models[idx]); - if (matched) { - typeMap.set(models[idx], resolveModelType((matched.capabilities as string[]) || [])); - } - } } else { - const modelInfos = await fetchAllModels(config, credential.token); - models = modelInfos.map((info) => info.name); - for (const info of modelInfos) { - typeMap.set(info.name, info.type); - } + models = []; } const requestData = { @@ -275,24 +265,41 @@ export default defineCommand({ { api: FREE_TIER_API, data: requestData, - region, - token: credential.token.slice(0, 8) + "...", }, format, ); return; } + const credential = await resolveConsoleGatewayCredential(config); + + if (!modelFlag) { + const modelInfos = await fetchAllModels(config, credential.token); + models = modelInfos.map((info) => info.name); + for (const info of modelInfos) { + typeMap.set(info.name, info.type); + } + requestData.queryFreeTierQuotaRequest.models = models; + } else { + const searchResults = await Promise.all( + models.map((name) => fetchModelList(config, credential.token, { name, pageSize: 50 })), + ); + for (let idx = 0; idx < models.length; idx++) { + const matched = searchResults[idx].models.find((item) => item.model === models[idx]); + if (matched) { + typeMap.set(models[idx], resolveModelType((matched.capabilities as string[]) || [])); + } + } + } + const [quotaResult, stopResult] = await Promise.all([ 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..206e3d3 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" }, { - flag: "--region ", - description: "API region (default: cn-beijing)", + flag: "--console-site ", + description: "Console site: domestic, international", + }, + { + flag: "--console-switch-agent ", + description: "Switch agent UID", + 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) { @@ -150,8 +153,6 @@ export default defineCommand({ process.exit(1); } - const credential = await resolveConsoleGatewayCredential(config); - let models: string[]; if (modelFlag) { models = [ @@ -163,7 +164,7 @@ export default defineCommand({ ), ]; } else { - models = await fetchAllModelNames(config, credential.token); + models = []; } const api = off ? DEACTIVATE_API : ACTIVATE_API; @@ -176,25 +177,27 @@ export default defineCommand({ { api, data: { [requestKey]: { models } }, - region, - token: credential.token.slice(0, 8) + "...", }, format, ); return; } + const credential = await resolveConsoleGatewayCredential(config); + + if (!modelFlag) { + models = await fetchAllModelNames(config, credential.token); + } + if (off) { const [quotaResult, stopResult] = await Promise.all([ 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 +221,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 +229,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..96c0ea8 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" }, { - flag: "--region ", - description: "API region (default: cn-beijing)", + flag: "--console-site ", + description: "Console site: domestic, international", + }, + { + flag: "--console-switch-agent ", + description: "Switch agent UID", + type: "number", }, ], examples: [ @@ -343,14 +347,11 @@ 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; const workspaceId = resolveWorkspaceId(config, flagWorkspaceId); - const credential = await resolveConsoleGatewayCredential(config); - const endTime = Date.now(); const startTime = endTime - daysFlag * 24 * 60 * 60 * 1000; @@ -378,15 +379,17 @@ 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; } + const credential = await resolveConsoleGatewayCredential(config); + 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,13 @@ 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 credential = await resolveConsoleGatewayCredential(config); + + 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..e213b9f 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" }, { - flag: "--region ", - description: "API region (default: cn-beijing)", + flag: "--console-site ", + description: "Console site: domestic, international", + }, + { + flag: "--console-switch-agent ", + description: "Switch agent UID", + 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/error-handler.ts b/packages/cli/src/error-handler.ts index ea1789c..b2291b3 100644 --- a/packages/cli/src/error-handler.ts +++ b/packages/cli/src/error-handler.ts @@ -9,6 +9,10 @@ import { API_KEY_PAGE } from "./urls.ts"; const LABEL_WIDTH = 13; +/** Short reminder; full resolution order matches `loadConfig` in bailian-cli-core. */ +const BASE_URL_HINT = + "If the DashScope host is wrong, check baseUrl (--base-url, bl config show, or DASHSCOPE_BASE_URL)."; + function pad(label: string): string { return label.padEnd(LABEL_WIDTH); } @@ -76,7 +80,7 @@ function pickNetworkHint(code: string | undefined): string { switch (code) { case "ENOTFOUND": case "EAI_AGAIN": - return "DNS resolution failed. Check DASHSCOPE_BASE_URL or your DNS / network."; + return `DNS resolution failed. Check DNS / network. ${BASE_URL_HINT}`; case "ECONNREFUSED": return "Connection refused. Check the target host/port and proxy settings."; case "ECONNRESET": @@ -86,13 +90,13 @@ function pickNetworkHint(code: string | undefined): string { "export HTTPS_PROXY=http://127.0.0.1:" ); case "ETIMEDOUT": - return "Connection timed out. Check your network or try a different region."; + return `Connection timed out. Check your network. ${BASE_URL_HINT}`; case "CERT_HAS_EXPIRED": case "UNABLE_TO_VERIFY_LEAF_SIGNATURE": case "DEPTH_ZERO_SELF_SIGNED_CERT": return "TLS certificate error. Check system clock and CA bundle."; default: - return "Check network connection, proxy settings (HTTP_PROXY / HTTPS_PROXY), and DASHSCOPE_BASE_URL."; + return `Check network and proxy (HTTP_PROXY / HTTPS_PROXY). ${BASE_URL_HINT}`; } } @@ -166,9 +170,8 @@ export function handleError(err: unknown): never { "Request timed out.", ExitCode.TIMEOUT, "Try increasing --timeout (e.g. --timeout 60).\n" + - "If this happens on every request with a valid API key, you may be hitting the wrong region.\n" + - "Run: bl auth status — to check your credentials and region.\n" + - "Run: bl config set --key region --value cn — to override the region.", + `${BASE_URL_HINT}\n` + + "Run: bl auth status — to check credentials.", { cause: err }, ); return handleError(timeout); 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..7c46ab3 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 () => { @@ -159,20 +160,25 @@ describe("e2e: auth", () => { expect(data.dashscope_commands?.method).toBeDefined(); }); - test.skipIf(!isDashScopeE2EReady())("auth status --output json --quiet --region cn", async () => { - const { stdout, stderr, exitCode } = await runCli([ - "auth", - "status", - "--non-interactive", - "--output", - "json", - "--quiet", - "--region", - "cn", - ]); - expect(exitCode, stderr).toBe(0); - const data = parseStdoutJson<{ authenticated?: boolean; dashscope_commands?: unknown }>(stdout); - expect(data.authenticated).toBe(true); - expect(data.dashscope_commands).toBeDefined(); - }); + test.skipIf(!isDashScopeE2EReady())( + "auth status --output json --quiet --base-url 国内", + async () => { + const { stdout, stderr, exitCode } = await runCli([ + "auth", + "status", + "--non-interactive", + "--output", + "json", + "--quiet", + "--base-url", + "https://dashscope.aliyuncs.com", + ]); + expect(exitCode, stderr).toBe(0); + const data = parseStdoutJson<{ authenticated?: boolean; dashscope_commands?: unknown }>( + stdout, + ); + expect(data.authenticated).toBe(true); + expect(data.dashscope_commands).toBeDefined(); + }, + ); }); 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..04d6f2a --- /dev/null +++ b/packages/cli/tests/e2e/console-flags.e2e.test.ts @@ -0,0 +1,148 @@ +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`) and DashScope `--base-url`. + */ + +describe("e2e: console global flags", () => { + test("根帮助展示 --base-url 与 console 全局标志", async () => { + const { stderr, exitCode } = await runCli(["--help"]); + expect(exitCode, stderr).toBe(0); + expect(stderr).toMatch(/--base-url/); + expect(stderr).toMatch(/--console-region/); + expect(stderr).toMatch(/--console-site/); + expect(stderr).toMatch(/--console-switch-agent/); + expect(stderr).not.toMatch(/^\s*--region\s/m); + }); + + 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 拒绝未知全局 flag --region", async () => { + const { stderr, exitCode } = await runCli([ + "console", + "call", + "--api", + "some.api.name", + "--data", + "{}", + "--dry-run", + "--non-interactive", + "--region", + "cn", + ]); + expect(exitCode).not.toBe(0); + expect(stderr).toMatch(/Unknown flag.*--region/); + }); + + 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..4018acf 100644 --- a/packages/cli/tests/e2e/mcp.e2e.test.ts +++ b/packages/cli/tests/e2e/mcp.e2e.test.ts @@ -66,7 +66,7 @@ describe("e2e: mcp", () => { expect(exitCode, stderr).toBe(0); const data = parseStdoutJson<{ api?: string; - region?: string; + consoleRegion?: string; data?: { reqDTO?: { type?: string; @@ -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..beaddcd 100644 --- a/packages/core/src/config/loader.ts +++ b/packages/core/src/config/loader.ts @@ -1,5 +1,5 @@ import { readFileSync, writeFileSync, renameSync, existsSync } from "fs"; -import { parseConfigFile, REGIONS, type Config, type ConfigFile, type Region } from "./schema.ts"; +import { parseConfigFile, REGIONS, type Config, type ConfigFile } from "./schema.ts"; import { ensureConfigDir, getConfigPath } from "./paths.ts"; import { detectOutputFormat, type OutputFormat } from "../output/formatter.ts"; import { BailianError } from "../errors/base.ts"; @@ -36,16 +36,7 @@ export function loadConfig(flags: GlobalFlags): Config { const accessTokenEnv = process.env.DASHSCOPE_ACCESS_TOKEN?.trim() || undefined; const fileAccessToken = file.access_token?.trim() || undefined; - const explicitRegion = (flags.region as string) || process.env.DASHSCOPE_REGION || undefined; - const cachedRegion = file.region; - const region = (explicitRegion || cachedRegion || "cn") as Region; - - const baseUrl = - flags.baseUrl || - process.env.DASHSCOPE_BASE_URL || - file.base_url || - REGIONS[region] || - REGIONS.cn; + const baseUrl = flags.baseUrl || file.base_url || process.env.DASHSCOPE_BASE_URL || REGIONS.cn; const output: OutputFormat = detectOutputFormat( flags.output || process.env.DASHSCOPE_OUTPUT || file.output, @@ -68,9 +59,7 @@ export function loadConfig(flags: GlobalFlags): Config { accessTokenEnv, fileAccessToken, fileApiKey, - fileRegion: file.region, configPath: getConfigPath(), - region, baseUrl, output, outputDir: file.output_dir || undefined, @@ -84,10 +73,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..331da0b 100644 --- a/packages/core/src/config/schema.ts +++ b/packages/core/src/config/schema.ts @@ -18,7 +18,6 @@ export interface ConfigFile { api_key?: string; /** OAuth-style token from `bl auth login --console` callback; sent as `Authorization: Bearer …` */ access_token?: string; - region?: Region; base_url?: string; output?: "text" | "json"; output_dir?: string; @@ -31,16 +30,18 @@ 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. */ @@ -63,8 +64,6 @@ export function parseConfigFile(raw: unknown): ConfigFile { out.access_token = obj.access_token; else if (typeof obj.accessToken === "string" && obj.accessToken.length > 0) out.access_token = obj.accessToken; - if (typeof obj.region === "string" && VALID_REGIONS.has(obj.region)) - out.region = obj.region as Region; if (typeof obj.base_url === "string" && isHttpUrl(obj.base_url)) out.base_url = obj.base_url; if (typeof obj.output === "string" && VALID_OUTPUTS.has(obj.output)) out.output = obj.output as ConfigFile["output"]; @@ -87,8 +86,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; @@ -103,9 +106,7 @@ export interface Config { /** `access_token` in config file (console login). */ fileAccessToken?: string; fileApiKey?: string; - fileRegion?: Region; configPath?: string; - region: Region; baseUrl: string; output: "text" | "json"; outputDir?: string; @@ -118,7 +119,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..6b04949 100644 --- a/packages/core/src/console/models.ts +++ b/packages/core/src/console/models.ts @@ -9,7 +9,6 @@ export interface ModelListParams { name?: string; providers?: string[]; capabilities?: string[]; - region?: string; } export interface ModelListResult { @@ -22,14 +21,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 +38,6 @@ export async function fetchModelList( contextWindows: [], }, }, - region, })) as any; const responseData = result?.data?.DataV2?.data ?? result?.data ?? {}; diff --git a/packages/core/src/telemetry/event.ts b/packages/core/src/telemetry/event.ts index 3eee293..283a9a0 100644 --- a/packages/core/src/telemetry/event.ts +++ b/packages/core/src/telemetry/event.ts @@ -7,7 +7,6 @@ export interface TrackingEvent { httpStatus?: number; requestId?: string; cliVersion: string; - region: string; nodeVersion: string; os: string; authMethod?: string; @@ -20,7 +19,6 @@ export function createTrackingEvent(opts: { success: boolean; error?: { message?: string; httpStatus?: number; requestId?: string }; cliVersion: string; - region: string; authMethod?: string; params?: Record; }): TrackingEvent { @@ -30,7 +28,6 @@ export function createTrackingEvent(opts: { durationMs: opts.durationMs, success: opts.success, cliVersion: opts.cliVersion, - region: opts.region, nodeVersion: process.version, os: process.platform, }; diff --git a/packages/core/src/telemetry/tracker.ts b/packages/core/src/telemetry/tracker.ts index a8d4f1c..495ae8a 100644 --- a/packages/core/src/telemetry/tracker.ts +++ b/packages/core/src/telemetry/tracker.ts @@ -17,7 +17,6 @@ const GLOBAL_FLAG_KEYS = new Set([ "help", "nonInteractive", "async", - "region", "console", ]); @@ -131,7 +130,6 @@ export async function trackCommandExecution( success, error: success ? undefined : { message: errorMessage, httpStatus, requestId }, cliVersion: config.clientVersion ?? "unknown", - region: config.region, authMethod, params: extractParams(flags), }); diff --git a/packages/core/src/types/command.ts b/packages/core/src/types/command.ts index aa991d5..7b9167a 100644 --- a/packages/core/src/types/command.ts +++ b/packages/core/src/types/command.ts @@ -43,7 +43,6 @@ export function defineCommand(spec: CommandSpec): Command { /** Global flags shared by all commands — drives the parser's type resolution. */ export const GLOBAL_OPTIONS: OptionDef[] = [ { flag: "--api-key ", description: "API key" }, - { flag: "--region ", description: "API region: cn (default), us, intl" }, { flag: "--base-url ", description: "API base URL" }, { flag: "--output ", description: "Output format: text, json" }, { flag: "--timeout ", description: "Request timeout", type: "number" }, @@ -53,6 +52,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..6bb1695 100644 --- a/packages/core/tests/index.test.ts +++ b/packages/core/tests/index.test.ts @@ -10,7 +10,6 @@ import { function testConfig(overrides: Partial = {}): Config { return { - region: "cn", baseUrl: "https://dashscope.aliyuncs.com", output: "json", timeout: 30, @@ -22,7 +21,6 @@ function testConfig(overrides: Partial = {}): Config { nonInteractive: true, async: false, telemetry: true, - consoleGatewayUrl: "https://bailian-cs.console.aliyun.com", ...overrides, }; } @@ -200,7 +198,12 @@ 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 ignores obsolete region field", () => { + const f = parseConfigFile({ region: "intl" }); + expect("region" in f).toBe(false); +}); + +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 +213,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/SKILL.md b/skills/bailian-cli/SKILL.md index 35844b6..17cde05 100644 --- a/skills/bailian-cli/SKILL.md +++ b/skills/bailian-cli/SKILL.md @@ -117,7 +117,7 @@ bl auth logout --console # clear console token only Get an API key: https://bailian.console.aliyun.com/cn-beijing/?tab=app#/api-key -**Region:** `cn` (default), `us`, `intl` — `--region` or `DASHSCOPE_REGION` or `bl config set --key region --value us`. +**DashScope endpoint:** default `https://dashscope.aliyuncs.com` (China). Override with `--base-url`, `bl config set --key base_url --value https://dashscope-us.aliyuncs.com` (US), or `DASHSCOPE_BASE_URL` / `https://dashscope-intl.aliyuncs.com` (international). --- @@ -127,13 +127,13 @@ See [`reference/index.md` → Global flags](reference/index.md#global-flags) for Commonly used: -| Flag | Purpose | -| ------------------------------------- | --------------------------------------------------------- | -| `--output text\|json` | Structured output (default: text in TTY, json when piped) | -| `--api-key`, `--region`, `--base-url` | Override auth / endpoint | -| `--quiet`, `--verbose`, `--dry-run` | Output control | -| `--non-interactive` | CI / agent mode (no prompts) | -| `--help` | Per-command help | +| Flag | Purpose | +| ----------------------------------- | --------------------------------------------------------- | +| `--output text\|json` | Structured output (default: text in TTY, json when piped) | +| `--api-key`, `--base-url` | Override auth / endpoint | +| `--quiet`, `--verbose`, `--dry-run` | Output control | +| `--non-interactive` | CI / agent mode (no prompts) | +| `--help` | Per-command help | --- @@ -176,7 +176,7 @@ ffmpeg -f concat -safe 0 -i list.txt -c copy output.mp4 ## Configuration - **Config file:** `~/.bailian/config.json` -- **Env:** `DASHSCOPE_API_KEY`, `DASHSCOPE_REGION`, `DASHSCOPE_BASE_URL`, `DASHSCOPE_OUTPUT` +- **Env:** `DASHSCOPE_API_KEY`, `DASHSCOPE_BASE_URL`, `DASHSCOPE_OUTPUT` ```bash bl config show diff --git a/skills/bailian-cli/assets/issue-reporting.md b/skills/bailian-cli/assets/issue-reporting.md index 7737ed6..43789ec 100644 --- a/skills/bailian-cli/assets/issue-reporting.md +++ b/skills/bailian-cli/assets/issue-reporting.md @@ -20,7 +20,7 @@ function shouldOfferIssueReport(exitCode, apiCode, message, hint): # Step 2: NETWORK / TIMEOUT — exclude if hint is actionable if exitCode in [5 (TIMEOUT), 6 (NETWORK)] AND hint is actionable: - return EXCLUDE # user can self-service (DNS, proxy, --timeout, region) + return EXCLUDE # user can self-service (DNS, proxy, --timeout, base_url) # Step 3: GENERAL (exit code 1) — shared by CLI bugs AND service passthrough # MUST inspect api_code / message to disambiguate @@ -80,7 +80,7 @@ These are **user**, **environment**, or **service business** errors. Give fix hi | **Free quota query** | `bl usage free` business result | Quota used up — not a CLI defect | | **Obvious local env** | Hint is sufficient | `ENOENT` / `EACCES`, wrong file path, disk full | | **Network (self-service)** | Exit code **6** (NETWORK) + clear hint | DNS, proxy, TLS — user fixes `DASHSCOPE_BASE_URL`, proxy, or network | -| **Timeout (self-service)** | Exit code **5** (TIMEOUT) + hint works | Increase `--timeout`, check region with `bl auth status` | +| **Timeout (self-service)** | Exit code **5** (TIMEOUT) + hint works | Increase `--timeout`, check `base_url` with `bl auth status` | **Rule:** If the authoritative source of the error is the **service response** or **user input**, treat it as non-reportable (same boundary as the CLI repo’s error-handling docs). @@ -172,7 +172,7 @@ Before any paste or `gh issue create`: - Replace `Authorization: Bearer ...` headers in verbose output → `Authorization: Bearer [REDACTED]` - Redact `--prompt` / `--message` / `--biz-params` contents if they contain user business data → summarize as `[user prompt about ]` - Redact `account`, `uid`, `aliuid` from `bl auth status` output → `[REDACTED]` -- Redact sensitive fields from `bl config show` (keep non-secret keys like `region`, model defaults) +- Redact sensitive fields from `bl config show` (keep non-secret keys like `base_url`, model defaults) - **Keep** `Request ID` / `request_id` — helps the team trace logs - Local paths may stay or be generalized (`~/path/to/file.png`) diff --git a/skills/bailian-cli/reference/app.md b/skills/bailian-cli/reference/app.md index e486673..5b56bfb 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 | +| `--console-site ` | string | no | Console site: domestic, international | +| `--console-switch-agent ` | number | no | Switch agent UID | #### Examples diff --git a/skills/bailian-cli/reference/auth.md b/skills/bailian-cli/reference/auth.md index 3790ae5..eaa1006 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 | +| `--console-site ` | string | no | Console site: domestic, international | +| `--console-switch-agent ` | number | no | Switch agent UID | #### Examples diff --git a/skills/bailian-cli/reference/config.md b/skills/bailian-cli/reference/config.md index 39019f5..0b7da11 100644 --- a/skills/bailian-cli/reference/config.md +++ b/skills/bailian-cli/reference/config.md @@ -49,10 +49,10 @@ bl config export-schema --command "video generate" #### Options -| Flag | Type | Required | Description | -| ----------------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | -| `--key ` | string | no | Config key (region, base*url, output, output_dir, timeout, api_key, access_token, default*\*\_model, access_key_id, access_key_secret, workspace_id) | -| `--value ` | string | no | Value to set | +| Flag | Type | Required | Description | +| ----------------- | ------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------- | +| `--key ` | string | no | Config key (base*url, output, output_dir, timeout, api_key, access_token, default*\*\_model, access_key_id, access_key_secret, workspace_id) | +| `--value ` | string | no | Value to set | #### Examples diff --git a/skills/bailian-cli/reference/console.md b/skills/bailian-cli/reference/console.md index 50e5ea1..26e70d5 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 | +| `--console-site ` | string | no | Console site: domestic, international | +| `--console-switch-agent ` | number | no | Switch agent UID | #### 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..890f43b 100644 --- a/skills/bailian-cli/reference/index.md +++ b/skills/bailian-cli/reference/index.md @@ -87,21 +87,23 @@ 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 | +| `--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..e18dd94 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 | +| `--console-site ` | string | no | Console site: domestic, international | +| `--console-switch-agent ` | number | no | Switch agent UID | #### Examples diff --git a/skills/bailian-cli/reference/quota.md b/skills/bailian-cli/reference/quota.md index 86aa355..236f248 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 | +| `--console-site ` | string | no | Console site: domestic, international | +| `--console-switch-agent ` | number | no | Switch agent UID | #### 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 | +| `--console-site ` | string | no | Console site: domestic, international | +| `--console-switch-agent ` | number | no | Switch agent UID | #### 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 | +| `--console-site ` | string | no | Console site: domestic, international | +| `--console-switch-agent ` | number | no | Switch agent UID | #### 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 | +| `--console-site ` | string | no | Console site: domestic, international | +| `--console-switch-agent ` | number | no | Switch agent UID | #### Examples diff --git a/skills/bailian-cli/reference/usage.md b/skills/bailian-cli/reference/usage.md index 52ccd11..6ae89c9 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 | +| `--console-site ` | string | no | Console site: domestic, international | +| `--console-switch-agent ` | number | no | Switch agent UID | #### 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 | +| `--console-site ` | string | no | Console site: domestic, international | +| `--console-switch-agent ` | number | no | Switch agent UID | #### 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 | +| `--console-site ` | string | no | Console site: domestic, international | +| `--console-switch-agent ` | number | no | Switch agent UID | #### Examples diff --git a/skills/bailian-cli/reference/workspace.md b/skills/bailian-cli/reference/workspace.md index 2428721..5cceddc 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 | +| `--console-site ` | string | no | Console site: domestic, international | +| `--console-switch-agent ` | number | no | Switch agent UID | #### Examples