mirror of
https://github.com/modelstudioai/cli.git
synced 2026-09-14 19:49:23 +08:00
Merge pull request #74 from budiga/token-plan-openapi
Token plan openapi
This commit is contained in:
@@ -122,6 +122,12 @@ bl quota check # 查看当前用量 vs
|
||||
bl quota check --model qwen3.6-plus --period 5 # 查看最近 5 分钟用量
|
||||
bl quota request --model qwen3.6-plus --tpm 6000000 # 申请临时 TPM 提额
|
||||
bl quota history # 查看提额历史记录
|
||||
|
||||
# Token Plan 团队版管理(需 AK/SK,见下方认证说明)
|
||||
bl tokenplan seats # 查看订阅席位明细
|
||||
bl tokenplan add-member --account-name dev --org-id org_xxx
|
||||
bl tokenplan assign-seats --workspace-id ws_xxx --seat-type standard --account-id acc_xxx
|
||||
bl tokenplan create-key --account-id acc_xxx --workspace-id ws_xxx
|
||||
```
|
||||
|
||||
> 更多案例与使用场景:[阿里云百炼 CLI 官方主页](https://bailian.console.aliyun.com/cli?source_channel=cli_github&)
|
||||
@@ -151,9 +157,9 @@ bl text chat --api-key sk-xxxxx --message "你好"
|
||||
bl auth login --console
|
||||
```
|
||||
|
||||
### 阿里云 AK/SK(仅知识库检索)
|
||||
### 阿里云 AK/SK(知识库检索与 Token Plan)
|
||||
|
||||
`knowledge retrieve` 命令需要阿里云 AccessKey。前往 [RAM 控制台](https://ram.console.aliyun.com/manage/ak) 获取。
|
||||
`knowledge retrieve` 与 `tokenplan` 命令组需要阿里云 AccessKey。前往 [RAM 控制台](https://ram.console.aliyun.com/manage/ak) 获取。
|
||||
|
||||
> 建议:创建 RAM 子账号并授予最小权限,避免使用主账号 AK/SK。
|
||||
|
||||
|
||||
@@ -46,6 +46,10 @@ import quotaList from "./quota/list.ts";
|
||||
import quotaRequest from "./quota/request.ts";
|
||||
import quotaHistory from "./quota/history.ts";
|
||||
import quotaCheck from "./quota/check.ts";
|
||||
import tokenplanSeats from "./tokenplan/seats.ts";
|
||||
import tokenplanCreateKey from "./tokenplan/create-key.ts";
|
||||
import tokenplanAssignSeats from "./tokenplan/assign-seats.ts";
|
||||
import tokenplanAddMember from "./tokenplan/add-member.ts";
|
||||
|
||||
/** Command registry map (no dependency on registry.ts — safe for build-time import). */
|
||||
export const commands: Record<string, Command> = {
|
||||
@@ -94,5 +98,9 @@ export const commands: Record<string, Command> = {
|
||||
"quota request": quotaRequest,
|
||||
"quota history": quotaHistory,
|
||||
"quota check": quotaCheck,
|
||||
"tokenplan seats": tokenplanSeats,
|
||||
"tokenplan create-key": tokenplanCreateKey,
|
||||
"tokenplan assign-seats": tokenplanAssignSeats,
|
||||
"tokenplan add-member": tokenplanAddMember,
|
||||
update: update,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
import {
|
||||
defineCommand,
|
||||
detectOutputFormat,
|
||||
type Config,
|
||||
type GlobalFlags,
|
||||
BailianError,
|
||||
ExitCode,
|
||||
} from "bailian-cli-core";
|
||||
import { emitResult, emitBare } from "../../output/output.ts";
|
||||
import { padEnd } from "../../output/cjk-width.ts";
|
||||
import type { AddOrganizationMemberResponse } from "./types.ts";
|
||||
import {
|
||||
TOKEN_PLAN_AK_OPTIONS,
|
||||
TOKEN_PLAN_COMMON_QUERY_OPTIONS,
|
||||
appendCommonQueryParams,
|
||||
callTokenPlanApi,
|
||||
prepareTokenPlanRequest,
|
||||
resolveTokenPlanCredentials,
|
||||
type TokenPlanQueryParams,
|
||||
} from "./utils.ts";
|
||||
|
||||
const API_ACTION = "AddOrganizationMember";
|
||||
const API_PATH = "/tokenplan/organization/member-additions";
|
||||
|
||||
const DEFAULT_ORG_ROLE = "ORG_MEMBER";
|
||||
|
||||
export default defineCommand({
|
||||
name: "tokenplan add-member",
|
||||
description: "Add a member to a Token Plan organization",
|
||||
usage: "bl tokenplan add-member --account-name <name> --org-id <id> [flags]",
|
||||
options: [
|
||||
{ flag: "--account-name <name>", description: "Member display name", required: true },
|
||||
{ flag: "--org-id <id>", description: "Organization ID", required: true },
|
||||
{
|
||||
flag: "--org-role-code <code>",
|
||||
description: "Organization role: ORG_ADMIN or ORG_MEMBER (default: ORG_MEMBER)",
|
||||
},
|
||||
{
|
||||
flag: "--spec-type <type>",
|
||||
description: "Seat tier to assign on creation: standard, pro, or max",
|
||||
},
|
||||
...TOKEN_PLAN_COMMON_QUERY_OPTIONS,
|
||||
...TOKEN_PLAN_AK_OPTIONS,
|
||||
],
|
||||
examples: [
|
||||
"bl tokenplan add-member --account-name dev_user --org-id org_123",
|
||||
"bl tokenplan add-member --account-name admin_user --org-id org_123 --org-role-code ORG_ADMIN",
|
||||
"bl tokenplan add-member --account-name member1 --org-id org_123 --spec-type standard",
|
||||
],
|
||||
async run(config: Config, flags: GlobalFlags) {
|
||||
const format = detectOutputFormat(config.output);
|
||||
const credentials = resolveTokenPlanCredentials(config, flags);
|
||||
|
||||
const accountName = flags.accountName as string | undefined;
|
||||
const orgId = flags.orgId as string | undefined;
|
||||
if (!accountName) {
|
||||
throw new BailianError("Missing required argument --account-name.", ExitCode.USAGE);
|
||||
}
|
||||
if (!orgId) {
|
||||
throw new BailianError("Missing required argument --org-id.", ExitCode.USAGE);
|
||||
}
|
||||
|
||||
const queryParams = buildQueryParams(flags);
|
||||
|
||||
if (config.dryRun) {
|
||||
const { endpoint, queryParams: query } = prepareTokenPlanRequest(
|
||||
config,
|
||||
API_PATH,
|
||||
queryParams,
|
||||
);
|
||||
emitResult({ endpoint, query }, format);
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await callTokenPlanApi<AddOrganizationMemberResponse>({
|
||||
config,
|
||||
credentials,
|
||||
action: API_ACTION,
|
||||
path: API_PATH,
|
||||
method: "POST",
|
||||
queryParams,
|
||||
});
|
||||
|
||||
if (config.quiet || format === "text") {
|
||||
emitTextMember(data);
|
||||
} else {
|
||||
emitResult(data, format);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
function buildQueryParams(flags: GlobalFlags): TokenPlanQueryParams {
|
||||
const params: TokenPlanQueryParams = {};
|
||||
|
||||
if (flags.accountName) params.AccountName = flags.accountName as string;
|
||||
if (flags.orgId) params.OrgId = flags.orgId as string;
|
||||
params.OrgRoleCode =
|
||||
typeof flags.orgRoleCode === "string" && flags.orgRoleCode.length > 0
|
||||
? flags.orgRoleCode
|
||||
: DEFAULT_ORG_ROLE;
|
||||
if (flags.specType) params.SpecType = flags.specType as string;
|
||||
appendCommonQueryParams(params, flags);
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
function emitTextMember(data: AddOrganizationMemberResponse): void {
|
||||
const item = data.Data;
|
||||
if (!item) {
|
||||
emitBare("Member added.");
|
||||
return;
|
||||
}
|
||||
|
||||
emitBare(`${padEnd("AccountId", 14)} ${item.AccountId ?? "-"}`);
|
||||
emitBare(`${padEnd("SeatAssigned", 14)} ${String(item.SeatAssigned ?? "-")}`);
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* ACS3-HMAC-SHA256 signing for ModelStudio Token Plan POP APIs (query-string style).
|
||||
*
|
||||
* Extends the core ROA signer with canonical query string support required by
|
||||
* Token Plan endpoints that pass parameters in the URL query.
|
||||
*/
|
||||
|
||||
import { createHmac, createHash, randomUUID } from "crypto";
|
||||
|
||||
export interface TokenPlanAkSignConfig {
|
||||
accessKeyId: string;
|
||||
accessKeySecret: string;
|
||||
action: string;
|
||||
version: string;
|
||||
body: string;
|
||||
host: string;
|
||||
pathname: string;
|
||||
method?: string;
|
||||
/** ACS3 canonical query string (sorted, encoded, no leading `?`). Empty for POST body-only APIs. */
|
||||
queryString?: string;
|
||||
}
|
||||
|
||||
/** Build ACS3 canonical query string from POP query parameters. */
|
||||
export function buildCanonicalQuery(params: Record<string, string | string[] | undefined>): string {
|
||||
const pairs: Array<[string, string]> = [];
|
||||
for (const [key, value] of Object.entries(params)) {
|
||||
if (value === undefined || value === "") continue;
|
||||
if (Array.isArray(value)) {
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
const v = value[i];
|
||||
if (v !== "") pairs.push([`${key}.${i + 1}`, v]);
|
||||
}
|
||||
} else {
|
||||
pairs.push([key, value]);
|
||||
}
|
||||
}
|
||||
pairs.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
|
||||
return pairs.map(([k, v]) => `${encodeRFC3986(k)}=${encodeRFC3986(v)}`).join("&");
|
||||
}
|
||||
|
||||
function encodeRFC3986(str: string): string {
|
||||
return encodeURIComponent(str).replace(
|
||||
/[!'()*]/g,
|
||||
(c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`,
|
||||
);
|
||||
}
|
||||
|
||||
export function signTokenPlanRequest(cfg: TokenPlanAkSignConfig): Record<string, string> {
|
||||
const method = cfg.method ?? "POST";
|
||||
const now = new Date();
|
||||
const dateISO = now.toISOString().replace(/\.\d{3}Z$/, "Z");
|
||||
const nonce = randomUUID();
|
||||
|
||||
const hashedBody = sha256Hex(cfg.body);
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
host: cfg.host,
|
||||
"x-acs-action": cfg.action,
|
||||
"x-acs-version": cfg.version,
|
||||
"x-acs-date": dateISO,
|
||||
"x-acs-signature-nonce": nonce,
|
||||
"x-acs-content-sha256": hashedBody,
|
||||
"content-type": "application/json",
|
||||
};
|
||||
|
||||
const signedHeaderKeys = Object.keys(headers)
|
||||
.filter((k) => k === "host" || k === "content-type" || k.startsWith("x-acs-"))
|
||||
.sort();
|
||||
|
||||
const canonicalHeaders = signedHeaderKeys.map((k) => `${k}:${headers[k]}`).join("\n") + "\n";
|
||||
|
||||
const signedHeadersStr = signedHeaderKeys.join(";");
|
||||
|
||||
const queryString = cfg.queryString ?? "";
|
||||
|
||||
const canonicalRequest = [
|
||||
method,
|
||||
cfg.pathname,
|
||||
queryString,
|
||||
canonicalHeaders,
|
||||
signedHeadersStr,
|
||||
hashedBody,
|
||||
].join("\n");
|
||||
|
||||
const algorithm = "ACS3-HMAC-SHA256";
|
||||
const hashedCanonical = sha256Hex(canonicalRequest);
|
||||
const stringToSign = `${algorithm}\n${hashedCanonical}`;
|
||||
|
||||
const signature = hmacSHA256Hex(cfg.accessKeySecret, stringToSign);
|
||||
|
||||
headers["authorization"] =
|
||||
`${algorithm} Credential=${cfg.accessKeyId},SignedHeaders=${signedHeadersStr},Signature=${signature}`;
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
function sha256Hex(data: string): string {
|
||||
return createHash("sha256").update(data, "utf8").digest("hex");
|
||||
}
|
||||
|
||||
function hmacSHA256Hex(key: string, data: string): string {
|
||||
return createHmac("sha256", key).update(data, "utf8").digest("hex");
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
import {
|
||||
defineCommand,
|
||||
detectOutputFormat,
|
||||
type Config,
|
||||
type GlobalFlags,
|
||||
BailianError,
|
||||
ExitCode,
|
||||
} from "bailian-cli-core";
|
||||
import { emitResult, emitBare } from "../../output/output.ts";
|
||||
import type { BatchAssignSeatsResponse } from "./types.ts";
|
||||
import {
|
||||
TOKEN_PLAN_AK_OPTIONS,
|
||||
TOKEN_PLAN_COMMON_QUERY_OPTIONS,
|
||||
TOKEN_PLAN_WORKSPACE_OPTION,
|
||||
appendCommonQueryParams,
|
||||
callTokenPlanApi,
|
||||
prepareTokenPlanRequest,
|
||||
requireWorkspaceId,
|
||||
resolveTokenPlanCredentials,
|
||||
type TokenPlanQueryParams,
|
||||
} from "./utils.ts";
|
||||
|
||||
const API_ACTION = "BatchAssignSeats";
|
||||
const API_PATH = "/tokenplan/subscription/seat-assignments";
|
||||
|
||||
export default defineCommand({
|
||||
name: "tokenplan assign-seats",
|
||||
description: "Batch assign Token Plan seats to members",
|
||||
usage:
|
||||
"bl tokenplan assign-seats --workspace-id <id> --seat-type <type> --account-id <id> [flags]",
|
||||
options: [
|
||||
TOKEN_PLAN_WORKSPACE_OPTION,
|
||||
{
|
||||
flag: "--seat-type <type>",
|
||||
description: "Seat tier: standard, pro, or max",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
flag: "--account-id <id>",
|
||||
description: "Target member account ID (repeatable)",
|
||||
type: "array",
|
||||
},
|
||||
...TOKEN_PLAN_COMMON_QUERY_OPTIONS,
|
||||
{
|
||||
flag: "--locale <locale>",
|
||||
description: "Language: zh-CN or en-US",
|
||||
},
|
||||
...TOKEN_PLAN_AK_OPTIONS,
|
||||
],
|
||||
examples: [
|
||||
"bl tokenplan assign-seats --workspace-id ws_456 --seat-type standard --account-id acc_123",
|
||||
"bl tokenplan assign-seats --workspace-id ws_456 --seat-type pro --account-id acc_1 --account-id acc_2",
|
||||
],
|
||||
async run(config: Config, flags: GlobalFlags) {
|
||||
const format = detectOutputFormat(config.output);
|
||||
const credentials = resolveTokenPlanCredentials(config, flags);
|
||||
|
||||
const workspaceId = requireWorkspaceId(config, flags);
|
||||
const seatType = flags.seatType as string | undefined;
|
||||
if (!seatType) {
|
||||
throw new BailianError("Missing required argument --seat-type.", ExitCode.USAGE);
|
||||
}
|
||||
|
||||
const accountIds = flags.accountId as string[] | undefined;
|
||||
if (!accountIds || accountIds.length === 0) {
|
||||
throw new BailianError("Missing required argument --account-id.", ExitCode.USAGE);
|
||||
}
|
||||
|
||||
const queryParams = buildQueryParams(flags, workspaceId);
|
||||
|
||||
if (config.dryRun) {
|
||||
const { endpoint, queryParams: query } = prepareTokenPlanRequest(
|
||||
config,
|
||||
API_PATH,
|
||||
queryParams,
|
||||
);
|
||||
emitResult({ endpoint, query }, format);
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await callTokenPlanApi<BatchAssignSeatsResponse>({
|
||||
config,
|
||||
credentials,
|
||||
action: API_ACTION,
|
||||
path: API_PATH,
|
||||
method: "POST",
|
||||
queryParams,
|
||||
});
|
||||
|
||||
if (config.quiet || format === "text") {
|
||||
emitBare("Seats assigned successfully.");
|
||||
} else {
|
||||
emitResult(data, format);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
function buildQueryParams(flags: GlobalFlags, workspaceId: string): TokenPlanQueryParams {
|
||||
const params: TokenPlanQueryParams = {};
|
||||
|
||||
params.WorkspaceId = workspaceId;
|
||||
if (flags.seatType) params.SeatType = flags.seatType as string;
|
||||
appendCommonQueryParams(params, flags);
|
||||
if (flags.locale) params.Locale = flags.locale as string;
|
||||
|
||||
const accountIds = flags.accountId as string[] | undefined;
|
||||
if (accountIds && accountIds.length > 0) {
|
||||
params.AccountIds = accountIds;
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
import {
|
||||
defineCommand,
|
||||
detectOutputFormat,
|
||||
type Config,
|
||||
type GlobalFlags,
|
||||
BailianError,
|
||||
ExitCode,
|
||||
} from "bailian-cli-core";
|
||||
import { emitResult, emitBare } from "../../output/output.ts";
|
||||
import { padEnd } from "../../output/cjk-width.ts";
|
||||
import type { CreateTokenPlanKeyResponse } from "./types.ts";
|
||||
import {
|
||||
TOKEN_PLAN_AK_OPTIONS,
|
||||
TOKEN_PLAN_COMMON_QUERY_OPTIONS,
|
||||
TOKEN_PLAN_WORKSPACE_OPTION,
|
||||
appendCommonQueryParams,
|
||||
callTokenPlanApi,
|
||||
prepareTokenPlanRequest,
|
||||
requireWorkspaceId,
|
||||
resolveTokenPlanCredentials,
|
||||
type TokenPlanQueryParams,
|
||||
} from "./utils.ts";
|
||||
|
||||
const API_ACTION = "CreateTokenPlanKey";
|
||||
const API_PATH = "/tokenplan/api-keys";
|
||||
|
||||
export default defineCommand({
|
||||
name: "tokenplan create-key",
|
||||
description: "Create a Token Plan API key for a seat",
|
||||
usage: "bl tokenplan create-key --account-id <id> --workspace-id <id> [flags]",
|
||||
options: [
|
||||
{ flag: "--account-id <id>", description: "Target member account ID", required: true },
|
||||
TOKEN_PLAN_WORKSPACE_OPTION,
|
||||
{ flag: "--description <text>", description: "API key description" },
|
||||
...TOKEN_PLAN_COMMON_QUERY_OPTIONS,
|
||||
...TOKEN_PLAN_AK_OPTIONS,
|
||||
],
|
||||
examples: [
|
||||
"bl tokenplan create-key --account-id acc_123 --workspace-id ws_456",
|
||||
"bl tokenplan create-key --account-id acc_123 --workspace-id ws_456 --description 'Dev key'",
|
||||
],
|
||||
async run(config: Config, flags: GlobalFlags) {
|
||||
const format = detectOutputFormat(config.output);
|
||||
const credentials = resolveTokenPlanCredentials(config, flags);
|
||||
|
||||
const accountId = flags.accountId as string | undefined;
|
||||
const workspaceId = requireWorkspaceId(config, flags);
|
||||
if (!accountId) {
|
||||
throw new BailianError("Missing required argument --account-id.", ExitCode.USAGE);
|
||||
}
|
||||
|
||||
const queryParams = buildQueryParams(flags, { accountId, workspaceId });
|
||||
|
||||
if (config.dryRun) {
|
||||
const { endpoint, queryParams: query } = prepareTokenPlanRequest(
|
||||
config,
|
||||
API_PATH,
|
||||
queryParams,
|
||||
);
|
||||
emitResult({ endpoint, query }, format);
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await callTokenPlanApi<CreateTokenPlanKeyResponse>({
|
||||
config,
|
||||
credentials,
|
||||
action: API_ACTION,
|
||||
path: API_PATH,
|
||||
method: "POST",
|
||||
queryParams,
|
||||
});
|
||||
|
||||
if (config.quiet || format === "text") {
|
||||
emitTextKey(data);
|
||||
} else {
|
||||
emitResult(data, format);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
function buildQueryParams(
|
||||
flags: GlobalFlags,
|
||||
resolved: { accountId: string; workspaceId: string },
|
||||
): TokenPlanQueryParams {
|
||||
const params: TokenPlanQueryParams = {};
|
||||
|
||||
params.AccountId = resolved.accountId;
|
||||
params.WorkspaceId = resolved.workspaceId;
|
||||
if (flags.description) params.Description = flags.description as string;
|
||||
appendCommonQueryParams(params, flags);
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
function emitTextKey(data: CreateTokenPlanKeyResponse): void {
|
||||
const item = data.Data;
|
||||
if (!item) {
|
||||
emitBare("API key created.");
|
||||
return;
|
||||
}
|
||||
|
||||
emitBare(`${padEnd("ApiKeyId", 14)} ${item.ApiKeyId ?? "-"}`);
|
||||
emitBare(`${padEnd("MaskedApiKey", 14)} ${item.MaskedApiKey ?? "-"}`);
|
||||
if (item.Description) {
|
||||
emitBare(`${padEnd("Description", 14)} ${item.Description}`);
|
||||
}
|
||||
if (item.PlainApiKey) {
|
||||
emitBare("");
|
||||
emitBare(`PlainApiKey (shown once): ${item.PlainApiKey}`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
import {
|
||||
defineCommand,
|
||||
detectOutputFormat,
|
||||
type Config,
|
||||
type GlobalFlags,
|
||||
BailianError,
|
||||
ExitCode,
|
||||
} from "bailian-cli-core";
|
||||
import { emitResult, emitBare } from "../../output/output.ts";
|
||||
import { padEnd } from "../../output/cjk-width.ts";
|
||||
import type { GetSubscriptionSeatDetailsResponse, TokenPlanSeatDetail } from "./types.ts";
|
||||
import {
|
||||
TOKEN_PLAN_AK_OPTIONS,
|
||||
TOKEN_PLAN_COMMON_QUERY_OPTIONS,
|
||||
appendCommonQueryParams,
|
||||
callTokenPlanApi,
|
||||
prepareTokenPlanRequest,
|
||||
resolveTokenPlanCredentials,
|
||||
type TokenPlanQueryParams,
|
||||
} from "./utils.ts";
|
||||
|
||||
const API_ACTION = "GetSubscriptionSeatDetails";
|
||||
const API_PATH = "/tokenplan/subscription/seat-detail";
|
||||
|
||||
export default defineCommand({
|
||||
name: "tokenplan seats",
|
||||
description: "List Token Plan subscription seat details",
|
||||
usage: "bl tokenplan seats [flags]",
|
||||
options: [
|
||||
{ flag: "--page-no <n>", description: "Page number (default: 1)", type: "number" },
|
||||
{ flag: "--page-size <n>", description: "Page size (default: 10)", type: "number" },
|
||||
...TOKEN_PLAN_COMMON_QUERY_OPTIONS,
|
||||
{
|
||||
flag: "--status <status>",
|
||||
description:
|
||||
"Seat status filter (repeatable): CREATING, NORMAL, LIMIT, RELEASE, STOP, REFUNDED",
|
||||
type: "array",
|
||||
},
|
||||
{
|
||||
flag: "--status-list-str <json>",
|
||||
description: "StatusList as JSON string, e.g. '[\"NORMAL\"]'",
|
||||
},
|
||||
{ flag: "--seat-id <id>", description: "Filter by seat ID" },
|
||||
{
|
||||
flag: "--seat-type <type>",
|
||||
description: "Seat tier: standard, pro, or max",
|
||||
},
|
||||
{
|
||||
flag: "--query-assigned <bool>",
|
||||
description: "Filter by assignment: true=assigned, false=unassigned",
|
||||
},
|
||||
...TOKEN_PLAN_AK_OPTIONS,
|
||||
],
|
||||
examples: [
|
||||
"bl tokenplan seats",
|
||||
"bl tokenplan seats --page-size 20 --status NORMAL",
|
||||
"bl tokenplan seats --query-assigned true --seat-type standard",
|
||||
],
|
||||
async run(config: Config, flags: GlobalFlags) {
|
||||
const format = detectOutputFormat(config.output);
|
||||
const credentials = resolveTokenPlanCredentials(config, flags);
|
||||
const queryParams = buildQueryParams(flags);
|
||||
|
||||
if (config.dryRun) {
|
||||
const { endpoint, queryParams: query } = prepareTokenPlanRequest(
|
||||
config,
|
||||
API_PATH,
|
||||
queryParams,
|
||||
);
|
||||
emitResult({ endpoint, query }, format);
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await callTokenPlanApi<GetSubscriptionSeatDetailsResponse>({
|
||||
config,
|
||||
credentials,
|
||||
action: API_ACTION,
|
||||
path: API_PATH,
|
||||
method: "GET",
|
||||
queryParams,
|
||||
});
|
||||
|
||||
const items = data.Data?.Items ?? [];
|
||||
if (config.quiet || format === "text") {
|
||||
emitTextSeats(items, data.Data?.Total, data.Data?.PageNo, data.Data?.PageSize);
|
||||
} else {
|
||||
emitResult(data, format);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
function buildQueryParams(flags: GlobalFlags): TokenPlanQueryParams {
|
||||
const params: TokenPlanQueryParams = {};
|
||||
|
||||
if (flags.pageNo !== undefined) params.PageNo = String(flags.pageNo as number);
|
||||
if (flags.pageSize !== undefined) params.PageSize = String(flags.pageSize as number);
|
||||
appendCommonQueryParams(params, flags);
|
||||
if (flags.statusListStr) params.StatusListStr = flags.statusListStr as string;
|
||||
|
||||
const status = flags.status as string[] | undefined;
|
||||
if (status && status.length > 0) {
|
||||
params.StatusList = status;
|
||||
}
|
||||
|
||||
if (flags.seatId) params.SeatId = flags.seatId as string;
|
||||
if (flags.seatType) params.SeatType = flags.seatType as string;
|
||||
|
||||
if (typeof flags.queryAssigned === "string" && flags.queryAssigned.length > 0) {
|
||||
const val = flags.queryAssigned.toLowerCase();
|
||||
if (val !== "true" && val !== "false") {
|
||||
throw new BailianError("--query-assigned must be 'true' or 'false'.", ExitCode.USAGE);
|
||||
}
|
||||
params.QueryAssigned = val;
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
function emitTextSeats(
|
||||
items: TokenPlanSeatDetail[],
|
||||
total?: number,
|
||||
pageNo?: number,
|
||||
pageSize?: number,
|
||||
): void {
|
||||
if (items.length === 0) {
|
||||
emitBare("No seats found.");
|
||||
return;
|
||||
}
|
||||
|
||||
const header = [
|
||||
padEnd("SeatId", 18),
|
||||
padEnd("Type", 10),
|
||||
padEnd("Status", 10),
|
||||
padEnd("Assigned", 12),
|
||||
padEnd("Account", 20),
|
||||
].join(" ");
|
||||
emitBare(header);
|
||||
emitBare("-".repeat(header.length));
|
||||
|
||||
for (const item of items) {
|
||||
const row = [
|
||||
padEnd(item.SeatId ?? "-", 18),
|
||||
padEnd(item.SpecType ?? "-", 10),
|
||||
padEnd(item.Status ?? "-", 10),
|
||||
padEnd(item.AssignedStatus ?? "-", 12),
|
||||
padEnd(item.AccountName ?? item.AccountId ?? "-", 20),
|
||||
].join(" ");
|
||||
emitBare(row);
|
||||
}
|
||||
|
||||
if (total !== undefined) {
|
||||
emitBare("");
|
||||
emitBare(
|
||||
`Total: ${total}${pageNo !== undefined ? ` | Page: ${pageNo}` : ""}${pageSize !== undefined ? ` | PageSize: ${pageSize}` : ""}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// ---- Token Plan / ModelStudio POP (2026-02-10) ----
|
||||
|
||||
export interface TokenPlanSeatEquity {
|
||||
EquityType?: string;
|
||||
CycleInstanceId?: string;
|
||||
CycleStartTime?: number;
|
||||
CycleEndTime?: number;
|
||||
CycleTotalValue?: number;
|
||||
CycleSurplusValue?: number;
|
||||
CycleVersion?: number;
|
||||
}
|
||||
|
||||
export interface TokenPlanSeatDetail {
|
||||
InstanceCode?: string;
|
||||
EquityList?: TokenPlanSeatEquity[];
|
||||
EndTime?: number;
|
||||
SeatId?: string;
|
||||
SpecType?: string;
|
||||
StartTime?: number;
|
||||
AssignedStatus?: string;
|
||||
AccountId?: string;
|
||||
AccountName?: string;
|
||||
AccountEmail?: string;
|
||||
Status?: string;
|
||||
}
|
||||
|
||||
export interface GetSubscriptionSeatDetailsResponse {
|
||||
Success?: boolean;
|
||||
Code?: string;
|
||||
Message?: string;
|
||||
Data?: {
|
||||
Items?: TokenPlanSeatDetail[];
|
||||
Total?: number;
|
||||
PageNo?: number;
|
||||
PageSize?: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface CreateTokenPlanKeyResponse {
|
||||
Success?: boolean;
|
||||
Code?: string;
|
||||
Message?: string;
|
||||
Data?: {
|
||||
ApiKeyId?: string;
|
||||
PlainApiKey?: string;
|
||||
MaskedApiKey?: string;
|
||||
Description?: string;
|
||||
CreatedAt?: string;
|
||||
SourceId?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface BatchAssignSeatsResponse {
|
||||
Success?: boolean;
|
||||
Code?: string;
|
||||
Message?: string;
|
||||
}
|
||||
|
||||
export interface AddOrganizationMemberResponse {
|
||||
Success?: boolean;
|
||||
Code?: string;
|
||||
Message?: string;
|
||||
RequestId?: string;
|
||||
HttpStatusCode?: number;
|
||||
Data?: {
|
||||
AccountId?: string;
|
||||
SeatAssigned?: boolean;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
import {
|
||||
REGIONS,
|
||||
maskToken,
|
||||
trackingHeaders,
|
||||
type Config,
|
||||
type GlobalFlags,
|
||||
type OptionDef,
|
||||
type Region,
|
||||
BailianError,
|
||||
ExitCode,
|
||||
} from "bailian-cli-core";
|
||||
import { buildCanonicalQuery, signTokenPlanRequest } from "./ak-sign.ts";
|
||||
|
||||
export const TOKEN_PLAN_API_VERSION = "2026-02-10";
|
||||
|
||||
export const TOKEN_PLAN_AK_OPTIONS: OptionDef[] = [
|
||||
{ flag: "--access-key-id <key>", description: "Alibaba Cloud Access Key ID (deprecated)" },
|
||||
{
|
||||
flag: "--access-key-secret <key>",
|
||||
description: "Alibaba Cloud Access Key Secret (deprecated)",
|
||||
},
|
||||
];
|
||||
|
||||
export const TOKEN_PLAN_COMMON_QUERY_OPTIONS: OptionDef[] = [
|
||||
{
|
||||
flag: "--caller-uac-account-id <id>",
|
||||
description: "Caller UAC account ID",
|
||||
},
|
||||
{
|
||||
flag: "--namespace-id <id>",
|
||||
description: "Product namespace ID (Token Plan default: namespace-1)",
|
||||
},
|
||||
];
|
||||
|
||||
export const TOKEN_PLAN_WORKSPACE_OPTION: OptionDef = {
|
||||
flag: "--workspace-id <id>",
|
||||
description: "Workspace ID (env: BAILIAN_WORKSPACE_ID, config: workspace_id)",
|
||||
};
|
||||
|
||||
const MODEL_STUDIO_HOSTS: Partial<Record<Region, string>> = {
|
||||
cn: "modelstudio.cn-beijing.aliyuncs.com",
|
||||
intl: "modelstudio.ap-southeast-1.aliyuncs.com",
|
||||
};
|
||||
|
||||
function resolveRegion(baseUrl: string): Region {
|
||||
for (const [region, url] of Object.entries(REGIONS) as Array<[Region, string]>) {
|
||||
if (baseUrl === url || baseUrl.startsWith(`${url}/`)) return region;
|
||||
}
|
||||
return "cn";
|
||||
}
|
||||
|
||||
/** ModelStudio POP OpenAPI host for the given DashScope base URL preset. */
|
||||
function modelStudioHost(baseUrl: string): string {
|
||||
const region = resolveRegion(baseUrl);
|
||||
return MODEL_STUDIO_HOSTS[region] ?? MODEL_STUDIO_HOSTS.cn!;
|
||||
}
|
||||
|
||||
export interface TokenPlanApiResponse {
|
||||
Success?: boolean;
|
||||
Code?: string;
|
||||
Message?: string;
|
||||
}
|
||||
|
||||
export type TokenPlanQueryParams = Record<string, string | string[] | undefined>;
|
||||
|
||||
export function resolveTokenPlanCredentials(
|
||||
config: Config,
|
||||
flags: GlobalFlags,
|
||||
): { accessKeyId: string; accessKeySecret: string } {
|
||||
const accessKeyId = (flags.accessKeyId as string) || config.accessKeyId;
|
||||
const accessKeySecret = (flags.accessKeySecret as string) || config.accessKeySecret;
|
||||
|
||||
if (!accessKeyId || !accessKeySecret) {
|
||||
throw new BailianError(
|
||||
"No credentials found.\n" +
|
||||
"Set ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET.",
|
||||
ExitCode.AUTH,
|
||||
);
|
||||
}
|
||||
|
||||
return { accessKeyId, accessKeySecret };
|
||||
}
|
||||
|
||||
export function requireWorkspaceId(config: Config, flags: GlobalFlags): string {
|
||||
const workspaceId = (flags.workspaceId as string) || config.workspaceId;
|
||||
if (!workspaceId) {
|
||||
throw new BailianError(
|
||||
"Missing workspace ID.\n" +
|
||||
"Set via: --workspace-id flag, env: BAILIAN_WORKSPACE_ID, or config: bl config set workspace_id <id>",
|
||||
ExitCode.USAGE,
|
||||
);
|
||||
}
|
||||
return workspaceId;
|
||||
}
|
||||
|
||||
export function appendCommonQueryParams(params: TokenPlanQueryParams, flags: GlobalFlags): void {
|
||||
if (flags.callerUacAccountId) params.CallerUacAccountId = flags.callerUacAccountId as string;
|
||||
if (flags.namespaceId) params.NamespaceId = flags.namespaceId as string;
|
||||
}
|
||||
|
||||
export function prepareTokenPlanRequest(
|
||||
config: Config,
|
||||
path: string,
|
||||
queryParams: TokenPlanQueryParams,
|
||||
): { host: string; endpoint: string; queryString: string; queryParams: TokenPlanQueryParams } {
|
||||
const queryString = buildCanonicalQuery(queryParams);
|
||||
const host = modelStudioHost(config.baseUrl);
|
||||
const endpoint = `https://${host}${path}${queryString ? `?${queryString}` : ""}`;
|
||||
return { host, endpoint, queryString, queryParams };
|
||||
}
|
||||
|
||||
export async function callTokenPlanApi<T extends TokenPlanApiResponse>(opts: {
|
||||
config: Config;
|
||||
credentials: { accessKeyId: string; accessKeySecret: string };
|
||||
action: string;
|
||||
path: string;
|
||||
method: "GET" | "POST";
|
||||
queryParams: TokenPlanQueryParams;
|
||||
}): Promise<T> {
|
||||
const { config, credentials, action, path, method, queryParams } = opts;
|
||||
const { host, endpoint, queryString } = prepareTokenPlanRequest(config, path, queryParams);
|
||||
|
||||
const headers = signTokenPlanRequest({
|
||||
accessKeyId: credentials.accessKeyId,
|
||||
accessKeySecret: credentials.accessKeySecret,
|
||||
action,
|
||||
version: TOKEN_PLAN_API_VERSION,
|
||||
body: "",
|
||||
host,
|
||||
pathname: path,
|
||||
method,
|
||||
queryString,
|
||||
});
|
||||
|
||||
if (config.verbose) {
|
||||
process.stderr.write(`> ${method} ${endpoint}\n`);
|
||||
process.stderr.write(`> AK: ${maskToken(credentials.accessKeyId)}\n`);
|
||||
}
|
||||
|
||||
const timeoutMs = config.timeout * 1000;
|
||||
const res = await fetch(endpoint, {
|
||||
method,
|
||||
headers: { ...headers, ...trackingHeaders() },
|
||||
signal: AbortSignal.timeout(timeoutMs),
|
||||
});
|
||||
|
||||
if (config.verbose) {
|
||||
process.stderr.write(`< ${res.status} ${res.statusText}\n`);
|
||||
}
|
||||
|
||||
const data = (await res.json()) as T;
|
||||
|
||||
if (!res.ok || data.Success === false) {
|
||||
throw new BailianError(
|
||||
`${data.Code || res.status} - ${data.Message || res.statusText}`,
|
||||
ExitCode.GENERAL,
|
||||
);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
@@ -8,54 +8,58 @@ Use this index for the full quick index and global flags.
|
||||
|
||||
## Quick index
|
||||
|
||||
| Command | Description | Detail |
|
||||
| -------------------------- | ----------------------------------------------------------------------------------------------------- | ---------------------------- |
|
||||
| `bl advisor recommend` | Recommend the best models for your use case (intent analysis → candidate recall → LLM ranking) | [advisor.md](advisor.md) |
|
||||
| `bl app call` | Call a Bailian application (agent or workflow) | [app.md](app.md) |
|
||||
| `bl app list` | List Bailian applications | [app.md](app.md) |
|
||||
| `bl auth login` | Authenticate with API key or console browser login (credentials can coexist) | [auth.md](auth.md) |
|
||||
| `bl auth logout` | Clear stored credentials | [auth.md](auth.md) |
|
||||
| `bl auth status` | Show current authentication state | [auth.md](auth.md) |
|
||||
| `bl config export-schema` | Export all (or one) CLI command(s) as Anthropic/OpenAI-compatible JSON tool schemas | [config.md](config.md) |
|
||||
| `bl config set` | Set a config value | [config.md](config.md) |
|
||||
| `bl config show` | Display current configuration | [config.md](config.md) |
|
||||
| `bl console call` | Call a Bailian console API via the CLI gateway | [console.md](console.md) |
|
||||
| `bl file upload` | Upload a local file to DashScope temporary storage (48h) | [file.md](file.md) |
|
||||
| `bl image edit` | Edit an existing image with text instructions (Qwen-Image) | [image.md](image.md) |
|
||||
| `bl image generate` | Generate images (Qwen-Image / wan2.x) | [image.md](image.md) |
|
||||
| `bl knowledge retrieve` | Retrieve from a Bailian knowledge base | [knowledge.md](knowledge.md) |
|
||||
| `bl mcp call` | Call a tool on an MCP server (tools/call) | [mcp.md](mcp.md) |
|
||||
| `bl mcp list` | List MCP servers activated under your Bailian account | [mcp.md](mcp.md) |
|
||||
| `bl mcp tools` | List tools exposed by an MCP server (tools/list) | [mcp.md](mcp.md) |
|
||||
| `bl memory add` | Add memory from messages or custom content | [memory.md](memory.md) |
|
||||
| `bl memory delete` | Delete a memory node | [memory.md](memory.md) |
|
||||
| `bl memory list` | List memory nodes for a user | [memory.md](memory.md) |
|
||||
| `bl memory profile create` | Create a user profile schema for memory profiling | [memory.md](memory.md) |
|
||||
| `bl memory profile get` | Get user profile by schema ID and user ID | [memory.md](memory.md) |
|
||||
| `bl memory search` | Search memory nodes by query or messages | [memory.md](memory.md) |
|
||||
| `bl memory update` | Update a memory node content | [memory.md](memory.md) |
|
||||
| `bl omni` | Multimodal chat with text + audio output (Qwen-Omni) | [omni.md](omni.md) |
|
||||
| `bl pipeline run` | Run a pipeline workflow definition | [pipeline.md](pipeline.md) |
|
||||
| `bl pipeline validate` | Validate a pipeline definition without executing | [pipeline.md](pipeline.md) |
|
||||
| `bl quota check` | Check current usage against rate limits | [quota.md](quota.md) |
|
||||
| `bl quota history` | View quota change history | [quota.md](quota.md) |
|
||||
| `bl quota list` | View model RPM/TPM rate limits | [quota.md](quota.md) |
|
||||
| `bl quota request` | Request a temporary quota increase | [quota.md](quota.md) |
|
||||
| `bl search web` | Search the web using DashScope MCP WebSearch service | [search.md](search.md) |
|
||||
| `bl speech recognize` | Recognize speech from audio files (FunAudio-ASR) | [speech.md](speech.md) |
|
||||
| `bl speech synthesize` | Synthesize speech from text (CosyVoice TTS) | [speech.md](speech.md) |
|
||||
| `bl text chat` | Send a chat completion (OpenAI compatible, DashScope) | [text.md](text.md) |
|
||||
| `bl update` | Update bl to the latest version | [update.md](update.md) |
|
||||
| `bl usage free` | Query free-tier quota for models (all models if --model is omitted) | [usage.md](usage.md) |
|
||||
| `bl usage freetier` | Enable or disable auto-stop for free-tier models. Enables by default; use --off to disable | [usage.md](usage.md) |
|
||||
| `bl usage stats` | Query model usage statistics | [usage.md](usage.md) |
|
||||
| `bl video download` | Download a completed video by task ID | [video.md](video.md) |
|
||||
| `bl video edit` | Edit a video with happyhorse-1.0-video-edit (style transfer, object replacement, etc.) | [video.md](video.md) |
|
||||
| `bl video generate` | Generate a video from text or image (happyhorse-1.1-t2v / happyhorse-1.1-i2v / wan2.6-t2v) | [video.md](video.md) |
|
||||
| `bl video ref` | Reference-to-video generation (happyhorse-1.1-r2v / wan2.6-r2v): multi-subject, multi-shot with voice | [video.md](video.md) |
|
||||
| `bl video task get` | Query async task status | [video.md](video.md) |
|
||||
| `bl vision describe` | Describe an image or video using Qwen-VL | [vision.md](vision.md) |
|
||||
| `bl workspace list` | List all workspaces | [workspace.md](workspace.md) |
|
||||
| Command | Description | Detail |
|
||||
| --------------------------- | ----------------------------------------------------------------------------------------------------- | ---------------------------- |
|
||||
| `bl advisor recommend` | Recommend the best models for your use case (intent analysis → candidate recall → LLM ranking) | [advisor.md](advisor.md) |
|
||||
| `bl app call` | Call a Bailian application (agent or workflow) | [app.md](app.md) |
|
||||
| `bl app list` | List Bailian applications | [app.md](app.md) |
|
||||
| `bl auth login` | Authenticate with API key or console browser login (credentials can coexist) | [auth.md](auth.md) |
|
||||
| `bl auth logout` | Clear stored credentials | [auth.md](auth.md) |
|
||||
| `bl auth status` | Show current authentication state | [auth.md](auth.md) |
|
||||
| `bl config export-schema` | Export all (or one) CLI command(s) as Anthropic/OpenAI-compatible JSON tool schemas | [config.md](config.md) |
|
||||
| `bl config set` | Set a config value | [config.md](config.md) |
|
||||
| `bl config show` | Display current configuration | [config.md](config.md) |
|
||||
| `bl console call` | Call a Bailian console API via the CLI gateway | [console.md](console.md) |
|
||||
| `bl file upload` | Upload a local file to DashScope temporary storage (48h) | [file.md](file.md) |
|
||||
| `bl image edit` | Edit an existing image with text instructions (Qwen-Image) | [image.md](image.md) |
|
||||
| `bl image generate` | Generate images (Qwen-Image / wan2.x) | [image.md](image.md) |
|
||||
| `bl knowledge retrieve` | Retrieve from a Bailian knowledge base | [knowledge.md](knowledge.md) |
|
||||
| `bl mcp call` | Call a tool on an MCP server (tools/call) | [mcp.md](mcp.md) |
|
||||
| `bl mcp list` | List MCP servers activated under your Bailian account | [mcp.md](mcp.md) |
|
||||
| `bl mcp tools` | List tools exposed by an MCP server (tools/list) | [mcp.md](mcp.md) |
|
||||
| `bl memory add` | Add memory from messages or custom content | [memory.md](memory.md) |
|
||||
| `bl memory delete` | Delete a memory node | [memory.md](memory.md) |
|
||||
| `bl memory list` | List memory nodes for a user | [memory.md](memory.md) |
|
||||
| `bl memory profile create` | Create a user profile schema for memory profiling | [memory.md](memory.md) |
|
||||
| `bl memory profile get` | Get user profile by schema ID and user ID | [memory.md](memory.md) |
|
||||
| `bl memory search` | Search memory nodes by query or messages | [memory.md](memory.md) |
|
||||
| `bl memory update` | Update a memory node content | [memory.md](memory.md) |
|
||||
| `bl omni` | Multimodal chat with text + audio output (Qwen-Omni) | [omni.md](omni.md) |
|
||||
| `bl pipeline run` | Run a pipeline workflow definition | [pipeline.md](pipeline.md) |
|
||||
| `bl pipeline validate` | Validate a pipeline definition without executing | [pipeline.md](pipeline.md) |
|
||||
| `bl quota check` | Check current usage against rate limits | [quota.md](quota.md) |
|
||||
| `bl quota history` | View quota change history | [quota.md](quota.md) |
|
||||
| `bl quota list` | View model RPM/TPM rate limits | [quota.md](quota.md) |
|
||||
| `bl quota request` | Request a temporary quota increase | [quota.md](quota.md) |
|
||||
| `bl search web` | Search the web using DashScope MCP WebSearch service | [search.md](search.md) |
|
||||
| `bl speech recognize` | Recognize speech from audio files (FunAudio-ASR) | [speech.md](speech.md) |
|
||||
| `bl speech synthesize` | Synthesize speech from text (CosyVoice TTS) | [speech.md](speech.md) |
|
||||
| `bl text chat` | Send a chat completion (OpenAI compatible, DashScope) | [text.md](text.md) |
|
||||
| `bl tokenplan add-member` | Add a member to a Token Plan organization | [tokenplan.md](tokenplan.md) |
|
||||
| `bl tokenplan assign-seats` | Batch assign Token Plan seats to members | [tokenplan.md](tokenplan.md) |
|
||||
| `bl tokenplan create-key` | Create a Token Plan API key for a seat | [tokenplan.md](tokenplan.md) |
|
||||
| `bl tokenplan seats` | List Token Plan subscription seat details | [tokenplan.md](tokenplan.md) |
|
||||
| `bl update` | Update bl to the latest version | [update.md](update.md) |
|
||||
| `bl usage free` | Query free-tier quota for models (all models if --model is omitted) | [usage.md](usage.md) |
|
||||
| `bl usage freetier` | Enable or disable auto-stop for free-tier models. Enables by default; use --off to disable | [usage.md](usage.md) |
|
||||
| `bl usage stats` | Query model usage statistics | [usage.md](usage.md) |
|
||||
| `bl video download` | Download a completed video by task ID | [video.md](video.md) |
|
||||
| `bl video edit` | Edit a video with happyhorse-1.0-video-edit (style transfer, object replacement, etc.) | [video.md](video.md) |
|
||||
| `bl video generate` | Generate a video from text or image (happyhorse-1.1-t2v / happyhorse-1.1-i2v / wan2.6-t2v) | [video.md](video.md) |
|
||||
| `bl video ref` | Reference-to-video generation (happyhorse-1.1-r2v / wan2.6-r2v): multi-subject, multi-shot with voice | [video.md](video.md) |
|
||||
| `bl video task get` | Query async task status | [video.md](video.md) |
|
||||
| `bl vision describe` | Describe an image or video using Qwen-VL | [vision.md](vision.md) |
|
||||
| `bl workspace list` | List all workspaces | [workspace.md](workspace.md) |
|
||||
|
||||
## By group
|
||||
|
||||
@@ -77,6 +81,7 @@ Use this index for the full quick index and global flags.
|
||||
| `search` | `web` | [search.md](search.md) |
|
||||
| `speech` | `recognize`, `synthesize` | [speech.md](speech.md) |
|
||||
| `text` | `chat` | [text.md](text.md) |
|
||||
| `tokenplan` | `add-member`, `assign-seats`, `create-key`, `seats` | [tokenplan.md](tokenplan.md) |
|
||||
| `update` | `(root)` | [update.md](update.md) |
|
||||
| `usage` | `free`, `freetier`, `stats` | [usage.md](usage.md) |
|
||||
| `video` | `download`, `edit`, `generate`, `ref`, `task get` | [video.md](video.md) |
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
# `bl tokenplan` commands
|
||||
|
||||
> Auto-generated from `packages/cli/src/commands/catalog.ts`. Do not edit by hand.
|
||||
> Regenerate: `pnpm --filter bailian-cli run generate:reference`.
|
||||
|
||||
Index: [index.md](index.md)
|
||||
|
||||
## Commands in this group
|
||||
|
||||
| Command | Description |
|
||||
| --------------------------- | ----------------------------------------- |
|
||||
| `bl tokenplan add-member` | Add a member to a Token Plan organization |
|
||||
| `bl tokenplan assign-seats` | Batch assign Token Plan seats to members |
|
||||
| `bl tokenplan create-key` | Create a Token Plan API key for a seat |
|
||||
| `bl tokenplan seats` | List Token Plan subscription seat details |
|
||||
|
||||
## Command details
|
||||
|
||||
### `bl tokenplan add-member`
|
||||
|
||||
| Field | Value |
|
||||
| --------------- | --------------------------------------------------------------------- |
|
||||
| **Name** | `tokenplan add-member` |
|
||||
| **Description** | Add a member to a Token Plan organization |
|
||||
| **Usage** | `bl tokenplan add-member --account-name <name> --org-id <id> [flags]` |
|
||||
|
||||
#### Options
|
||||
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------------------ | ------ | -------- | ---------------------------------------------------------------- |
|
||||
| `--account-name <name>` | string | yes | Member display name |
|
||||
| `--org-id <id>` | string | yes | Organization ID |
|
||||
| `--org-role-code <code>` | string | no | Organization role: ORG_ADMIN or ORG_MEMBER (default: ORG_MEMBER) |
|
||||
| `--spec-type <type>` | string | no | Seat tier to assign on creation: standard, pro, or max |
|
||||
| `--caller-uac-account-id <id>` | string | no | Caller UAC account ID |
|
||||
| `--namespace-id <id>` | string | no | Product namespace ID (Token Plan default: namespace-1) |
|
||||
| `--access-key-id <key>` | string | no | Alibaba Cloud Access Key ID (deprecated) |
|
||||
| `--access-key-secret <key>` | string | no | Alibaba Cloud Access Key Secret (deprecated) |
|
||||
|
||||
#### Examples
|
||||
|
||||
```bash
|
||||
bl tokenplan add-member --account-name dev_user --org-id org_123
|
||||
```
|
||||
|
||||
```bash
|
||||
bl tokenplan add-member --account-name admin_user --org-id org_123 --org-role-code ORG_ADMIN
|
||||
```
|
||||
|
||||
```bash
|
||||
bl tokenplan add-member --account-name member1 --org-id org_123 --spec-type standard
|
||||
```
|
||||
|
||||
### `bl tokenplan assign-seats`
|
||||
|
||||
| Field | Value |
|
||||
| --------------- | -------------------------------------------------------------------------------------------- |
|
||||
| **Name** | `tokenplan assign-seats` |
|
||||
| **Description** | Batch assign Token Plan seats to members |
|
||||
| **Usage** | `bl tokenplan assign-seats --workspace-id <id> --seat-type <type> --account-id <id> [flags]` |
|
||||
|
||||
#### Options
|
||||
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------------------ | ------ | -------- | -------------------------------------------------------------- |
|
||||
| `--workspace-id <id>` | string | no | Workspace ID (env: BAILIAN_WORKSPACE_ID, config: workspace_id) |
|
||||
| `--seat-type <type>` | string | yes | Seat tier: standard, pro, or max |
|
||||
| `--account-id <id>` | array | no | Target member account ID (repeatable) |
|
||||
| `--caller-uac-account-id <id>` | string | no | Caller UAC account ID |
|
||||
| `--namespace-id <id>` | string | no | Product namespace ID (Token Plan default: namespace-1) |
|
||||
| `--locale <locale>` | string | no | Language: zh-CN or en-US |
|
||||
| `--access-key-id <key>` | string | no | Alibaba Cloud Access Key ID (deprecated) |
|
||||
| `--access-key-secret <key>` | string | no | Alibaba Cloud Access Key Secret (deprecated) |
|
||||
|
||||
#### Examples
|
||||
|
||||
```bash
|
||||
bl tokenplan assign-seats --workspace-id ws_456 --seat-type standard --account-id acc_123
|
||||
```
|
||||
|
||||
```bash
|
||||
bl tokenplan assign-seats --workspace-id ws_456 --seat-type pro --account-id acc_1 --account-id acc_2
|
||||
```
|
||||
|
||||
### `bl tokenplan create-key`
|
||||
|
||||
| Field | Value |
|
||||
| --------------- | ----------------------------------------------------------------------- |
|
||||
| **Name** | `tokenplan create-key` |
|
||||
| **Description** | Create a Token Plan API key for a seat |
|
||||
| **Usage** | `bl tokenplan create-key --account-id <id> --workspace-id <id> [flags]` |
|
||||
|
||||
#### Options
|
||||
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------------------ | ------ | -------- | -------------------------------------------------------------- |
|
||||
| `--account-id <id>` | string | yes | Target member account ID |
|
||||
| `--workspace-id <id>` | string | no | Workspace ID (env: BAILIAN_WORKSPACE_ID, config: workspace_id) |
|
||||
| `--description <text>` | string | no | API key description |
|
||||
| `--caller-uac-account-id <id>` | string | no | Caller UAC account ID |
|
||||
| `--namespace-id <id>` | string | no | Product namespace ID (Token Plan default: namespace-1) |
|
||||
| `--access-key-id <key>` | string | no | Alibaba Cloud Access Key ID (deprecated) |
|
||||
| `--access-key-secret <key>` | string | no | Alibaba Cloud Access Key Secret (deprecated) |
|
||||
|
||||
#### Examples
|
||||
|
||||
```bash
|
||||
bl tokenplan create-key --account-id acc_123 --workspace-id ws_456
|
||||
```
|
||||
|
||||
```bash
|
||||
bl tokenplan create-key --account-id acc_123 --workspace-id ws_456 --description 'Dev key'
|
||||
```
|
||||
|
||||
### `bl tokenplan seats`
|
||||
|
||||
| Field | Value |
|
||||
| --------------- | ----------------------------------------- |
|
||||
| **Name** | `tokenplan seats` |
|
||||
| **Description** | List Token Plan subscription seat details |
|
||||
| **Usage** | `bl tokenplan seats [flags]` |
|
||||
|
||||
#### Options
|
||||
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------------------ | ------ | -------- | --------------------------------------------------------------------------------- |
|
||||
| `--page-no <n>` | number | no | Page number (default: 1) |
|
||||
| `--page-size <n>` | number | no | Page size (default: 10) |
|
||||
| `--caller-uac-account-id <id>` | string | no | Caller UAC account ID |
|
||||
| `--namespace-id <id>` | string | no | Product namespace ID (Token Plan default: namespace-1) |
|
||||
| `--status <status>` | array | no | Seat status filter (repeatable): CREATING, NORMAL, LIMIT, RELEASE, STOP, REFUNDED |
|
||||
| `--status-list-str <json>` | string | no | StatusList as JSON string, e.g. '["NORMAL"]' |
|
||||
| `--seat-id <id>` | string | no | Filter by seat ID |
|
||||
| `--seat-type <type>` | string | no | Seat tier: standard, pro, or max |
|
||||
| `--query-assigned <bool>` | string | no | Filter by assignment: true=assigned, false=unassigned |
|
||||
| `--access-key-id <key>` | string | no | Alibaba Cloud Access Key ID (deprecated) |
|
||||
| `--access-key-secret <key>` | string | no | Alibaba Cloud Access Key Secret (deprecated) |
|
||||
|
||||
#### Examples
|
||||
|
||||
```bash
|
||||
bl tokenplan seats
|
||||
```
|
||||
|
||||
```bash
|
||||
bl tokenplan seats --page-size 20 --status NORMAL
|
||||
```
|
||||
|
||||
```bash
|
||||
bl tokenplan seats --query-assigned true --seat-type standard
|
||||
```
|
||||
Reference in New Issue
Block a user