Skip to content

Commit a7245c0

Browse files
committed
feat(deploy): add pause/resume commands; JSON-only output for dataset/finetune/deploy
- Add `bl deploy pause` and `bl deploy resume` (console domain, first console-auth commands in deploy group) via modelInstance start/stop APIs - Add core deploy/lifecycle.ts with input-wrapped console gateway calls - Switch all dataset/finetune/deploy commands to JSON-only output, removing text formatting logic - Expose usage/charge_type in finetune get, model_name/expire_time in finetune checkpoints with near-expiry warning - Update deploy delete hint to suggest `bl deploy pause`
1 parent 2626814 commit a7245c0

31 files changed

Lines changed: 584 additions & 571 deletions

File tree

packages/cli/src/commands.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ import {
8080
deployScale,
8181
deployUpdate,
8282
deployDelete,
83+
deployPause,
84+
deployResume,
8385
tokenPlanListSeats,
8486
tokenPlanCreateKey,
8587
tokenPlanAssignSeats,
@@ -198,6 +200,8 @@ export const commands: Record<string, AnyCommand> = {
198200
"deploy scale": deployScale,
199201
"deploy update": deployUpdate,
200202
"deploy delete": deployDelete,
203+
"deploy pause": deployPause,
204+
"deploy resume": deployResume,
201205
"token-plan list-seats": tokenPlanListSeats,
202206
"token-plan create-key": tokenPlanCreateKey,
203207
"token-plan assign-seats": tokenPlanAssignSeats,

packages/commands/src/commands/dataset/delete.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { defineCommand, detectOutputFormat, deleteDataset, type FlagsDef } from "bailian-cli-core";
2-
import { emitResult, emitBare, emitRequestId } from "bailian-cli-runtime";
1+
import { defineCommand, deleteDataset, type FlagsDef } from "bailian-cli-core";
2+
import { emitResult, emitBare } from "bailian-cli-runtime";
33

44
const DELETE_FLAGS = {
55
fileId: {
@@ -19,20 +19,18 @@ export default defineCommand({
1919
async run(ctx) {
2020
const { settings, flags } = ctx;
2121
const fileId = flags.fileId;
22-
const format = detectOutputFormat(settings.output);
2322

2423
if (settings.dryRun) {
25-
emitResult({ action: "dataset.delete", file_id: fileId }, format);
24+
emitResult({ action: "dataset.delete", file_id: fileId }, "json");
2625
return;
2726
}
2827

2928
const response = await deleteDataset(ctx.client, fileId);
3029

31-
if (settings.quiet || format === "text") {
32-
emitBare(`Deleted ${fileId}.`);
33-
emitRequestId(response.request_id, settings.quiet);
30+
if (settings.quiet) {
31+
emitBare(fileId);
3432
} else {
35-
emitResult(response, format);
33+
emitResult(response, "json");
3634
}
3735
},
3836
});

packages/commands/src/commands/dataset/get.ts

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { defineCommand, detectOutputFormat, getDataset, type FlagsDef } from "bailian-cli-core";
2-
import { emitResult, emitBare, emitRequestId } from "bailian-cli-runtime";
1+
import { defineCommand, getDataset, type FlagsDef } from "bailian-cli-core";
2+
import { emitResult, emitBare } from "bailian-cli-runtime";
33

44
const GET_FLAGS = {
55
fileId: {
@@ -19,10 +19,9 @@ export default defineCommand({
1919
async run(ctx) {
2020
const { settings, flags } = ctx;
2121
const fileId = flags.fileId;
22-
const format = detectOutputFormat(settings.output);
2322

2423
if (settings.dryRun) {
25-
emitResult({ action: "dataset.get", file_id: fileId }, format);
24+
emitResult({ action: "dataset.get", file_id: fileId }, "json");
2625
return;
2726
}
2827

@@ -45,19 +44,10 @@ export default defineCommand({
4544
description: file.description ?? "",
4645
};
4746

48-
if (format === "json") {
49-
emitResult({ ...item, request_id: response.request_id }, format);
50-
return;
47+
if (settings.quiet) {
48+
emitBare(item.file_id);
49+
} else {
50+
emitResult({ ...item, request_id: response.request_id }, "json");
5151
}
52-
53-
// text / quiet
54-
emitBare(`file_id: ${item.file_id}`);
55-
emitBare(`name: ${item.name}`);
56-
emitBare(`size: ${item.size}`);
57-
if (item.md5) emitBare(`md5: ${item.md5}`);
58-
if (item.purpose) emitBare(`purpose: ${item.purpose}`);
59-
if (item.created_at) emitBare(`created_at: ${item.created_at}`);
60-
if (item.description) emitBare(`description: ${item.description}`);
61-
emitRequestId(response.request_id, settings.quiet);
6252
},
6353
});

packages/commands/src/commands/dataset/list.ts

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { defineCommand, detectOutputFormat, listDatasets, type FlagsDef } from "bailian-cli-core";
2-
import { emitResult, emitBare, emitRequestId, formatTable } from "bailian-cli-runtime";
1+
import { defineCommand, listDatasets, type FlagsDef } from "bailian-cli-core";
2+
import { emitResult, emitBare } from "bailian-cli-runtime";
33

44
const LIST_FLAGS = {
55
page: { type: "number", valueHint: "<n>", description: "Page number (default: 1)" },
@@ -23,7 +23,6 @@ export default defineCommand({
2323
exampleArgs: ["", "--purpose fine-tune", "--purpose evaluation --page-size 20", "--output json"],
2424
async run(ctx) {
2525
const { settings, flags } = ctx;
26-
const format = detectOutputFormat(settings.output);
2726

2827
if (settings.dryRun) {
2928
emitResult(
@@ -33,7 +32,7 @@ export default defineCommand({
3332
page_size: flags.pageSize,
3433
purpose: flags.purpose,
3534
},
36-
format,
35+
"json",
3736
);
3837
return;
3938
}
@@ -46,28 +45,17 @@ export default defineCommand({
4645
const files = response.data?.files ?? [];
4746
const total = response.data?.total;
4847

49-
// Normalize to consistent structure for both text/json output.
5048
const items = files.map((item) => ({
5149
file_id: item.file_id ?? "",
5250
name: item.name ?? "",
5351
size: item.size !== undefined ? `${(item.size / 1024).toFixed(1)} KB` : "?",
5452
purpose: item.purpose ?? "",
5553
}));
5654

57-
if (format === "json") {
58-
emitResult({ items, total, request_id: response.request_id }, format);
59-
return;
60-
}
61-
62-
// text / quiet
63-
if (items.length === 0) {
64-
emitBare("No dataset files found.");
65-
return;
55+
if (settings.quiet) {
56+
for (const item of items) emitBare(item.file_id);
57+
} else {
58+
emitResult({ items, total, request_id: response.request_id }, "json");
6659
}
67-
const headers = ["FILE_ID", "NAME", "SIZE", "PURPOSE"];
68-
const rows = items.map((i) => [i.file_id, i.name, i.size, i.purpose]);
69-
for (const line of formatTable(headers, rows)) emitBare(line);
70-
if (total !== undefined) emitBare(`\nTotal: ${total}`);
71-
emitRequestId(response.request_id, settings.quiet);
7260
},
7361
});

packages/commands/src/commands/dataset/upload.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import {
22
defineCommand,
3-
detectOutputFormat,
43
uploadDataset,
54
validateDataset,
65
parseDatasetSchemaFlag,
@@ -11,7 +10,7 @@ import {
1110
ExitCode,
1211
type FlagsDef,
1312
} from "bailian-cli-core";
14-
import { emitResult, emitBare, emitRequestId } from "bailian-cli-runtime";
13+
import { emitResult, emitBare } from "bailian-cli-runtime";
1514

1615
const UPLOAD_FLAGS = {
1716
file: {
@@ -80,7 +79,6 @@ export default defineCommand({
8079
`Supported schemas: chatml, dpo, cpt, tts, image.`,
8180
);
8281
}
83-
const format = detectOutputFormat(settings.output);
8482
// Image schema allows larger ZIPs (1 GB vs 300 MB for text).
8583
const isMediaSchema = schema === "image";
8684

@@ -129,7 +127,7 @@ export default defineCommand({
129127
validate: !flags.noValidate,
130128
schema: schema ?? "auto",
131129
},
132-
format,
130+
"json",
133131
);
134132
return;
135133
}
@@ -142,11 +140,8 @@ export default defineCommand({
142140

143141
if (settings.quiet) {
144142
emitBare(file.file_id);
145-
} else if (format === "text") {
146-
emitBare(`Uploaded ${file.name} → file_id=${file.file_id}`);
147-
emitRequestId(request_id, settings.quiet);
148143
} else {
149-
emitResult({ ...file, request_id }, format);
144+
emitResult({ ...file, request_id }, "json");
150145
}
151146
},
152147
});

packages/commands/src/commands/dataset/validate.ts

Lines changed: 3 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,13 @@
11
import {
22
defineCommand,
3-
detectOutputFormat,
43
validateDataset,
54
parseDatasetSchemaFlag,
6-
formatIssue,
75
BailianError,
86
ExitCode,
9-
type ValidationResult,
107
type FlagsDef,
118
} from "bailian-cli-core";
129
import { emitResult, emitBare } from "bailian-cli-runtime";
1310

14-
function formatStats(result: ValidationResult): string[] {
15-
const out: string[] = [];
16-
if (result.stats.totalRecords !== undefined) out.push(`records: ${result.stats.totalRecords}`);
17-
if (result.stats.sampledRecords !== undefined)
18-
out.push(`sampled: ${result.stats.sampledRecords}`);
19-
if (result.stats.bytes !== undefined) out.push(`bytes: ${result.stats.bytes}`);
20-
if (result.stats.durationMs !== undefined) out.push(`took: ${result.stats.durationMs}ms`);
21-
return out;
22-
}
23-
2411
const VALIDATE_FLAGS = {
2512
file: {
2613
type: "string",
@@ -79,8 +66,6 @@ export default defineCommand({
7966
`Supported schemas: chatml, dpo, cpt, tts, image.`,
8067
);
8168
}
82-
const format = detectOutputFormat(settings.output);
83-
8469
if (settings.dryRun) {
8570
emitResult(
8671
{
@@ -89,38 +74,17 @@ export default defineCommand({
8974
full: flags.fullValidate,
9075
schema: schema ?? "auto",
9176
},
92-
format,
77+
"json",
9378
);
9479
return;
9580
}
9681

9782
const result = await validateDataset(filePath, { fullValidate: flags.fullValidate, schema });
9883

99-
if (format === "json") {
100-
// For json output we always emit the structured result, exit code conveys validity.
101-
emitResult(result, format);
102-
} else if (settings.quiet) {
84+
if (settings.quiet) {
10385
emitBare(result.valid ? "ok" : "fail");
10486
} else {
105-
const status = result.valid ? "PASSED" : "FAILED";
106-
emitBare(`Dataset validation ${status} for ${result.filePath}`);
107-
const stats = formatStats(result);
108-
if (stats.length) emitBare(` ${stats.join(" · ")}`);
109-
110-
if (result.errors.length) {
111-
emitBare(`Errors (${result.errors.length}):`);
112-
for (const error of result.errors.slice(0, 20)) emitBare(formatIssue(error));
113-
if (result.errors.length > 20) {
114-
emitBare(` … and ${result.errors.length - 20} more.`);
115-
}
116-
}
117-
if (result.warnings.length) {
118-
emitBare(`Warnings (${result.warnings.length}):`);
119-
for (const warning of result.warnings.slice(0, 10)) emitBare(formatIssue(warning));
120-
if (result.warnings.length > 10) {
121-
emitBare(` … and ${result.warnings.length - 10} more.`);
122-
}
123-
}
87+
emitResult(result, "json");
12488
}
12589

12690
if (!result.valid) {

packages/commands/src/commands/deploy/create.ts

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import {
22
defineCommand,
3-
detectOutputFormat,
43
createDeployment,
54
pickPlanStrategy,
65
STRATEGIES,
@@ -11,7 +10,7 @@ import {
1110
type CommandContext,
1211
type FlagsDef,
1312
} from "bailian-cli-core";
14-
import { emitResult, emitBare, emitRequestId } from "bailian-cli-runtime";
13+
import { emitResult, emitBare } from "bailian-cli-runtime";
1514

1615
const CREATE_FLAGS = {
1716
model: {
@@ -122,7 +121,6 @@ async function runCreate(
122121
const model = flags.model as string;
123122
const name = flags.name as string;
124123
const plan = (flags.plan as string | undefined) || defaultDeployPlan(modality);
125-
const format = detectOutputFormat(settings.output);
126124

127125
// Plan-specific behaviour is owned by core `plans.ts`. The strategy resolves
128126
// the plan-specific body fragment (mu may auto-pick a template from the
@@ -146,7 +144,7 @@ async function runCreate(
146144
};
147145

148146
if (settings.dryRun) {
149-
emitResult({ action: "deploy.create", body }, format);
147+
emitResult({ action: "deploy.create", body }, "json");
150148
return;
151149
}
152150

@@ -155,17 +153,8 @@ async function runCreate(
155153

156154
if (settings.quiet) {
157155
emitBare(deployment?.deployed_model ?? "");
158-
} else if (format === "text") {
159-
emitBare(`Created deployment.`);
160-
if (deployment?.deployed_model) emitBare(` deployed_model: ${deployment.deployed_model}`);
161-
if (deployment?.status) emitBare(` status: ${deployment.status}`);
162-
if (deployment?.plan) emitBare(` plan: ${deployment.plan}`);
163-
emitBare(
164-
`\nNext: track readiness with: ${identity.binName} deploy get --deployed-model ${deployment?.deployed_model ?? "<id>"}`,
165-
);
166-
emitRequestId(response.request_id, settings.quiet);
167156
} else {
168-
emitResult(response, format);
157+
emitResult(response, "json");
169158
}
170159
}
171160

packages/commands/src/commands/deploy/delete.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
import {
22
defineCommand,
3-
detectOutputFormat,
43
deleteDeployment,
54
getDeployment,
65
BailianError,
76
ExitCode,
87
type FlagsDef,
98
} from "bailian-cli-core";
10-
import { emitResult, emitBare, emitRequestId } from "bailian-cli-runtime";
9+
import { emitResult, emitBare } from "bailian-cli-runtime";
1110

1211
const DELETE_FLAGS = {
1312
deployedModel: {
@@ -38,10 +37,9 @@ export default defineCommand({
3837
async run(ctx) {
3938
const { settings, flags } = ctx;
4039
const deployedModel = flags.deployedModel;
41-
const format = detectOutputFormat(settings.output);
4240

4341
if (settings.dryRun) {
44-
emitResult({ action: "deploy.delete", deployed_model: deployedModel }, format);
42+
emitResult({ action: "deploy.delete", deployed_model: deployedModel }, "json");
4543
return;
4644
}
4745

@@ -55,7 +53,8 @@ export default defineCommand({
5553
if (status && status !== "STOPPED" && status !== "FAILED") {
5654
throw new BailianError(
5755
`Deployment ${deployedModel} is ${status}. Only STOPPED / FAILED deployments can be deleted. ` +
58-
`Stop it first via the platform console, or pass --skip-precheck to attempt deletion anyway.`,
56+
`Run \`bl deploy pause --deployed-model ${deployedModel}\` to pause it first, ` +
57+
`or pass --skip-precheck to attempt deletion anyway.`,
5958
ExitCode.USAGE,
6059
);
6160
}
@@ -69,11 +68,8 @@ export default defineCommand({
6968

7069
if (settings.quiet) {
7170
emitBare(deployedModel);
72-
} else if (format === "text") {
73-
emitBare(`Deleted ${deployedModel}.`);
74-
emitRequestId(response.request_id, settings.quiet);
7571
} else {
76-
emitResult(response, format);
72+
emitResult(response, "json");
7773
}
7874
},
7975
});

0 commit comments

Comments
 (0)