mirror of
https://github.com/modelstudioai/cli.git
synced 2026-09-14 19:49:23 +08:00
feat(bootstrap): add command to initialize Bailian workspace and activate postpaid services
This commit is contained in:
@@ -74,6 +74,7 @@ import {
|
||||
tokenPlanCreateKey,
|
||||
tokenPlanAssignSeats,
|
||||
tokenPlanAddMember,
|
||||
bootstrap,
|
||||
} from "bailian-cli-commands";
|
||||
|
||||
// Full bailian-cli product: every command, exposed under the `bl` binary.
|
||||
@@ -156,4 +157,5 @@ export const commands: Record<string, AnyCommand> = {
|
||||
"token-plan create-key": tokenPlanCreateKey,
|
||||
"token-plan assign-seats": tokenPlanAssignSeats,
|
||||
"token-plan add-member": tokenPlanAddMember,
|
||||
bootstrap: bootstrap,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
import { defineCommand, detectOutputFormat, BailianError, ExitCode } from "bailian-cli-core";
|
||||
import { emitResult, emitBare } from "bailian-cli-runtime";
|
||||
|
||||
const API = {
|
||||
loginInfo: "zeldaEasy.cornerstone-portal.cs-console.loginInfo",
|
||||
initSpace: "zeldaEasy.bailian-dash-workspace.space.initSpace",
|
||||
queryBuyResult: "zeldaEasy.broadscope-bailian.bill.queryBuyPostpaidResult",
|
||||
commodityOrderInfo: "zeldaEasy.broadscope-bailian.bill.postpaidCommodityOrderInfo",
|
||||
buyCommodity: "zeldaEasy.broadscope-bailian.bill.buyPostpaidCommodity",
|
||||
} as const;
|
||||
|
||||
const POLL_INTERVAL_MS = 1000;
|
||||
const MAX_POLL_ATTEMPTS = 120;
|
||||
|
||||
function sleep(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
interface CommodityItem {
|
||||
commodity?: string;
|
||||
status?: number;
|
||||
startDate?: string;
|
||||
}
|
||||
|
||||
export default defineCommand({
|
||||
description: "Initialize Bailian workspace and activate postpaid services",
|
||||
auth: "console",
|
||||
usageArgs: "",
|
||||
flags: {},
|
||||
exampleArgs: [],
|
||||
async run(ctx) {
|
||||
const { settings } = ctx;
|
||||
const format = detectOutputFormat(settings.output);
|
||||
|
||||
if (settings.dryRun) {
|
||||
emitResult(
|
||||
{
|
||||
apis: [
|
||||
{ step: 1, api: API.loginInfo, description: "Check login & workspace status" },
|
||||
{ step: 2, api: API.initSpace, description: "Initialize workspace (if needed)" },
|
||||
{ step: 3, api: API.queryBuyResult, description: "Query postpaid order status" },
|
||||
{
|
||||
step: 4,
|
||||
api: API.commodityOrderInfo,
|
||||
description: "Query commodity activation status",
|
||||
},
|
||||
{
|
||||
step: 5,
|
||||
api: API.buyCommodity,
|
||||
description: "Activate postpaid commodities (if needed)",
|
||||
},
|
||||
],
|
||||
},
|
||||
format,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const verbose = settings.verbose;
|
||||
const callApi = async (api: string) => {
|
||||
if (verbose) process.stderr.write(`> ${api}\n`);
|
||||
const resp = await ctx.client.console<any>(api, {});
|
||||
if (verbose) process.stderr.write(`< ${JSON.stringify(resp)}\n`);
|
||||
return resp;
|
||||
};
|
||||
|
||||
// Step 1: Check login info
|
||||
emitBare("Checking workspace status...");
|
||||
const loginInfo = await callApi(API.loginInfo);
|
||||
const spaceInited = loginInfo?.spaceInited === true;
|
||||
|
||||
// Step 2: Init space if needed
|
||||
if (!spaceInited) {
|
||||
emitBare("Initializing workspace...");
|
||||
await callApi(API.initSpace);
|
||||
emitBare("Workspace initialized.");
|
||||
} else {
|
||||
emitBare("Workspace already initialized.");
|
||||
}
|
||||
|
||||
// Step 3-5: Order & commodity flow
|
||||
await ensureCommoditiesActive(callApi, format);
|
||||
},
|
||||
});
|
||||
|
||||
type ApiCall = (api: string) => Promise<any>;
|
||||
|
||||
async function ensureCommoditiesActive(call: ApiCall, format: "text" | "json"): Promise<void> {
|
||||
emitBare("Checking service activation status...");
|
||||
let buyResult: string | undefined;
|
||||
for (let i = 0; i < MAX_POLL_ATTEMPTS; i++) {
|
||||
const resp = await call(API.queryBuyResult);
|
||||
buyResult = resp?.result;
|
||||
if (buyResult !== "buying") break;
|
||||
if (i === 0) emitBare("Service activation in progress, polling...");
|
||||
await sleep(POLL_INTERVAL_MS);
|
||||
}
|
||||
|
||||
if (buyResult === "fail") {
|
||||
throw new BailianError("Service activation failed.", ExitCode.GENERAL);
|
||||
}
|
||||
|
||||
if (buyResult === "success") {
|
||||
await pollCommoditiesUntilActive(call, format);
|
||||
return;
|
||||
}
|
||||
|
||||
await checkAndActivateCommodities(call, format);
|
||||
}
|
||||
|
||||
async function checkAndActivateCommodities(call: ApiCall, format: "text" | "json"): Promise<void> {
|
||||
const resp = await call(API.commodityOrderInfo);
|
||||
const items: CommodityItem[] = resp?.result ?? [];
|
||||
|
||||
const overdue = items.filter((c) => c.status === 11);
|
||||
if (overdue.length > 0) {
|
||||
emitBare("Warning: Some services are overdue:");
|
||||
for (const c of overdue) emitBare(` - ${c.commodity}`);
|
||||
}
|
||||
|
||||
const notActivated = items.filter((c) => c.status === 1);
|
||||
if (notActivated.length > 0) {
|
||||
emitBare("Activating postpaid services...");
|
||||
await call(API.buyCommodity);
|
||||
await pollCommoditiesUntilActive(call, format);
|
||||
return;
|
||||
}
|
||||
|
||||
const active = items.filter((c) => c.status === 10);
|
||||
emitResult({ status: "ready", activeServices: active.map((c) => c.commodity) }, format);
|
||||
}
|
||||
|
||||
async function pollCommoditiesUntilActive(call: ApiCall, format: "text" | "json"): Promise<void> {
|
||||
emitBare("Waiting for services to activate...");
|
||||
for (let i = 0; i < MAX_POLL_ATTEMPTS; i++) {
|
||||
const resp = await call(API.commodityOrderInfo);
|
||||
const items: CommodityItem[] = resp?.result ?? [];
|
||||
|
||||
const pending = items.filter((c) => c.status !== 10 && c.status !== 11);
|
||||
if (pending.length === 0) {
|
||||
const overdue = items.filter((c) => c.status === 11);
|
||||
if (overdue.length > 0) {
|
||||
emitBare("Warning: Some services are overdue:");
|
||||
for (const c of overdue) emitBare(` - ${c.commodity}`);
|
||||
}
|
||||
const active = items.filter((c) => c.status === 10);
|
||||
emitResult({ status: "ready", activeServices: active.map((c) => c.commodity) }, format);
|
||||
return;
|
||||
}
|
||||
await sleep(POLL_INTERVAL_MS);
|
||||
}
|
||||
|
||||
throw new BailianError("Timed out waiting for services to activate.", ExitCode.TIMEOUT);
|
||||
}
|
||||
@@ -77,3 +77,4 @@ export { default as tokenPlanListSeats } from "./commands/token-plan/list-seats.
|
||||
export { default as tokenPlanCreateKey } from "./commands/token-plan/create-key.ts";
|
||||
export { default as tokenPlanAssignSeats } from "./commands/token-plan/assign-seats.ts";
|
||||
export { default as tokenPlanAddMember } from "./commands/token-plan/add-member.ts";
|
||||
export { default as bootstrap } from "./commands/bootstrap/index.ts";
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
# `bl bootstrap` commands
|
||||
|
||||
> Auto-generated from `packages/cli/src/commands.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 bootstrap` | Initialize Bailian workspace and activate postpaid services |
|
||||
|
||||
## Command details
|
||||
|
||||
### `bl bootstrap`
|
||||
|
||||
| Field | Value |
|
||||
| --------------- | ----------------------------------------------------------- |
|
||||
| **Name** | `bootstrap` |
|
||||
| **Description** | Initialize Bailian workspace and activate postpaid services |
|
||||
| **Usage** | `bl bootstrap` |
|
||||
|
||||
#### Flags
|
||||
|
||||
| Flag | Type | Required | Description |
|
||||
| ------------------------------ | ------ | -------- | -------------------------------------------------------- |
|
||||
| `--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 |
|
||||
| `--workspace-id <id>` | string | no | Workspace ID (env: BAILIAN_WORKSPACE_ID) |
|
||||
|
||||
#### Examples
|
||||
|
||||
_No examples._
|
||||
@@ -17,6 +17,7 @@ Use this index for the full quick index and global flags.
|
||||
| `bl auth login` | Authenticate with API key, console browser login, or OpenAPI AK/SK (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 bootstrap` | Initialize Bailian workspace and activate postpaid services | [bootstrap.md](bootstrap.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) |
|
||||
@@ -92,6 +93,7 @@ Use this index for the full quick index and global flags.
|
||||
| `advisor` | `recommend` | [advisor.md](advisor.md) |
|
||||
| `app` | `call`, `list` | [app.md](app.md) |
|
||||
| `auth` | `generate-access-token`, `login`, `logout`, `status` | [auth.md](auth.md) |
|
||||
| `bootstrap` | `(root)` | [bootstrap.md](bootstrap.md) |
|
||||
| `config` | `set`, `show` | [config.md](config.md) |
|
||||
| `console` | `call` | [console.md](console.md) |
|
||||
| `dataset` | `delete`, `get`, `list`, `upload`, `validate` | [dataset.md](dataset.md) |
|
||||
|
||||
Reference in New Issue
Block a user