Skip to content

Commit 49095c3

Browse files
committed
refactor(commands): remove yes confirmation gates
1 parent c188441 commit 49095c3

16 files changed

Lines changed: 120 additions & 691 deletions

File tree

docs/plans/finetune-deploy-mvp.md

Lines changed: 0 additions & 438 deletions
This file was deleted.

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,6 @@ describe.skipIf(!isDashScopeE2EReady())("e2e: finetune (offline)", () => {
190190
"qwen3-8b",
191191
"--datasets",
192192
localPath,
193-
"--yes",
194193
"--output",
195194
"json",
196195
]);
@@ -214,7 +213,6 @@ describe.skipIf(!isDashScopeE2EReady())("e2e: finetune (offline)", () => {
214213
localPath,
215214
"--batch-size",
216215
"1",
217-
"--yes",
218216
"--output",
219217
"json",
220218
]);

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ describe("e2e: quota", () => {
2222
expect(exitCode, stderr).toBe(0);
2323
expect(stderr).toContain("--model");
2424
expect(stderr).toContain("--tpm");
25-
expect(stderr).toContain("--yes");
2625
});
2726

2827
test("quota history --help 正常退出", async () => {

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

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,4 @@
1-
import {
2-
defineCommand,
3-
detectOutputFormat,
4-
deleteDataset,
5-
BailianError,
6-
ExitCode,
7-
type FlagsDef,
8-
} from "bailian-cli-core";
1+
import { defineCommand, detectOutputFormat, deleteDataset, type FlagsDef } from "bailian-cli-core";
92
import { emitResult, emitBare } from "bailian-cli-runtime";
103

114
const DELETE_FLAGS = {
@@ -15,15 +8,14 @@ const DELETE_FLAGS = {
158
description: "Dataset file ID (required)",
169
required: true,
1710
},
18-
yes: { type: "switch", description: "Confirm the deletion (required to delete)" },
1911
} satisfies FlagsDef;
2012

2113
export default defineCommand({
2214
description: "Delete a dataset file by ID",
2315
auth: "apiKey",
24-
usageArgs: "--file-id <id> --yes",
16+
usageArgs: "--file-id <id>",
2517
flags: DELETE_FLAGS,
26-
exampleArgs: ["--file-id file-id-xxx --yes", "--file-id file-id-xxx --dry-run"],
18+
exampleArgs: ["--file-id file-id-xxx", "--file-id file-id-xxx --dry-run"],
2719
async run(ctx) {
2820
const { settings, flags } = ctx;
2921
const fileId = flags.fileId;
@@ -34,14 +26,6 @@ export default defineCommand({
3426
return;
3527
}
3628

37-
if (!flags.yes) {
38-
throw new BailianError(
39-
`Refusing to permanently delete ${fileId} without --yes.`,
40-
ExitCode.USAGE,
41-
"Pass --yes to confirm the deletion.",
42-
);
43-
}
44-
4529
const response = await deleteDataset(ctx.client, fileId);
4630

4731
if (settings.quiet || format === "text") {

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

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ import {
22
defineCommand,
33
detectOutputFormat,
44
createDeployment,
5-
BailianError,
6-
ExitCode,
75
type CreateDeploymentRequest,
86
type FlagsDef,
97
} from "bailian-cli-core";
@@ -58,16 +56,15 @@ const CREATE_FLAGS = {
5856
valueHint: "<n>",
5957
description: "PTU max thinking-output tokens/min (optional, some models)",
6058
},
61-
yes: { type: "switch", description: "Confirm deployment creation (required to create)" },
6259
} satisfies FlagsDef;
6360

6461
/**
6562
* `bl deploy create` — create a model deployment.
6663
*
6764
* Plan-specific behaviour (required flags / body assembly / auto-pick) lives
6865
* in `plans.ts` (`PlanStrategy` + `STRATEGIES`). This file only handles the
69-
* shared envelope: flag validation, dispatch, dry-run, the --yes gate, and
70-
* result formatting. Adding a new plan = one entry in the strategy table;
66+
* shared envelope: flag validation, dispatch, dry-run, and result
67+
* formatting. Adding a new plan = one entry in the strategy table;
7168
* nothing here changes.
7269
*
7370
* `--model` (model identifier) and `--name` (console display name) are required.
@@ -76,13 +73,13 @@ export default defineCommand({
7673
description: "Create a model deployment",
7774
auth: "apiKey",
7875
usageArgs:
79-
"--model <model_name> --name <display_name> --yes [--plan <plan>] [--template-id <id>] [--capacity <n>] [--billing-method <m>] [--input-tpm <n>] [--output-tpm <n>] [--thinking-output-tpm <n>]",
76+
"--model <model_name> --name <display_name> [--plan <plan>] [--template-id <id>] [--capacity <n>] [--billing-method <m>] [--input-tpm <n>] [--output-tpm <n>] [--thinking-output-tpm <n>]",
8077
flags: CREATE_FLAGS,
8178
exampleArgs: [
82-
"--model my-qwen-sft --name my-sft-test --yes",
83-
"--model qwen3.6-flash-2026-04-16 --name my-flash --plan ptu --input-tpm 10000 --output-tpm 1000 --yes",
84-
"--model qwen3-8b --name my-qwen3-mu --plan mu --yes",
85-
"--model qwen3-8b --name my-qwen3 --plan mu --template-id MU1 --capacity 2 --yes",
79+
"--model my-qwen-sft --name my-sft-test",
80+
"--model qwen3.6-flash-2026-04-16 --name my-flash --plan ptu --input-tpm 10000 --output-tpm 1000",
81+
"--model qwen3-8b --name my-qwen3-mu --plan mu",
82+
"--model qwen3-8b --name my-qwen3 --plan mu --template-id MU1 --capacity 2",
8683
],
8784
notes: [
8885
"Plan defaults to `lora` (Token-billed). Pass --plan to override.",
@@ -124,15 +121,6 @@ export default defineCommand({
124121
// already rejected by `validate` above.
125122
const strategy = pickPlanStrategy(plan);
126123

127-
// Gate before any side-effecting resolution (mu hits the catalog API).
128-
if (!settings.dryRun && !flags.yes) {
129-
throw new BailianError(
130-
`Refusing to create deployment (model=${model}, name=${name}, plan=${plan}) without --yes.`,
131-
ExitCode.USAGE,
132-
"Pass --yes to confirm deployment creation, or use --dry-run to preview the request.",
133-
);
134-
}
135-
136124
const resolved = await strategy.resolve({
137125
client: ctx.client,
138126
dryRun: settings.dryRun,

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

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ const DELETE_FLAGS = {
1616
description: "Deployed model identifier (required)",
1717
required: true,
1818
},
19-
yes: { type: "switch", description: "Confirm the deletion (required to delete)" },
2019
skipPrecheck: {
2120
type: "switch",
2221
description: "Skip the local STOPPED/FAILED status precheck",
@@ -33,9 +32,9 @@ const DELETE_FLAGS = {
3332
export default defineCommand({
3433
description: "Delete a model deployment (must be STOPPED or FAILED)",
3534
auth: "apiKey",
36-
usageArgs: "--deployed-model <id> --yes [--skip-precheck]",
35+
usageArgs: "--deployed-model <id> [--skip-precheck]",
3736
flags: DELETE_FLAGS,
38-
exampleArgs: ["--deployed-model dep-... --yes", "--deployed-model dep-... --dry-run"],
37+
exampleArgs: ["--deployed-model dep-...", "--deployed-model dep-... --dry-run"],
3938
async run(ctx) {
4039
const { settings, flags } = ctx;
4140
const deployedModel = flags.deployedModel;
@@ -46,14 +45,6 @@ export default defineCommand({
4645
return;
4746
}
4847

49-
if (!flags.yes) {
50-
throw new BailianError(
51-
`Refusing to delete deployment ${deployedModel} without --yes.`,
52-
ExitCode.USAGE,
53-
"Pass --yes to confirm the deletion.",
54-
);
55-
}
56-
5748
// Precheck status unless skipped — surface a clear hint instead of letting
5849
// the server return a generic precondition error.
5950
if (!flags.skipPrecheck) {

packages/commands/src/commands/deploy/scale.ts

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ import {
22
defineCommand,
33
detectOutputFormat,
44
scaleDeployment,
5-
BailianError,
6-
ExitCode,
75
type FlagsDef,
86
} from "bailian-cli-core";
97
import { emitResult, emitBare } from "bailian-cli-runtime";
@@ -30,7 +28,6 @@ const SCALE_FLAGS = {
3028
valueHint: "<n>",
3129
description: "PTU only — output tokens per minute",
3230
},
33-
yes: { type: "switch", description: "Confirm the scaling (required to scale)" },
3431
} satisfies FlagsDef;
3532

3633
/**
@@ -42,11 +39,11 @@ const SCALE_FLAGS = {
4239
export default defineCommand({
4340
description: "Scale a deployment's capacity",
4441
auth: "apiKey",
45-
usageArgs: "--deployed-model <id> --capacity <n> --yes [--input-tpm <n>] [--output-tpm <n>]",
42+
usageArgs: "--deployed-model <id> --capacity <n> [--input-tpm <n>] [--output-tpm <n>]",
4643
flags: SCALE_FLAGS,
4744
exampleArgs: [
48-
"--deployed-model qwen-plus-...-b6d61c71 --capacity 8 --yes",
49-
"--deployed-model dep-... --capacity 2 --yes",
45+
"--deployed-model qwen-plus-...-b6d61c71 --capacity 8",
46+
"--deployed-model dep-... --capacity 2",
5047
],
5148
validate: (flags) =>
5249
flags.capacity === undefined && flags.inputTpm === undefined && flags.outputTpm === undefined
@@ -67,18 +64,6 @@ export default defineCommand({
6764
return;
6865
}
6966

70-
if (!flags.yes) {
71-
const parts: string[] = [];
72-
if (flags.capacity !== undefined) parts.push(`capacity=${flags.capacity}`);
73-
if (flags.inputTpm !== undefined) parts.push(`input_tpm=${flags.inputTpm}`);
74-
if (flags.outputTpm !== undefined) parts.push(`output_tpm=${flags.outputTpm}`);
75-
throw new BailianError(
76-
`Refusing to scale deployment ${deployedModel} (${parts.join(", ")}) without --yes.`,
77-
ExitCode.USAGE,
78-
"Pass --yes to confirm the scaling.",
79-
);
80-
}
81-
8267
const response = await scaleDeployment(ctx.client, deployedModel, body);
8368
const deployment = response.output ?? response.data;
8469

packages/commands/src/commands/deploy/update.ts

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ import {
22
defineCommand,
33
detectOutputFormat,
44
updateDeployment,
5-
BailianError,
6-
ExitCode,
75
type FlagsDef,
86
} from "bailian-cli-core";
97
import { emitResult, emitBare } from "bailian-cli-runtime";
@@ -25,7 +23,6 @@ const UPDATE_FLAGS = {
2523
valueHint: "<n>",
2624
description: "Tokens per minute",
2725
},
28-
yes: { type: "switch", description: "Confirm the rate-limit update (required to update)" },
2926
} satisfies FlagsDef;
3027

3128
/**
@@ -37,11 +34,11 @@ const UPDATE_FLAGS = {
3734
export default defineCommand({
3835
description: "Update a deployment's rate limits (rpm_limit / tpm_limit)",
3936
auth: "apiKey",
40-
usageArgs: "--deployed-model <id> --yes [--rpm-limit <n>] [--tpm-limit <n>]",
37+
usageArgs: "--deployed-model <id> [--rpm-limit <n>] [--tpm-limit <n>]",
4138
flags: UPDATE_FLAGS,
4239
exampleArgs: [
43-
"--deployed-model dep-... --rpm-limit 1000 --yes",
44-
"--deployed-model dep-... --rpm-limit 1000 --tpm-limit 200000 --yes",
40+
"--deployed-model dep-... --rpm-limit 1000",
41+
"--deployed-model dep-... --rpm-limit 1000 --tpm-limit 200000",
4542
],
4643
notes: ["At least one of --rpm-limit / --tpm-limit must be provided."],
4744
validate: (flags) =>
@@ -62,17 +59,6 @@ export default defineCommand({
6259
return;
6360
}
6461

65-
if (!flags.yes) {
66-
const parts: string[] = [];
67-
if (flags.rpmLimit !== undefined) parts.push(`rpm_limit=${flags.rpmLimit}`);
68-
if (flags.tpmLimit !== undefined) parts.push(`tpm_limit=${flags.tpmLimit}`);
69-
throw new BailianError(
70-
`Refusing to update rate limits for ${deployedModel} (${parts.join(", ")}) without --yes.`,
71-
ExitCode.USAGE,
72-
"Pass --yes to confirm the rate-limit update.",
73-
);
74-
}
75-
7662
const response = await updateDeployment(ctx.client, deployedModel, body);
7763
const deployment = response.output ?? response.data;
7864

packages/commands/src/commands/finetune/cancel.ts

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,4 @@
1-
import {
2-
defineCommand,
3-
detectOutputFormat,
4-
cancelFineTune,
5-
BailianError,
6-
ExitCode,
7-
type FlagsDef,
8-
} from "bailian-cli-core";
1+
import { defineCommand, detectOutputFormat, cancelFineTune, type FlagsDef } from "bailian-cli-core";
92
import { emitResult, emitBare } from "bailian-cli-runtime";
103

114
const CANCEL_FLAGS = {
@@ -15,15 +8,14 @@ const CANCEL_FLAGS = {
158
description: "Fine-tune job ID (required)",
169
required: true,
1710
},
18-
yes: { type: "switch", description: "Confirm the cancellation (required to cancel)" },
1911
} satisfies FlagsDef;
2012

2113
export default defineCommand({
2214
description: "Cancel a running fine-tune job",
2315
auth: "apiKey",
24-
usageArgs: "--job-id <id> --yes",
16+
usageArgs: "--job-id <id>",
2517
flags: CANCEL_FLAGS,
26-
exampleArgs: ["--job-id ft-xxx --yes", "--job-id ft-xxx --dry-run"],
18+
exampleArgs: ["--job-id ft-xxx", "--job-id ft-xxx --dry-run"],
2719
notes: [
2820
"Only PENDING / RUNNING jobs can be cancelled. Completed / failed / already-",
2921
"cancelled jobs return a server-side error (passed through verbatim).",
@@ -38,14 +30,6 @@ export default defineCommand({
3830
return;
3931
}
4032

41-
if (!flags.yes) {
42-
throw new BailianError(
43-
`Refusing to cancel fine-tune job ${jobId} without --yes.`,
44-
ExitCode.USAGE,
45-
"Pass --yes to confirm the cancellation.",
46-
);
47-
}
48-
4933
const response = await cancelFineTune(ctx.client, jobId);
5034
const job = response.output ?? response.data;
5135

packages/commands/src/commands/finetune/create.ts

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -250,31 +250,27 @@ const CREATE_FLAGS = {
250250
valueHint: "<n>",
251251
description: "Max sequence length",
252252
},
253-
yes: {
254-
type: "switch",
255-
description: "Confirm job creation (required to submit; uploads data and consumes quota)",
256-
},
257253
} satisfies FlagsDef;
258254

259255
export default defineCommand({
260256
description: "Create a fine-tune job (sft | sft-lora | dpo | dpo-lora | cpt)",
261257
auth: "apiKey",
262258
usageArgs:
263-
"--model <model> --datasets <id|path,...> [--validations <id|path,...>] [--model-name <name>] [--suffix <text>] [--n-epochs <n>] [--batch-size <n>] [--learning-rate <str>] [--max-length <n>] [--training-type <sft|sft-lora|dpo|dpo-lora|cpt>] --yes",
259+
"--model <model> --datasets <id|path,...> [--validations <id|path,...>] [--model-name <name>] [--suffix <text>] [--n-epochs <n>] [--batch-size <n>] [--learning-rate <str>] [--max-length <n>] [--training-type <sft|sft-lora|dpo|dpo-lora|cpt>]",
264260
flags: CREATE_FLAGS,
265261
exampleArgs: [
266-
"--model qwen3-8b --datasets file-xxx --yes",
267-
"--model qwen3-8b --datasets ./train.jsonl --yes",
268-
"--model qwen3-8b --datasets ./train.jsonl --validations ./eval.jsonl --yes",
269-
"--model qwen3-8b --datasets file-aaa,./extra.jsonl --yes",
270-
"--model qwen3-8b --datasets ./train.jsonl --training-type sft --yes",
271-
'--model qwen3-8b --datasets file-xxx --learning-rate "1.6e-5" --n-epochs 4 --yes',
272-
"--model qwen3-8b --datasets file-xxx --yes --output json",
262+
"--model qwen3-8b --datasets file-xxx",
263+
"--model qwen3-8b --datasets ./train.jsonl",
264+
"--model qwen3-8b --datasets ./train.jsonl --validations ./eval.jsonl",
265+
"--model qwen3-8b --datasets file-aaa,./extra.jsonl",
266+
"--model qwen3-8b --datasets ./train.jsonl --training-type sft",
267+
'--model qwen3-8b --datasets file-xxx --learning-rate "1.6e-5" --n-epochs 4',
268+
"--model qwen3-8b --datasets file-xxx --output json",
273269
"--model qwen3-8b --datasets file-xxx --dry-run",
274270
],
275271
notes: [
276-
"Creating a job consumes training quota, so --yes is required to submit",
277-
"(use --dry-run to preview the request body without --yes).",
272+
"Creating a job uploads any local datasets and consumes training quota.",
273+
"Use --dry-run to preview the request body without submitting.",
278274
"Training-type values use the `<method>` / `<method>-lora` convention:",
279275
"sft (full) | sft-lora (LoRA) | dpo (full) | dpo-lora (LoRA) | cpt. These map",
280276
"to the server's training_type at the interface boundary, so the rest of the",
@@ -443,18 +439,8 @@ export default defineCommand({
443439
}
444440
}
445441

446-
// --yes gate — BEFORE upload: without it we must not silently consume
447-
// quota OR upload any file. (Local validation is still allowed to run.)
448-
if (!settings.dryRun && !flags.yes) {
449-
throw new BailianError(
450-
"Refusing to create a fine-tune job without --yes.",
451-
ExitCode.USAGE,
452-
"Pass --yes to confirm creation (uploads datasets and consumes training quota), or --dry-run to preview the request.",
453-
);
454-
}
455-
456442
// Upload local paths now that pre-flight (validation, batch-size gate,
457-
// capability check, --yes gate) has cleared them. This swaps the
443+
// capability check) has cleared them. This swaps the
458444
// placeholder path entries in `training.fileIds` / `validation?.fileIds`
459445
// for real file-ids, so the body below sees ids.
460446
if (!settings.dryRun) {

0 commit comments

Comments
 (0)