mirror of
https://github.com/modelstudioai/cli.git
synced 2026-09-14 19:49:23 +08:00
Merge branch 'main' into feat/update-intent-model
This commit is contained in:
@@ -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 <region>", description: "Console region" },
|
||||
{ flag: "--console-site <site>", description: "Console site: domestic, international" },
|
||||
{ flag: "--console-switch-agent <uid>", description: "Switch agent UID", type: "number" },
|
||||
```
|
||||
|
||||
这些 flag 已在 `GLOBAL_OPTIONS`(`packages/core/src/types/command.ts`)中注册,由 `loadConfig` 写入 `config.consoleRegion` / `config.consoleSite` / `config.consoleSwitchAgent`,`callConsoleGateway` 自动读取——命令无需手动提取或传递。
|
||||
|
||||
## 完成改动后的快速验证
|
||||
|
||||
```sh
|
||||
|
||||
+1
-1
@@ -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`。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -30,9 +30,15 @@ export default defineCommand({
|
||||
description: "Results per page (default: 30)",
|
||||
type: "number",
|
||||
},
|
||||
{ flag: "--console-region <region>", description: "Console region" },
|
||||
{
|
||||
flag: "--region <region>",
|
||||
description: "API region (default: cn-beijing)",
|
||||
flag: "--console-site <site>",
|
||||
description: "Console site: domestic, international",
|
||||
},
|
||||
{
|
||||
flag: "--console-switch-agent <uid>",
|
||||
description: "Switch agent UID",
|
||||
type: "number",
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
@@ -45,7 +51,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);
|
||||
@@ -62,17 +67,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 ?? [];
|
||||
|
||||
@@ -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<string, string> = {
|
||||
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<string> {
|
||||
@@ -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<string, unknown>, ...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<string, unknown> | 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<number> {
|
||||
@@ -276,9 +379,69 @@ function openInBrowser(url: string): Promise<void> {
|
||||
});
|
||||
}
|
||||
|
||||
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<void> {
|
||||
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<unknown>(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<string, unknown>;
|
||||
existing.api_key = key;
|
||||
await writeConfigFile(existing);
|
||||
}
|
||||
|
||||
export async function runConsoleLogin(
|
||||
consoleOrigin: string,
|
||||
opts?: { needApiKey?: boolean; onApiKey?: (key: string) => Promise<void> },
|
||||
config: Config,
|
||||
opts?: { needApiKey?: boolean },
|
||||
): Promise<void> {
|
||||
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);
|
||||
|
||||
if (accessToken || apiKey) {
|
||||
const hasConfig =
|
||||
accessToken || baseUrl || consoleSite || consoleRegion || consoleSwitchAgent || workspaceId;
|
||||
|
||||
if (hasConfig || apiKey) {
|
||||
try {
|
||||
if (accessToken) {
|
||||
if (hasConfig) {
|
||||
const existing = readConfigFile() as Record<string, unknown>;
|
||||
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 {
|
||||
|
||||
@@ -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<void> {
|
||||
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<unknown>(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<string, unknown>;
|
||||
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",
|
||||
@@ -85,10 +24,14 @@ export default defineCommand({
|
||||
usage: "bl auth login --api-key <key> | bl auth login --console",
|
||||
options: [
|
||||
{ flag: "--api-key <key>", description: "DashScope API key to store" },
|
||||
{
|
||||
flag: "--base-url <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"],
|
||||
@@ -101,9 +44,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;
|
||||
}
|
||||
@@ -131,8 +73,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<string, unknown>;
|
||||
existing.base_url = baseUrl;
|
||||
await writeConfigFile(existing);
|
||||
}
|
||||
await validateAndPersistApiKey(effectiveConfig, key, effectiveConfig.baseUrl);
|
||||
printQuickStart();
|
||||
} else {
|
||||
emitBare("Would validate and save API key.");
|
||||
|
||||
@@ -142,6 +142,18 @@ export default defineCommand({
|
||||
name: "auth status",
|
||||
description: "Show current authentication state",
|
||||
usage: "bl auth status",
|
||||
options: [
|
||||
{ flag: "--console-region <region>", description: "Console region" },
|
||||
{
|
||||
flag: "--console-site <site>",
|
||||
description: "Console site: domestic, international",
|
||||
},
|
||||
{
|
||||
flag: "--console-switch-agent <uid>",
|
||||
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);
|
||||
|
||||
@@ -12,7 +12,6 @@ import {
|
||||
import { emitResult } from "../../output/output.ts";
|
||||
|
||||
const VALID_KEYS = [
|
||||
"region",
|
||||
"base_url",
|
||||
"output",
|
||||
"output_dir",
|
||||
@@ -59,7 +58,7 @@ export default defineCommand({
|
||||
{
|
||||
flag: "--key <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 <value>", description: "Value to set" },
|
||||
],
|
||||
@@ -91,13 +90,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`,
|
||||
|
||||
@@ -20,25 +20,21 @@ export default defineCommand({
|
||||
const format = detectOutputFormat(config.output);
|
||||
|
||||
const result: Record<string, unknown> = {
|
||||
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);
|
||||
},
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
defineCommand,
|
||||
callConsoleGateway,
|
||||
effectiveConsoleGatewayConfig,
|
||||
resolveConsoleGatewayCredential,
|
||||
CONSOLE_GATEWAY_NO_TOKEN_MESSAGE,
|
||||
BailianError,
|
||||
@@ -27,14 +28,20 @@ export default defineCommand({
|
||||
description: "Request data as JSON string",
|
||||
required: true,
|
||||
},
|
||||
{ flag: "--console-region <region>", description: "Console region" },
|
||||
{
|
||||
flag: "--region <region>",
|
||||
description: "API region (default: cn-beijing)",
|
||||
flag: "--console-site <site>",
|
||||
description: "Console site: domestic, international",
|
||||
},
|
||||
{
|
||||
flag: "--console-switch-agent <uid>",
|
||||
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;
|
||||
@@ -51,7 +58,6 @@ export default defineCommand({
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const region = (flags.region as string) || "cn-beijing";
|
||||
const format = detectOutputFormat(config.output);
|
||||
|
||||
let token: string | undefined;
|
||||
@@ -64,14 +70,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);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
defineCommand,
|
||||
callConsoleGateway,
|
||||
effectiveConsoleGatewayConfig,
|
||||
resolveConsoleGatewayCredential,
|
||||
detectOutputFormat,
|
||||
BailianError,
|
||||
@@ -36,7 +37,16 @@ export default defineCommand({
|
||||
},
|
||||
{ flag: "--page <n>", description: "Page number (default: 1)", type: "number" },
|
||||
{ flag: "--page-size <n>", description: "Results per page (default: 30)", type: "number" },
|
||||
{ flag: "--region <region>", description: "API region (default: cn-beijing)" },
|
||||
{ flag: "--console-region <region>", description: "Console region" },
|
||||
{
|
||||
flag: "--console-site <site>",
|
||||
description: "Console site: domestic, international",
|
||||
},
|
||||
{
|
||||
flag: "--console-switch-agent <uid>",
|
||||
description: "Switch agent UID",
|
||||
type: "number",
|
||||
},
|
||||
],
|
||||
examples: ["bl mcp list", "bl mcp list --name finance", "bl mcp list --output json"],
|
||||
async run(config: Config, flags: GlobalFlags) {
|
||||
@@ -44,7 +54,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 = {
|
||||
@@ -59,7 +68,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;
|
||||
}
|
||||
|
||||
@@ -68,7 +77,6 @@ export default defineCommand({
|
||||
const result = (await callConsoleGateway(config, credential.token, {
|
||||
api: MCP_LIST_API,
|
||||
data,
|
||||
region,
|
||||
})) as Record<string, unknown>;
|
||||
|
||||
const dataField = (result?.data as Record<string, unknown> | undefined) ?? {};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
defineCommand,
|
||||
callConsoleGateway,
|
||||
effectiveConsoleGatewayConfig,
|
||||
resolveConsoleGatewayCredential,
|
||||
detectOutputFormat,
|
||||
type Config,
|
||||
@@ -91,11 +92,7 @@ function extractResponseData(result: Record<string, unknown>): Record<string, un
|
||||
return direct ?? data;
|
||||
}
|
||||
|
||||
async function fetchAllModelsWithQpm(
|
||||
config: Config,
|
||||
token: string,
|
||||
region: string,
|
||||
): Promise<ModelWithQpm[]> {
|
||||
async function fetchAllModelsWithQpm(config: Config, token: string): Promise<ModelWithQpm[]> {
|
||||
const allModels: ModelWithQpm[] = [];
|
||||
let pageNo = 1;
|
||||
|
||||
@@ -112,7 +109,6 @@ async function fetchAllModelsWithQpm(
|
||||
supports: { selfServiceLimitIncrease: true },
|
||||
},
|
||||
},
|
||||
region,
|
||||
});
|
||||
|
||||
const resp = extractResponseData(raw as Record<string, unknown>);
|
||||
@@ -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<string, unknown>);
|
||||
@@ -254,9 +248,15 @@ export default defineCommand({
|
||||
flag: "--period <minutes>",
|
||||
description: "Query usage for the last N minutes (default: 2)",
|
||||
},
|
||||
{ flag: "--console-region <region>", description: "Console region" },
|
||||
{
|
||||
flag: "--region <region>",
|
||||
description: "API region (default: cn-beijing)",
|
||||
flag: "--console-site <site>",
|
||||
description: "Console site: domestic, international",
|
||||
},
|
||||
{
|
||||
flag: "--console-switch-agent <uid>",
|
||||
description: "Switch agent UID",
|
||||
type: "number",
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
@@ -274,23 +274,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(
|
||||
@@ -310,7 +309,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) => {
|
||||
|
||||
@@ -108,9 +108,15 @@ export default defineCommand({
|
||||
flag: "--model <model>",
|
||||
description: "Filter by model name",
|
||||
},
|
||||
{ flag: "--console-region <region>", description: "Console region" },
|
||||
{
|
||||
flag: "--region <region>",
|
||||
description: "API region (default: cn-beijing)",
|
||||
flag: "--console-site <site>",
|
||||
description: "Console site: domestic, international",
|
||||
},
|
||||
{
|
||||
flag: "--console-switch-agent <uid>",
|
||||
description: "Switch agent UID",
|
||||
type: "number",
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
@@ -124,7 +130,6 @@ export default defineCommand({
|
||||
const page = Number(flags.page) || 1;
|
||||
const pageSize = Number(flags.pageSize) || 10;
|
||||
const modelFilter = (flags.model as string) || undefined;
|
||||
const region = (flags.region as string) || "cn-beijing";
|
||||
const format = detectOutputFormat(config.output);
|
||||
|
||||
const requestData = {
|
||||
@@ -132,7 +137,7 @@ export default defineCommand({
|
||||
};
|
||||
|
||||
if (config.dryRun) {
|
||||
emitResult({ api: HISTORY_API, data: requestData, region }, format);
|
||||
emitResult({ api: HISTORY_API, data: requestData }, format);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -143,7 +148,6 @@ export default defineCommand({
|
||||
result = await callConsoleGateway(config, credential.token, {
|
||||
api: HISTORY_API,
|
||||
data: requestData,
|
||||
region,
|
||||
});
|
||||
} catch (err) {
|
||||
if (err instanceof BailianError && err.message.includes("NotLogined")) {
|
||||
|
||||
@@ -68,7 +68,6 @@ function extractResponseData(result: Record<string, unknown>): Record<string, un
|
||||
async function fetchAllModelsWithQpm(
|
||||
config: Config,
|
||||
token: string,
|
||||
region: string,
|
||||
onlySelfService: boolean,
|
||||
): Promise<ModelWithQpm[]> {
|
||||
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<string, unknown>);
|
||||
@@ -165,9 +163,15 @@ export default defineCommand({
|
||||
flag: "--all",
|
||||
description: "Show all models, not just self-service ones",
|
||||
},
|
||||
{ flag: "--console-region <region>", description: "Console region" },
|
||||
{
|
||||
flag: "--region <region>",
|
||||
description: "API region (default: cn-beijing)",
|
||||
flag: "--console-site <site>",
|
||||
description: "Console site: domestic, international",
|
||||
},
|
||||
{
|
||||
flag: "--console-switch-agent <uid>",
|
||||
description: "Switch agent UID",
|
||||
type: "number",
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
@@ -180,7 +184,6 @@ export default defineCommand({
|
||||
async run(config: Config, flags: GlobalFlags) {
|
||||
const modelFlag = (flags.model as string) || undefined;
|
||||
const showAll = Boolean(flags.all);
|
||||
const region = (flags.region as string) || "cn-beijing";
|
||||
const format = detectOutputFormat(config.output);
|
||||
|
||||
if (config.dryRun) {
|
||||
@@ -192,7 +195,7 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,6 @@ function extractResponseData(result: Record<string, unknown>): Record<string, un
|
||||
async function fetchModelQpmInfo(
|
||||
config: Config,
|
||||
token: string,
|
||||
region: string,
|
||||
modelName: string,
|
||||
): Promise<{ model: string; qpmInfo: Record<string, QpmInfoItem> } | undefined> {
|
||||
const raw = await callConsoleGateway(config, token, {
|
||||
@@ -69,7 +68,6 @@ async function fetchModelQpmInfo(
|
||||
supports: { selfServiceLimitIncrease: true },
|
||||
},
|
||||
},
|
||||
region,
|
||||
});
|
||||
|
||||
const resp = extractResponseData(raw as Record<string, unknown>);
|
||||
@@ -99,9 +97,15 @@ export default defineCommand({
|
||||
flag: "--yes",
|
||||
description: "Skip downgrade confirmation",
|
||||
},
|
||||
{ flag: "--console-region <region>", description: "Console region" },
|
||||
{
|
||||
flag: "--region <region>",
|
||||
description: "API region (default: cn-beijing)",
|
||||
flag: "--console-site <site>",
|
||||
description: "Console site: domestic, international",
|
||||
},
|
||||
{
|
||||
flag: "--console-switch-agent <uid>",
|
||||
description: "Switch agent UID",
|
||||
type: "number",
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
@@ -123,7 +127,6 @@ 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) {
|
||||
@@ -139,7 +142,7 @@ export default defineCommand({
|
||||
|
||||
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`,
|
||||
@@ -179,7 +182,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")) {
|
||||
|
||||
@@ -201,9 +201,15 @@ export default defineCommand({
|
||||
flag: "--sort <field>",
|
||||
description: "Sort by: remaining (ascending), expires (ascending)",
|
||||
},
|
||||
{ flag: "--console-region <region>", description: "Console region" },
|
||||
{
|
||||
flag: "--region <region>",
|
||||
description: "API region (default: cn-beijing)",
|
||||
flag: "--console-site <site>",
|
||||
description: "Console site: domestic, international",
|
||||
},
|
||||
{
|
||||
flag: "--console-switch-agent <uid>",
|
||||
description: "Switch agent UID",
|
||||
type: "number",
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
@@ -213,7 +219,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;
|
||||
@@ -226,7 +232,6 @@ export default defineCommand({
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
const region = (flags.region as string) || "cn-beijing";
|
||||
const format = detectOutputFormat(config.output);
|
||||
|
||||
let models: string[];
|
||||
@@ -286,12 +291,10 @@ export default defineCommand({
|
||||
callConsoleGateway(config, credential.token, {
|
||||
api: FREE_TIER_API,
|
||||
data: requestData,
|
||||
region,
|
||||
}),
|
||||
callConsoleGateway(config, credential.token, {
|
||||
api: FREE_TIER_ONLY_STATUS_API,
|
||||
data: { queryFreeTierOnlyStatusRequest: { models } },
|
||||
region,
|
||||
}),
|
||||
]);
|
||||
|
||||
|
||||
@@ -63,7 +63,6 @@ async function pollUntilDone(
|
||||
api: string,
|
||||
requestKey: string,
|
||||
models: string[],
|
||||
region: string,
|
||||
): Promise<unknown> {
|
||||
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<string, unknown>);
|
||||
@@ -124,9 +122,15 @@ export default defineCommand({
|
||||
flag: "--off",
|
||||
description: "Disable auto-stop",
|
||||
},
|
||||
{ flag: "--console-region <region>", description: "Console region" },
|
||||
{
|
||||
flag: "--region <region>",
|
||||
description: "API region (default: cn-beijing)",
|
||||
flag: "--console-site <site>",
|
||||
description: "Console site: domestic, international",
|
||||
},
|
||||
{
|
||||
flag: "--console-switch-agent <uid>",
|
||||
description: "Switch agent UID",
|
||||
type: "number",
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
@@ -141,7 +145,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) {
|
||||
@@ -193,12 +196,10 @@ export default defineCommand({
|
||||
callConsoleGateway(config, credential.token, {
|
||||
api: FREE_TIER_API,
|
||||
data: { queryFreeTierQuotaRequest: { models } },
|
||||
region,
|
||||
}),
|
||||
callConsoleGateway(config, credential.token, {
|
||||
api: FREE_TIER_ONLY_STATUS_API,
|
||||
data: { queryFreeTierOnlyStatusRequest: { models } },
|
||||
region,
|
||||
}),
|
||||
]);
|
||||
|
||||
@@ -222,7 +223,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;
|
||||
@@ -230,7 +231,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;
|
||||
|
||||
@@ -70,7 +70,6 @@ async function pollTelemetryApi(
|
||||
token: string,
|
||||
api: string,
|
||||
reqDTO: Record<string, unknown>,
|
||||
region: string,
|
||||
): Promise<unknown> {
|
||||
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<string, unknown>);
|
||||
@@ -306,9 +304,15 @@ export default defineCommand({
|
||||
flag: "--workspace-id <id>",
|
||||
description: "Workspace ID (env: BAILIAN_WORKSPACE_ID)",
|
||||
},
|
||||
{ flag: "--console-region <region>", description: "Console region" },
|
||||
{
|
||||
flag: "--region <region>",
|
||||
description: "API region (default: cn-beijing)",
|
||||
flag: "--console-site <site>",
|
||||
description: "Console site: domestic, international",
|
||||
},
|
||||
{
|
||||
flag: "--console-switch-agent <uid>",
|
||||
description: "Switch agent UID",
|
||||
type: "number",
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
@@ -324,7 +328,6 @@ export default defineCommand({
|
||||
const modelFlag = (flags.model as string) || undefined;
|
||||
const daysFlag = Number(flags.days) || 7;
|
||||
const typeFlag = (flags.type as string) || undefined;
|
||||
const region = (flags.region as string) || "cn-beijing";
|
||||
const format = detectOutputFormat(config.output);
|
||||
|
||||
const flagWorkspaceId = (flags.workspaceId as string) || undefined;
|
||||
@@ -357,7 +360,7 @@ export default defineCommand({
|
||||
|
||||
if (config.dryRun) {
|
||||
emitResult(
|
||||
{ api: LIST_API, data: { reqDTO: { ...baseReqDTO, model: models.join(",") } }, region },
|
||||
{ api: LIST_API, data: { reqDTO: { ...baseReqDTO, model: models.join(",") } } },
|
||||
format,
|
||||
);
|
||||
return;
|
||||
@@ -367,7 +370,7 @@ export default defineCommand({
|
||||
|
||||
const results = await Promise.all(
|
||||
models.map((model) =>
|
||||
pollTelemetryApi(config, credential.token, LIST_API, { ...baseReqDTO, model }, region),
|
||||
pollTelemetryApi(config, credential.token, LIST_API, { ...baseReqDTO, model }),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -411,7 +414,7 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -85,28 +85,32 @@ export default defineCommand({
|
||||
flag: "--list <n>",
|
||||
description: "Limit number of results",
|
||||
},
|
||||
{ flag: "--console-region <region>", description: "Console region" },
|
||||
{
|
||||
flag: "--region <region>",
|
||||
description: "API region (default: cn-beijing)",
|
||||
flag: "--console-site <site>",
|
||||
description: "Console site: domestic, international",
|
||||
},
|
||||
{
|
||||
flag: "--console-switch-agent <uid>",
|
||||
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,
|
||||
});
|
||||
|
||||
const resp = extractResponseData(result as Record<string, unknown>);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -79,7 +83,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":
|
||||
@@ -89,13 +93,13 @@ function pickNetworkHint(code: string | undefined): string {
|
||||
"export HTTPS_PROXY=http://127.0.0.1:<proxy-port>"
|
||||
);
|
||||
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}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,9 +173,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);
|
||||
|
||||
@@ -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`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 <model>/);
|
||||
expect(stderr).toMatch(/--period <minutes>/);
|
||||
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 <api>/);
|
||||
expect(stderr).toMatch(/--data <json>/);
|
||||
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<ConsoleDryRunMeta>(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<ConsoleDryRunMeta>(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<ConsoleDryRunMeta>(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<ConsoleDryRunMeta>(stdout);
|
||||
expect(data.consoleRegion).toBe("cn-hangzhou");
|
||||
expect(data.consoleSite).toBe("international");
|
||||
});
|
||||
});
|
||||
@@ -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 <server-code> --dry-run 输出 /api/v1/mcps/<code>/mcp 形态 URL", async () => {
|
||||
|
||||
@@ -231,11 +231,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 () => {
|
||||
|
||||
@@ -273,13 +273,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",
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<string>(["cn", "us", "intl"]);
|
||||
const VALID_OUTPUTS = new Set<string>(["text", "json"]);
|
||||
const VALID_CONSOLE_SITES = new Set<string>(["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;
|
||||
|
||||
@@ -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<string, Record<ConsoleSite, ConsoleGatewayInfo>> = {
|
||||
"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<string, unknown>;
|
||||
/** 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, unknown>): string {
|
||||
function buildGatewayParams(
|
||||
api: string,
|
||||
data: Record<string, unknown>,
|
||||
switchAgent?: number,
|
||||
): string {
|
||||
return JSON.stringify({
|
||||
Api: api,
|
||||
V: "1.0",
|
||||
@@ -24,6 +76,7 @@ function buildGatewayParams(api: string, data: Record<string, unknown>): string
|
||||
console: "ONE_CONSOLE",
|
||||
productCode: "p_efm",
|
||||
consoleSite: "BAILIAN_ALIYUN",
|
||||
...(switchAgent != null ? { switchAgent } : {}),
|
||||
...(typeof data.cornerstoneParam === "object" && data.cornerstoneParam !== null
|
||||
? (data.cornerstoneParam as Record<string, unknown>)
|
||||
: {}),
|
||||
@@ -37,17 +90,28 @@ function buildGatewayParams(api: string, data: Record<string, unknown>): 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<unknown> {
|
||||
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 gatewayBase = config.consoleGatewayUrl;
|
||||
const resolved = resolveGateway(effectiveRegion, effectiveSite);
|
||||
const gatewayBase = `https://${resolved.csGateway}`;
|
||||
const action = resolved.action;
|
||||
|
||||
const params = buildGatewayParams(api, data, effectiveSwitchAgent);
|
||||
const body = new URLSearchParams({ params, region: effectiveRegion });
|
||||
const timeoutMs = config.timeout * 1000;
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
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,
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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<ModelListResult> {
|
||||
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 ?? {};
|
||||
|
||||
@@ -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<string, unknown>;
|
||||
}): 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,
|
||||
};
|
||||
|
||||
@@ -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),
|
||||
});
|
||||
|
||||
@@ -46,7 +46,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 <key>", description: "API key" },
|
||||
{ flag: "--region <region>", description: "API region: cn (default), us, intl" },
|
||||
{ flag: "--base-url <url>", description: "API base URL" },
|
||||
{ flag: "--output <format>", description: "Output format: text, json" },
|
||||
{ flag: "--timeout <seconds>", description: "Request timeout", type: "number" },
|
||||
@@ -56,6 +55,16 @@ export const GLOBAL_OPTIONS: OptionDef[] = [
|
||||
{ flag: "--dry-run", description: "Dry run mode" },
|
||||
{ flag: "--non-interactive", description: "Disable interactive prompts" },
|
||||
{ flag: "--concurrent <n>", description: "Run N parallel requests (default: 1)", type: "number" },
|
||||
{
|
||||
flag: "--console-region <region>",
|
||||
description: "Console gateway region (e.g. cn-beijing, ap-southeast-1)",
|
||||
},
|
||||
{ flag: "--console-site <site>", description: "Console site: domestic, international" },
|
||||
{
|
||||
flag: "--console-switch-agent <uid>",
|
||||
description: "Switch agent UID for delegated access",
|
||||
type: "number",
|
||||
},
|
||||
{ flag: "--help", description: "Show help" },
|
||||
{ flag: "--version", description: "Print version" },
|
||||
];
|
||||
|
||||
@@ -11,5 +11,8 @@ export interface GlobalFlags {
|
||||
help: boolean;
|
||||
nonInteractive: boolean;
|
||||
async: boolean;
|
||||
consoleRegion?: string;
|
||||
consoleSite?: string;
|
||||
consoleSwitchAgent?: number;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
|
||||
function testConfig(overrides: Partial<Config> = {}): Config {
|
||||
return {
|
||||
region: "cn",
|
||||
baseUrl: "https://dashscope.aliyuncs.com",
|
||||
output: "json",
|
||||
timeout: 30,
|
||||
@@ -22,7 +21,6 @@ function testConfig(overrides: Partial<Config> = {}): 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();
|
||||
});
|
||||
|
||||
@@ -116,7 +116,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).
|
||||
|
||||
---
|
||||
|
||||
@@ -126,13 +126,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 |
|
||||
|
||||
---
|
||||
|
||||
@@ -175,7 +175,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
|
||||
|
||||
@@ -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 <topic>]`
|
||||
- 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`)
|
||||
|
||||
|
||||
@@ -73,12 +73,14 @@ bl app call --app-id abc123 --prompt "Start" --biz-params '{"key":"value"}'
|
||||
|
||||
#### Options
|
||||
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------- | ------ | -------- | ----------------------------------- |
|
||||
| `--name <name>` | string | no | Filter by app name (keyword search) |
|
||||
| `--page <n>` | number | no | Page number (default: 1) |
|
||||
| `--page-size <n>` | number | no | Results per page (default: 30) |
|
||||
| `--region <region>` | string | no | API region (default: cn-beijing) |
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------------------ | ------ | -------- | ------------------------------------- |
|
||||
| `--name <name>` | string | no | Filter by app name (keyword search) |
|
||||
| `--page <n>` | number | no | Page number (default: 1) |
|
||||
| `--page-size <n>` | number | no | Results per page (default: 30) |
|
||||
| `--console-region <region>` | string | no | Console region |
|
||||
| `--console-site <site>` | string | no | Console site: domestic, international |
|
||||
| `--console-switch-agent <uid>` | number | no | Switch agent UID |
|
||||
|
||||
#### Examples
|
||||
|
||||
|
||||
@@ -25,10 +25,11 @@ Index: [index.md](index.md)
|
||||
|
||||
#### Options
|
||||
|
||||
| Flag | Type | Required | Description |
|
||||
| ----------------- | ------- | -------- | ------------------------------------------------------------------------ |
|
||||
| `--api-key <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 <key>` | string | no | DashScope API key to store |
|
||||
| `--base-url <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 <region>` | string | no | Console region |
|
||||
| `--console-site <site>` | string | no | Console site: domestic, international |
|
||||
| `--console-switch-agent <uid>` | number | no | Switch agent UID |
|
||||
|
||||
#### Examples
|
||||
|
||||
|
||||
@@ -49,10 +49,10 @@ bl config export-schema --command "video generate"
|
||||
|
||||
#### Options
|
||||
|
||||
| Flag | Type | Required | Description |
|
||||
| ----------------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `--key <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 <value>` | string | no | Value to set |
|
||||
| Flag | Type | Required | Description |
|
||||
| ----------------- | ------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `--key <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 <value>` | string | no | Value to set |
|
||||
|
||||
#### Examples
|
||||
|
||||
|
||||
@@ -23,11 +23,13 @@ Index: [index.md](index.md)
|
||||
|
||||
#### Options
|
||||
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------- | ------ | -------- | ------------------------------------------------------------------------ |
|
||||
| `--api <api>` | string | yes | API name (e.g. zeldaEasy.broadscope-bailian.memory-library.getLibraries) |
|
||||
| `--data <json>` | string | yes | Request data as JSON string |
|
||||
| `--region <region>` | string | no | API region (default: cn-beijing) |
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------------------ | ------ | -------- | ------------------------------------------------------------------------ |
|
||||
| `--api <api>` | string | yes | API name (e.g. zeldaEasy.broadscope-bailian.memory-library.getLibraries) |
|
||||
| `--data <json>` | string | yes | Request data as JSON string |
|
||||
| `--console-region <region>` | string | no | Console region |
|
||||
| `--console-site <site>` | string | no | Console site: domestic, international |
|
||||
| `--console-switch-agent <uid>` | 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
|
||||
```
|
||||
|
||||
@@ -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 <key>` | string | no | API key |
|
||||
| `--region <region>` | string | no | API region: cn (default), us, intl |
|
||||
| `--base-url <url>` | string | no | API base URL |
|
||||
| `--output <format>` | string | no | Output format: text, json |
|
||||
| `--timeout <seconds>` | 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 <n>` | number | no | Run N parallel requests (default: 1) |
|
||||
| `--help` | boolean | no | Show help |
|
||||
| `--version` | boolean | no | Print version |
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------------------ | ------- | -------- | -------------------------------------------------------- |
|
||||
| `--api-key <key>` | string | no | API key |
|
||||
| `--base-url <url>` | string | no | API base URL |
|
||||
| `--output <format>` | string | no | Output format: text, json |
|
||||
| `--timeout <seconds>` | 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 <n>` | number | no | Run N parallel requests (default: 1) |
|
||||
| `--console-region <region>` | string | no | Console gateway region (e.g. cn-beijing, ap-southeast-1) |
|
||||
| `--console-site <site>` | string | no | Console site: domestic, international |
|
||||
| `--console-switch-agent <uid>` | number | no | Switch agent UID for delegated access |
|
||||
| `--help` | boolean | no | Show help |
|
||||
| `--version` | boolean | no | Print version |
|
||||
|
||||
## Notes
|
||||
|
||||
|
||||
@@ -57,13 +57,15 @@ bl mcp call market-cmapi00073529.SmartFundSelection --arg riskLevel=R3 --arg min
|
||||
|
||||
#### Options
|
||||
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------- | ------ | -------- | ---------------------------------------------------- |
|
||||
| `--name <text>` | string | no | Filter by server name (substring match) |
|
||||
| `--type <type>` | string | no | Server type: OFFICIAL \| PRIVATE (default: OFFICIAL) |
|
||||
| `--page <n>` | number | no | Page number (default: 1) |
|
||||
| `--page-size <n>` | number | no | Results per page (default: 30) |
|
||||
| `--region <region>` | string | no | API region (default: cn-beijing) |
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------------------ | ------ | -------- | ---------------------------------------------------- |
|
||||
| `--name <text>` | string | no | Filter by server name (substring match) |
|
||||
| `--type <type>` | string | no | Server type: OFFICIAL \| PRIVATE (default: OFFICIAL) |
|
||||
| `--page <n>` | number | no | Page number (default: 1) |
|
||||
| `--page-size <n>` | number | no | Results per page (default: 30) |
|
||||
| `--console-region <region>` | string | no | Console region |
|
||||
| `--console-site <site>` | string | no | Console site: domestic, international |
|
||||
| `--console-switch-agent <uid>` | number | no | Switch agent UID |
|
||||
|
||||
#### Examples
|
||||
|
||||
|
||||
@@ -26,11 +26,13 @@ Index: [index.md](index.md)
|
||||
|
||||
#### Options
|
||||
|
||||
| Flag | Type | Required | Description |
|
||||
| -------------------- | ------ | -------- | ----------------------------------------------- |
|
||||
| `--model <model>` | string | no | Model name(s), comma-separated |
|
||||
| `--period <minutes>` | string | no | Query usage for the last N minutes (default: 2) |
|
||||
| `--region <region>` | string | no | API region (default: cn-beijing) |
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------------------ | ------ | -------- | ----------------------------------------------- |
|
||||
| `--model <model>` | string | no | Model name(s), comma-separated |
|
||||
| `--period <minutes>` | string | no | Query usage for the last N minutes (default: 2) |
|
||||
| `--console-region <region>` | string | no | Console region |
|
||||
| `--console-site <site>` | string | no | Console site: domestic, international |
|
||||
| `--console-switch-agent <uid>` | number | no | Switch agent UID |
|
||||
|
||||
#### Examples
|
||||
|
||||
@@ -64,12 +66,14 @@ bl quota check --output json
|
||||
|
||||
#### Options
|
||||
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------- | ------ | -------- | -------------------------------- |
|
||||
| `--page <n>` | string | no | Page number (default: 1) |
|
||||
| `--page-size <n>` | string | no | Page size (default: 10) |
|
||||
| `--model <model>` | string | no | Filter by model name |
|
||||
| `--region <region>` | string | no | API region (default: cn-beijing) |
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------------------ | ------ | -------- | ------------------------------------- |
|
||||
| `--page <n>` | string | no | Page number (default: 1) |
|
||||
| `--page-size <n>` | string | no | Page size (default: 10) |
|
||||
| `--model <model>` | string | no | Filter by model name |
|
||||
| `--console-region <region>` | string | no | Console region |
|
||||
| `--console-site <site>` | string | no | Console site: domestic, international |
|
||||
| `--console-switch-agent <uid>` | number | no | Switch agent UID |
|
||||
|
||||
#### Examples
|
||||
|
||||
@@ -103,11 +107,13 @@ bl quota history --output json
|
||||
|
||||
#### Options
|
||||
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------- | ------- | -------- | ------------------------------------------- |
|
||||
| `--model <model>` | string | no | Model name(s), comma-separated |
|
||||
| `--all` | boolean | no | Show all models, not just self-service ones |
|
||||
| `--region <region>` | string | no | API region (default: cn-beijing) |
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------------------ | ------- | -------- | ------------------------------------------- |
|
||||
| `--model <model>` | string | no | Model name(s), comma-separated |
|
||||
| `--all` | boolean | no | Show all models, not just self-service ones |
|
||||
| `--console-region <region>` | string | no | Console region |
|
||||
| `--console-site <site>` | string | no | Console site: domestic, international |
|
||||
| `--console-switch-agent <uid>` | number | no | Switch agent UID |
|
||||
|
||||
#### Examples
|
||||
|
||||
@@ -141,12 +147,14 @@ bl quota list --output json
|
||||
|
||||
#### Options
|
||||
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------- | ------- | -------- | -------------------------------- |
|
||||
| `--model <model>` | string | yes | Model name (required) |
|
||||
| `--tpm <value>` | string | yes | Target TPM value (required) |
|
||||
| `--yes` | boolean | no | Skip downgrade confirmation |
|
||||
| `--region <region>` | string | no | API region (default: cn-beijing) |
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------------------ | ------- | -------- | ------------------------------------- |
|
||||
| `--model <model>` | string | yes | Model name (required) |
|
||||
| `--tpm <value>` | string | yes | Target TPM value (required) |
|
||||
| `--yes` | boolean | no | Skip downgrade confirmation |
|
||||
| `--console-region <region>` | string | no | Console region |
|
||||
| `--console-site <site>` | string | no | Console site: domestic, international |
|
||||
| `--console-switch-agent <uid>` | number | no | Switch agent UID |
|
||||
|
||||
#### Examples
|
||||
|
||||
|
||||
@@ -25,12 +25,14 @@ Index: [index.md](index.md)
|
||||
|
||||
#### Options
|
||||
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------- | ------ | -------- | ------------------------------------------------------------------------- |
|
||||
| `--model <model>` | string | no | Model name(s) to query, comma-separated for multiple; omit for all models |
|
||||
| `--expiring <days>` | string | no | Only show quotas expiring within N days |
|
||||
| `--sort <field>` | string | no | Sort by: remaining (ascending), expires (ascending) |
|
||||
| `--region <region>` | string | no | API region (default: cn-beijing) |
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------------------ | ------ | -------- | ------------------------------------------------------------------------- |
|
||||
| `--model <model>` | string | no | Model name(s) to query, comma-separated for multiple; omit for all models |
|
||||
| `--expiring <days>` | string | no | Only show quotas expiring within N days |
|
||||
| `--sort <field>` | string | no | Sort by: remaining (ascending), expires (ascending) |
|
||||
| `--console-region <region>` | string | no | Console region |
|
||||
| `--console-site <site>` | string | no | Console site: domestic, international |
|
||||
| `--console-switch-agent <uid>` | 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 <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 <region>` | string | no | API region (default: cn-beijing) |
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------------------ | ------- | -------- | ------------------------------------------- |
|
||||
| `--model <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 <region>` | string | no | Console region |
|
||||
| `--console-site <site>` | string | no | Console site: domestic, international |
|
||||
| `--console-switch-agent <uid>` | number | no | Switch agent UID |
|
||||
|
||||
#### Examples
|
||||
|
||||
@@ -116,13 +120,15 @@ bl usage freetier --off --all
|
||||
|
||||
#### Options
|
||||
|
||||
| Flag | Type | Required | Description |
|
||||
| --------------------- | ------ | -------- | ------------------------------------------------------ |
|
||||
| `--model <model>` | string | no | Model name(s), comma-separated; omit for overview |
|
||||
| `--days <days>` | string | no | Number of days (default: 7) |
|
||||
| `--type <type>` | string | no | Model type: Text, Vision, Multimodal, Audio, Embedding |
|
||||
| `--workspace-id <id>` | string | no | Workspace ID (env: BAILIAN_WORKSPACE_ID) |
|
||||
| `--region <region>` | string | no | API region (default: cn-beijing) |
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------------------ | ------ | -------- | ------------------------------------------------------ |
|
||||
| `--model <model>` | string | no | Model name(s), comma-separated; omit for overview |
|
||||
| `--days <days>` | string | no | Number of days (default: 7) |
|
||||
| `--type <type>` | string | no | Model type: Text, Vision, Multimodal, Audio, Embedding |
|
||||
| `--workspace-id <id>` | string | no | Workspace ID (env: BAILIAN_WORKSPACE_ID) |
|
||||
| `--console-region <region>` | string | no | Console region |
|
||||
| `--console-site <site>` | string | no | Console site: domestic, international |
|
||||
| `--console-switch-agent <uid>` | number | no | Switch agent UID |
|
||||
|
||||
#### Examples
|
||||
|
||||
|
||||
@@ -23,10 +23,12 @@ Index: [index.md](index.md)
|
||||
|
||||
#### Options
|
||||
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------- | ------ | -------- | -------------------------------- |
|
||||
| `--list <n>` | string | no | Limit number of results |
|
||||
| `--region <region>` | string | no | API region (default: cn-beijing) |
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------------------ | ------ | -------- | ------------------------------------- |
|
||||
| `--list <n>` | string | no | Limit number of results |
|
||||
| `--console-region <region>` | string | no | Console region |
|
||||
| `--console-site <site>` | string | no | Console site: domestic, international |
|
||||
| `--console-switch-agent <uid>` | number | no | Switch agent UID |
|
||||
|
||||
#### Examples
|
||||
|
||||
|
||||
Reference in New Issue
Block a user