diff --git a/packages/cli/src/commands/console/call.ts b/packages/cli/src/commands/console/call.ts index 4bf9ee6..d953a4f 100644 --- a/packages/cli/src/commands/console/call.ts +++ b/packages/cli/src/commands/console/call.ts @@ -1,6 +1,7 @@ import { defineCommand, callConsoleGateway, + effectiveConsoleGatewayConfig, resolveConsoleGatewayCredential, CONSOLE_GATEWAY_NO_TOKEN_MESSAGE, BailianError, @@ -58,7 +59,15 @@ export default defineCommand({ } if (config.dryRun) { - emitResult({ api, data, token: token ? token.slice(0, 8) + "..." : null }, format); + emitResult( + { + api, + data, + token: token ? token.slice(0, 8) + "..." : null, + ...effectiveConsoleGatewayConfig(config), + }, + format, + ); return; } diff --git a/packages/cli/src/commands/mcp/list.ts b/packages/cli/src/commands/mcp/list.ts index 1e6e747..6d39c71 100644 --- a/packages/cli/src/commands/mcp/list.ts +++ b/packages/cli/src/commands/mcp/list.ts @@ -1,6 +1,7 @@ import { defineCommand, callConsoleGateway, + effectiveConsoleGatewayConfig, resolveConsoleGatewayCredential, detectOutputFormat, BailianError, @@ -56,7 +57,7 @@ export default defineCommand({ }; if (config.dryRun) { - emitResult({ api: MCP_LIST_API, data }, format); + emitResult({ api: MCP_LIST_API, data, ...effectiveConsoleGatewayConfig(config) }, format); return; } diff --git a/packages/cli/src/commands/quota/check.ts b/packages/cli/src/commands/quota/check.ts index f00ab44..c6b6179 100644 --- a/packages/cli/src/commands/quota/check.ts +++ b/packages/cli/src/commands/quota/check.ts @@ -1,6 +1,7 @@ import { defineCommand, callConsoleGateway, + effectiveConsoleGatewayConfig, resolveConsoleGatewayCredential, detectOutputFormat, type Config, @@ -277,6 +278,7 @@ export default defineCommand({ emitResult( { apis: [MODEL_LIST_API, MONITOR_API], + ...effectiveConsoleGatewayConfig(config), }, format, ); diff --git a/packages/cli/tests/e2e/auth.e2e.test.ts b/packages/cli/tests/e2e/auth.e2e.test.ts index 3946e75..339383c 100644 --- a/packages/cli/tests/e2e/auth.e2e.test.ts +++ b/packages/cli/tests/e2e/auth.e2e.test.ts @@ -17,6 +17,7 @@ describe("e2e: auth", () => { const { stderr, exitCode } = await runCli(["auth", "login", "--help"]); expect(exitCode, stderr).toBe(0); expect(stderr).toMatch(/login|api-key/i); + expect(stderr).toMatch(/--console-site/); }); test("auth logout --help 正常退出", async () => { diff --git a/packages/cli/tests/e2e/console-flags.e2e.test.ts b/packages/cli/tests/e2e/console-flags.e2e.test.ts new file mode 100644 index 0000000..07ca49f --- /dev/null +++ b/packages/cli/tests/e2e/console-flags.e2e.test.ts @@ -0,0 +1,152 @@ +import { describe, expect, test } from "vite-plus/test"; +import { parseStdoutJson, runCli } from "./helpers.ts"; + +type ConsoleDryRunMeta = { + consoleRegion?: string; + consoleSite?: string; + consoleSwitchAgent?: number; +}; + +/** + * E2E for global console flags (`--console-region`, `--console-site`, + * `--console-switch-agent`) vs DashScope `--region`. + */ + +describe("e2e: console global flags", () => { + test("根帮助展示 --console-region / --console-site / --console-switch-agent", async () => { + const { stderr, exitCode } = await runCli(["--help"]); + expect(exitCode, stderr).toBe(0); + expect(stderr).toMatch(/--console-region/); + expect(stderr).toMatch(/--console-site/); + expect(stderr).toMatch(/--console-switch-agent/); + expect(stderr).toMatch(/--region.*cn.*us.*intl/i); + }); + + test("quota check --help 不重复命令级 region,并提示全局 flags", async () => { + const { stderr, exitCode } = await runCli(["quota", "check", "--help"]); + expect(exitCode, stderr).toBe(0); + expect(stderr).toMatch(/Global flags.*always available/i); + expect(stderr).toMatch(/--model /); + expect(stderr).toMatch(/--period /); + expect(stderr).not.toMatch(/API region \(default: cn-beijing\)/); + }); + + test("console call --help 不暴露命令级 region/site,示例使用 --console-region", async () => { + const { stderr, exitCode } = await runCli(["console", "call", "--help"]); + expect(exitCode, stderr).toBe(0); + expect(stderr).toMatch(/--api /); + expect(stderr).toMatch(/--data /); + expect(stderr).not.toMatch(/^\s*--region\s/m); + expect(stderr).not.toMatch(/^\s*--site\s/m); + expect(stderr).toMatch(/--console-region cn-beijing/); + }); + + test("auth login --help 描述 --console 与 --console-site 配合", async () => { + const { stderr, exitCode } = await runCli(["auth", "login", "--help"]); + expect(exitCode, stderr).toBe(0); + expect(stderr).toMatch(/--console-site/); + expect(stderr).toMatch(/--console.*console-site|console-site.*domestic|international/i); + }); + + test("console call --dry-run 默认 consoleRegion 为 cn-beijing", async () => { + const { stdout, stderr, exitCode } = await runCli([ + "console", + "call", + "--api", + "some.api.name", + "--data", + "{}", + "--dry-run", + "--non-interactive", + "--output", + "json", + ]); + expect(exitCode, stderr).toBe(0); + const data = parseStdoutJson(stdout); + expect(data.consoleRegion).toBe("cn-beijing"); + expect(data.consoleSite).toBe("domestic"); + }); + + test("console call --dry-run --console-region / --console-site / --console-switch-agent 透传", async () => { + const { stdout, stderr, exitCode } = await runCli([ + "console", + "call", + "--api", + "some.api.name", + "--data", + "{}", + "--dry-run", + "--non-interactive", + "--output", + "json", + "--console-region", + "ap-southeast-1", + "--console-site", + "international", + "--console-switch-agent", + "12345", + ]); + expect(exitCode, stderr).toBe(0); + const data = parseStdoutJson(stdout); + expect(data.consoleRegion).toBe("ap-southeast-1"); + expect(data.consoleSite).toBe("international"); + expect(data.consoleSwitchAgent).toBe(12345); + }); + + test("console call --dry-run --region cn-beijing 不改变 consoleRegion", async () => { + const { stdout, stderr, exitCode } = await runCli([ + "console", + "call", + "--api", + "some.api.name", + "--data", + "{}", + "--dry-run", + "--non-interactive", + "--output", + "json", + "--region", + "cn-beijing", + "--console-region", + "ap-southeast-1", + ]); + expect(exitCode, stderr).toBe(0); + const data = parseStdoutJson(stdout); + expect(data.consoleRegion).toBe("ap-southeast-1"); + }); + + test("mcp list --dry-run --console-region 透传", async () => { + const { stdout, stderr, exitCode } = await runCli([ + "mcp", + "list", + "--dry-run", + "--non-interactive", + "--output", + "json", + "--console-region", + "cn-hangzhou", + ]); + expect(exitCode, stderr).toBe(0); + const data = parseStdoutJson(stdout); + expect(data.consoleRegion).toBe("cn-hangzhou"); + }); + + test("quota check --dry-run --console-region 透传", async () => { + const { stdout, stderr, exitCode } = await runCli([ + "quota", + "check", + "--dry-run", + "--non-interactive", + "--output", + "json", + "--console-region", + "cn-hangzhou", + "--console-site", + "international", + ]); + expect(exitCode, stderr).toBe(0); + const data = parseStdoutJson(stdout); + expect(data.consoleRegion).toBe("cn-hangzhou"); + expect(data.consoleSite).toBe("international"); + }); +}); diff --git a/packages/cli/tests/e2e/mcp.e2e.test.ts b/packages/cli/tests/e2e/mcp.e2e.test.ts index 93eabf2..ee56cf4 100644 --- a/packages/cli/tests/e2e/mcp.e2e.test.ts +++ b/packages/cli/tests/e2e/mcp.e2e.test.ts @@ -88,7 +88,7 @@ describe("e2e: mcp", () => { }); test("mcp list --dry-run 自定义 --console-region 透传", async () => { - const { stderr, exitCode } = await runCli([ + const { stdout, stderr, exitCode } = await runCli([ "mcp", "list", "--dry-run", @@ -99,6 +99,8 @@ describe("e2e: mcp", () => { "cn-hangzhou", ]); expect(exitCode, stderr).toBe(0); + const data = parseStdoutJson<{ consoleRegion?: string }>(stdout); + expect(data.consoleRegion).toBe("cn-hangzhou"); }); test("mcp tools --dry-run 输出 /api/v1/mcps//mcp 形态 URL", async () => { diff --git a/packages/cli/tests/e2e/quota.e2e.test.ts b/packages/cli/tests/e2e/quota.e2e.test.ts index 19e537d..4e54fbb 100644 --- a/packages/cli/tests/e2e/quota.e2e.test.ts +++ b/packages/cli/tests/e2e/quota.e2e.test.ts @@ -228,11 +228,28 @@ describe.skipIf(!isConsoleE2EReady())("e2e: quota(Console)", () => { "json", ]); expect(exitCode, stderr).toBe(0); - const data = parseStdoutJson<{ apis?: string[] }>(stdout); + const data = parseStdoutJson<{ apis?: string[]; consoleRegion?: string }>(stdout); expect(data.apis).toContain( "zeldaHttp.dashscopeModel./zelda/api/v1/modelCenter/listFoundationModels", ); expect(data.apis).toContain("zeldaEasy.bailian-telemetry.monitor.getMonitorData"); + expect(data.consoleRegion).toBe("cn-beijing"); + }); + + test("quota check --dry-run --console-region 透传", async () => { + const { stdout, stderr, exitCode } = await runCli([ + "quota", + "check", + "--dry-run", + "--non-interactive", + "--output", + "json", + "--console-region", + "cn-hangzhou", + ]); + expect(exitCode, stderr).toBe(0); + const data = parseStdoutJson<{ consoleRegion?: string }>(stdout); + expect(data.consoleRegion).toBe("cn-hangzhou"); }); test("quota check 文本输出包含双行表头", async () => { diff --git a/packages/core/src/console/gateway.ts b/packages/core/src/console/gateway.ts index ffad27a..3a636db 100644 --- a/packages/core/src/console/gateway.ts +++ b/packages/core/src/console/gateway.ts @@ -35,6 +35,20 @@ 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; @@ -85,9 +99,11 @@ export async function callConsoleGateway( token: string | undefined, { api, data }: ConsoleGatewayRequest, ): Promise { - const effectiveRegion = config.consoleRegion ?? "cn-beijing"; - const effectiveSite = config.consoleSite ?? "domestic"; - const effectiveSwitchAgent = config.consoleSwitchAgent; + const { + consoleRegion: effectiveRegion, + consoleSite: effectiveSite, + consoleSwitchAgent: effectiveSwitchAgent, + } = effectiveConsoleGatewayConfig(config); const resolved = resolveGateway(effectiveRegion, effectiveSite); const gatewayBase = `https://${resolved.csGateway}`; diff --git a/packages/core/src/console/index.ts b/packages/core/src/console/index.ts index 61cf595..948e878 100644 --- a/packages/core/src/console/index.ts +++ b/packages/core/src/console/index.ts @@ -1,4 +1,4 @@ export type { ConsoleGatewayRequest, ConsoleSite } from "./gateway.ts"; -export { callConsoleGateway } from "./gateway.ts"; +export { callConsoleGateway, effectiveConsoleGatewayConfig } from "./gateway.ts"; export type { ModelListParams, ModelListResult } from "./models.ts"; export { fetchModelList } from "./models.ts"; diff --git a/packages/core/src/console/models.ts b/packages/core/src/console/models.ts index 70345c2..8366a2f 100644 --- a/packages/core/src/console/models.ts +++ b/packages/core/src/console/models.ts @@ -22,14 +22,7 @@ export async function fetchModelList( token: string, params: ModelListParams = {}, ): Promise { - const { - pageNo = 1, - pageSize = 50, - name = "", - providers = [], - capabilities = [], - region, - } = params; + const { pageNo = 1, pageSize = 50, name = "", providers = [], capabilities = [] } = params; const result = (await callConsoleGateway(config, token, { api: MODEL_LIST_API, @@ -46,7 +39,6 @@ export async function fetchModelList( contextWindows: [], }, }, - region, })) as any; const responseData = result?.data?.DataV2?.data ?? result?.data ?? {};