Skip to content

Commit 95eb07d

Browse files
committed
refactor(auth): centralize credential resolution into authStage + Client
Move all credential handling out of commands into one place. authStage resolves the credential for the command's declared `auth` and bakes it into `ctx.client`, gating (throw) when missing; commands reach the network only through `ctx.client` and never touch tokens or baseUrl. - add Client (request/requestJson/uploadFile/mcp/console/url) wrapping the token + baseUrl; commands call it instead of self-resolving - run(config, flags) → run(ctx) + CommandContext; migrate all 45 commands - split domains: model = pure api-key (drop access-token fallback), console = config.json only (drop DASHSCOPE_ACCESS_TOKEN env) - consolidate env reads in loadConfig; CredentialSource = flag | env | config; priority flag > env > config - endpoints return paths (xxxPath) instead of full URLs; baseUrl owned by Client - auth status now uses describeAuth - video/download: auth "none" → "apiKey" (it needs the model API) - dedupe fetchModelList behind an injected console-call function - remove ensureApiKey/ensure-key.ts, prompt.ts + isInteractive, and the old resolveCredential/resolveConsoleGatewayCredential resolvers - tests: adapt auth.e2e to the new auth status shape; drop the DASHSCOPE_ACCESS_TOKEN branch from console-readiness gates
1 parent f9bf36c commit 95eb07d

77 files changed

Lines changed: 696 additions & 1072 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/cli/tests/e2e/auth.e2e.test.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -152,12 +152,10 @@ describe("e2e: auth", () => {
152152
expect(exitCode, stderr).toBe(0);
153153
const data = parseStdoutJson<{
154154
authenticated?: boolean;
155-
api_key?: { configured?: boolean };
156-
dashscope_commands?: { method?: string };
155+
api_key?: { source?: string; masked?: string; base_url?: string };
157156
}>(stdout);
158157
expect(data.authenticated).toBe(true);
159-
expect(data.api_key?.configured).toBe(true);
160-
expect(data.dashscope_commands?.method).toBeDefined();
158+
expect(data.api_key?.source).toBeDefined();
161159
});
162160

163161
test.skipIf(!isDashScopeE2EReady())(
@@ -174,11 +172,9 @@ describe("e2e: auth", () => {
174172
"https://dashscope.aliyuncs.com",
175173
]);
176174
expect(exitCode, stderr).toBe(0);
177-
const data = parseStdoutJson<{ authenticated?: boolean; dashscope_commands?: unknown }>(
178-
stdout,
179-
);
175+
const data = parseStdoutJson<{ authenticated?: boolean; api_key?: unknown }>(stdout);
180176
expect(data.authenticated).toBe(true);
181-
expect(data.dashscope_commands).toBeDefined();
177+
expect(data.api_key).toBeDefined();
182178
},
183179
);
184180
});

packages/cli/tests/e2e/quota.e2e.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { readConfigFile } from "bailian-cli-core";
44

55
function isConsoleE2EReady(): boolean {
66
if (!isBailianE2EEnabled()) return false;
7-
if (process.env.DASHSCOPE_ACCESS_TOKEN?.trim()) return true;
87
try {
98
const config = readConfigFile();
109
return typeof config.access_token === "string" && config.access_token.length > 0;

packages/cli/tests/e2e/usage-free.e2e.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { readConfigFile } from "bailian-cli-core";
44

55
function isConsoleE2EReady(): boolean {
66
if (!isBailianE2EEnabled()) return false;
7-
if (process.env.DASHSCOPE_ACCESS_TOKEN?.trim()) return true;
87
try {
98
const config = readConfigFile();
109
return typeof config.access_token === "string" && config.access_token.length > 0;

packages/cli/tests/e2e/usage-stats.e2e.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { readConfigFile } from "bailian-cli-core";
44

55
function isConsoleE2EReady(): boolean {
66
if (!isBailianE2EEnabled()) return false;
7-
if (process.env.DASHSCOPE_ACCESS_TOKEN?.trim()) return true;
87
try {
98
const config = readConfigFile();
109
return typeof config.access_token === "string" && config.access_token.length > 0;

packages/commands/src/commands/advisor/recommend.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,8 @@ export default defineCommand({
230230
'--message "Low-cost high-concurrency online customer service" --output json',
231231
'--message "Long document summarization" --dry-run',
232232
],
233-
async run(config, flags) {
233+
async run(ctx) {
234+
const { config, flags } = ctx;
234235
const userInput = flags.message;
235236

236237
const top = 3;

packages/commands/src/commands/app/call.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import {
22
defineCommand,
3-
request,
4-
requestJson,
5-
appCompletionEndpoint,
3+
appCompletionPath,
64
parseSSE,
75
detectOutputFormat,
86
type AppCompletionRequest,
@@ -65,7 +63,8 @@ export default defineCommand({
6563
'--app-id abc123 --prompt "Search for materials" --pipeline-ids pipe1,pipe2',
6664
'--app-id abc123 --prompt "Start" --biz-params \'{"key":"value"}\'',
6765
],
68-
async run(config, flags) {
66+
async run(ctx) {
67+
const { config, flags } = ctx;
6968
const appId = flags.appId;
7069
const prompt = flags.prompt;
7170

@@ -121,16 +120,14 @@ export default defineCommand({
121120
}
122121

123122
if (config.dryRun) {
124-
emitResult({ endpoint: appCompletionEndpoint(config.baseUrl, appId), request: body }, format);
123+
emitResult({ endpoint: ctx.client.url(appCompletionPath(appId)), request: body }, format);
125124
return;
126125
}
127126

128-
const url = appCompletionEndpoint(config.baseUrl, appId);
129-
130127
if (shouldStream) {
131128
const headers: Record<string, string> = { "X-DashScope-SSE": "enable" };
132-
const res = await request(config, {
133-
url,
129+
const res = await ctx.client.request({
130+
path: appCompletionPath(appId),
134131
method: "POST",
135132
body,
136133
headers,
@@ -188,8 +185,8 @@ export default defineCommand({
188185
process.stdout.write("\n");
189186
}
190187
} else {
191-
const response = await requestJson<AppCompletionResponse>(config, {
192-
url,
188+
const response = await ctx.client.requestJson<AppCompletionResponse>({
189+
path: appCompletionPath(appId),
193190
method: "POST",
194191
body,
195192
});

packages/commands/src/commands/app/list.ts

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
import {
2-
defineCommand,
3-
callConsoleGateway,
4-
resolveConsoleGatewayCredential,
5-
detectOutputFormat,
6-
} from "bailian-cli-core";
1+
import { defineCommand, detectOutputFormat } from "bailian-cli-core";
72
import { emitResult } from "bailian-cli-runtime";
83

94
const APP_LIST_API = "zeldaEasy.broadscope-bailian.app-control.list";
@@ -37,14 +32,13 @@ export default defineCommand({
3732
consoleSwitchAgent: { type: "number", valueHint: "<uid>", description: "Switch agent UID" },
3833
},
3934
exampleArgs: ["", "--name customer service", "--page 2 --page-size 10", "--output json"],
40-
async run(config, flags) {
35+
async run(ctx) {
36+
const { config, flags } = ctx;
4137
const name = flags.name || "";
4238
const pageNo = flags.page || 1;
4339
const pageSize = flags.pageSize || 30;
4440
const format = detectOutputFormat(config.output);
4541

46-
const credential = await resolveConsoleGatewayCredential(config);
47-
4842
const data = {
4943
reqDTO: {
5044
name,
@@ -57,14 +51,11 @@ export default defineCommand({
5751
};
5852

5953
if (config.dryRun) {
60-
emitResult({ api: APP_LIST_API, data, token: credential.token.slice(0, 8) + "..." }, format);
54+
emitResult({ api: APP_LIST_API, data }, format);
6155
return;
6256
}
6357

64-
const result = (await callConsoleGateway(config, credential.token, {
65-
api: APP_LIST_API,
66-
data,
67-
})) as any;
58+
const result = await ctx.client.console<any>(APP_LIST_API, data);
6859

6960
const list: unknown[] = result?.data?.DataV2?.data?.data?.list ?? [];
7061
const total: number = result?.data?.DataV2?.data?.data?.total ?? 0;

packages/commands/src/commands/auth/login-console.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import http from "node:http";
55
import {
66
BailianError,
77
ExitCode,
8-
chatEndpoint,
8+
chatPath,
99
getConfigPath,
1010
readConfigFile,
1111
requestJson,
@@ -406,7 +406,7 @@ export async function validateAndPersistApiKey(
406406
process.stderr.write("Testing key... ");
407407
const testConfig = { ...config, apiKey: key, baseUrl };
408408
const requestOpts = {
409-
url: chatEndpoint(testConfig.baseUrl),
409+
url: testConfig.baseUrl + chatPath(),
410410
method: "POST",
411411
timeout: Math.min(config.timeout, 30),
412412
body: {

packages/commands/src/commands/auth/login.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ export default defineCommand({
2626
},
2727
exampleArgs: ["--api-key sk-xxxxx", "--console"],
2828
validate: (f) => (!f.console && !f.apiKey ? "Provide --api-key or --console" : undefined),
29-
async run(config, flags) {
29+
async run(ctx) {
30+
const { config, flags } = ctx;
3031
if (flags.console) {
3132
if (config.dryRun) {
3233
emitBare(

packages/commands/src/commands/auth/logout.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ export default defineCommand({
2727
yes: { type: "switch", description: "Skip confirmation prompt" },
2828
},
2929
exampleArgs: ["", "--console", "--dry-run", "--yes"],
30-
async run(config, flags) {
30+
async run(ctx) {
31+
const { config, flags } = ctx;
3132
const file = readConfigFile();
3233

3334
if (flags.console) {

0 commit comments

Comments
 (0)