feat(cli): expose high-risk confirmation guidance in help and skills

This commit is contained in:
若麒
2026-08-28 17:19:24 +08:00
parent afb547e0c8
commit 0872ff6a20
14 changed files with 288 additions and 114 deletions
+3
View File
@@ -40,6 +40,8 @@ bailian-gen bailian-finetune bailian-managed-agent bailian-web-search
- [ ] **整包装齐**:安装/升级文案主推 `bl skill init`;业务 skill **不**声明 `companions`
- [ ] **协议读取**:CRITICAL / references 可链 `../bailian-protocol/…`;若读不到 → 停止执行 `bl`,提示 `bl skill init`
- [ ] **高风险确认**:统一由 `bailian-protocol` 定义;reference / leaf help 以 `risk: high` 明示风险,业务 skill 不得引导 Agent 自动补 `--yes`。遇到 exit code 7 / `requires_confirmation` 时停止执行并请求确认;目标或范围变化后重新确认
- [ ] **正常控制流**:`requires_confirmation` 不是 CLI bug,`assets/issue-reporting.md` 必须将 exit code 7 保持在 EXCLUDE 范围
- [ ] **软 hand-off**:兄弟业务 skill **只写 skill 名**;已安装则 Read,未安装则 `bl … --help` 或提示整包安装;**不要**把 `../bailian-gen/…` 等写成执行前提
- [ ] **Hub vs 领域**:`bailian-cli` 的「When to use which command」只列 hub 拥有的意图;媒体 / 精调 / managed-agent 各留 hand-off 行,**不抄**领域默认模型与子命令明细
- [ ] **渐进披露**:SKILL 写意图路由与领域硬规则;flags / usage / examples 以 `reference/` 或 `bl <command> --help` 为准,表后保留「勿猜 flag」指向句
@@ -55,6 +57,7 @@ bailian-gen bailian-finetune bailian-managed-agent bailian-web-search
- [ ] 新一级命令组归属领域时:改 `tools/generate-reference.ts` 的 `GROUP_OWNER_SKILL`,并更新**拥有方** skill 的路由表;hub 最多加一行 hand-off
- [ ] 跑 `pnpm run sync:skill-assets`(或 commit 走 pre-commit),提交生成的 `reference/` 与 version 同步结果
- [ ] 高风险命令生成的 reference 必须包含 `Risk` / `Risk message` 和简短 Agent safety 提示;带 `--yes` 的示例必须标注只能在确认后执行,不要手改生成物
- [ ] 默认模型若写在领域路由表(如 `bailian-gen`):与命令 default / [model-add-remove.md](model-add-remove.md) 一并核对
## 完成后自查
@@ -0,0 +1,47 @@
import { readFileSync, readdirSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { expect, test } from "vite-plus/test";
const repositoryRoot = join(dirname(fileURLToPath(import.meta.url)), "../../..");
const skillsRoot = join(repositoryRoot, "skills");
test("every generated high-risk command reference requires user confirmation before --yes", () => {
let highRiskCommandCount = 0;
for (const skillDirectory of readdirSync(skillsRoot, { withFileTypes: true })) {
if (!skillDirectory.isDirectory()) continue;
const referenceDirectory = join(skillsRoot, skillDirectory.name, "reference");
let referenceFiles: string[];
try {
referenceFiles = readdirSync(referenceDirectory).filter(
(fileName) => fileName.endsWith(".md") && fileName !== "index.md",
);
} catch {
continue;
}
for (const referenceFile of referenceFiles) {
const markdown = readFileSync(join(referenceDirectory, referenceFile), "utf8");
const commandSections = markdown.split(/(?=^### `bl )/m).slice(1);
for (const commandSection of commandSections) {
if (!commandSection.includes("`--yes`")) continue;
highRiskCommandCount += 1;
expect(commandSection).toMatch(/\|\s+\*\*Risk\*\*\s+\|\s+`high`\s+\|/);
expect(commandSection).toMatch(/\|\s+\*\*Risk message\*\*\s+\|\s+.+\|/);
expect(commandSection).toMatch(/type=.*requires_confirmation/);
const agentSafetyLine = commandSection
.split("\n")
.find((line) => line.startsWith("> **Agent safety:**"));
expect(agentSafetyLine).toBeDefined();
expect(agentSafetyLine).toMatch(/never add `--yes` automatically/i);
expect(agentSafetyLine).toMatch(/explicit user confirmation/i);
expect(agentSafetyLine).not.toContain("`--dry-run`");
}
}
}
expect(highRiskCommandCount).toBeGreaterThan(0);
});
+20
View File
@@ -1,6 +1,7 @@
import type {
AnyCommand,
AuthRequirement,
CommandRiskLevel,
FlagDef,
FlagsDef,
LocalizedText,
@@ -41,10 +42,16 @@ const AUTH_LABELS = {
none: { "en-US": "No Auth", "zh-CN": "无需鉴权" },
} satisfies Record<AuthRequirement, LocalizedText>;
const RISK_LEVEL_LABELS = {
high: { "en-US": "high", "zh-CN": "高风险" },
} satisfies Record<CommandRiskLevel, LocalizedText>;
const HELP_TEXT = {
usage: { "en-US": "Usage:", "zh-CN": "用法:" },
commands: { "en-US": "Commands:", "zh-CN": "命令:" },
authentication: { "en-US": "Authentication:", "zh-CN": "鉴权方式:" },
risk: { "en-US": "Risk:", "zh-CN": "风险等级:" },
riskMessage: { "en-US": "Risk message:", "zh-CN": "风险说明:" },
flags: { "en-US": "Flags:", "zh-CN": "选项:" },
globalFlags: { "en-US": "Global Flags:", "zh-CN": "全局选项:" },
modelAuthFlags: { "en-US": "Model Auth Flags:", "zh-CN": "模型鉴权选项:" },
@@ -64,6 +71,10 @@ const HELP_TEXT = {
},
notes: { "en-US": "Notes:", "zh-CN": "说明:" },
examples: { "en-US": "Examples:", "zh-CN": "示例:" },
confirmedExample: {
"en-US": "# Only after explicit confirmation:",
"zh-CN": "# 仅在明确确认后执行:",
},
minimalWorkflow: { "en-US": "Minimal workflow.yaml:", "zh-CN": "最小 workflow.yaml:" },
tryIt: { "en-US": "Try it:", "zh-CN": "试一试:" },
} satisfies Record<string, LocalizedText>;
@@ -432,6 +443,12 @@ ${authFlagSections ? `${authFlagSections}\n\n` : ""}${b(this.localize(HELP_TEXT.
out.write(
`${b(this.localize(HELP_TEXT.authentication))} ${a(this.localize(AUTH_LABELS[cmd.auth]))}\n`,
);
if (cmd.risk !== undefined) {
out.write(
`${b(this.localize(HELP_TEXT.risk))} ${a(this.localize(RISK_LEVEL_LABELS[cmd.risk.level]))}\n`,
);
out.write(`${b(this.localize(HELP_TEXT.riskMessage))} ${this.localize(cmd.risk.message)}\n`);
}
const flagEntries = [
...Object.entries(cmd.flags ?? {}),
...Object.entries(confirmationFlagDefs(cmd)),
@@ -460,6 +477,9 @@ ${authFlagSections ? `${authFlagSections}\n\n` : ""}${b(this.localize(HELP_TEXT.
out.write(`\n${b(this.localize(HELP_TEXT.examples))}\n`);
for (const example of cmd.exampleArgs) {
const localizedExample = this.localize(example);
if (cmd.risk !== undefined && /(?:^|\s)--yes(?:\s|$)/.test(localizedExample)) {
out.write(` ${d(this.localize(HELP_TEXT.confirmedExample))}\n`);
}
const line = localizedExample.startsWith("#")
? localizedExample
: localizedExample
+9
View File
@@ -47,6 +47,13 @@ test("registry renders runtime help copy with the selected language", async () =
},
],
auth: "none",
risk: {
level: "high",
message: {
"en-US": "This operation is permanent.",
"zh-CN": "该操作无法撤销。",
},
},
run: async () => {},
});
const registry = new CommandRegistry({ test: command }, "bl", translator);
@@ -69,6 +76,8 @@ test("registry renders runtime help copy with the selected language", async () =
output = "";
registry.printHelp(["test"], stream);
expect(output).toContain("风险等级: 高风险");
expect(output).toContain("风险说明: 该操作无法撤销。");
expect(output).toContain("测试说明");
expect(output).toContain('bl test --message "你好"');
expect(output).toContain(" # 流式输出响应");
@@ -53,11 +53,12 @@ test("high risk 命令不能自行声明 runtime 保留的 yes", () => {
expect(() => new CommandRegistry({ "x normal": normal }, "bl")).not.toThrow();
});
test("命令 help 只为 high risk 展示 runtime 注入的 --yes", () => {
test("命令 help 只为 high risk 展示风险信息和 runtime 注入的 --yes", () => {
const high = defineCommand({
description: "danger",
auth: "none",
risk: { level: "high", message: "dangerous operation" },
exampleArgs: ["--dry-run", "--yes"],
run: noopRun,
});
const normal = defineCommand({
@@ -77,5 +78,10 @@ test("命令 help 只为 high risk 展示 runtime 注入的 --yes", () => {
} as unknown as NodeJS.WriteStream);
expect(highHelp).toContain("--yes");
expect(highHelp).toContain("Risk: high");
expect(highHelp).toContain("Risk message: dangerous operation");
expect(highHelp).toMatch(/# Only after explicit confirmation:\n\s+bl asset delete --yes/);
expect(normalHelp).not.toContain("--yes");
expect(normalHelp).not.toContain("Risk:");
expect(normalHelp).not.toContain("Risk message:");
});
+26 -25
View File
@@ -56,30 +56,30 @@ Do not guess flags — use the reference files or `--help`.
Use this table only after the decision table in [`bailian-protocol`](../bailian-protocol/SKILL.md#provider-selection-and-consent) has routed the request to `bl` (class 4, or class 2 after the user picks Bailian). Hub-owned intents only — for media / fine-tune / agents.yaml, soft hand-off to the domain skill.
| User intent | Command | Notes |
| ------------------------------------------------ | --------------------------------------------- | -------------------------------------------------------------------------------- |
| Explicit Bailian model chat / text execution | `bl text chat` | Default `qwen3.8-max` |
| Bailian agent / workflow | `bl app call` | Needs `--app-id` |
| Find app by name | `bl app list` then `bl app call` | Console auth |
| Bailian app memory CRUD (not host-agent memory) | `bl memory *` | [`reference/memory.md`](reference/memory.md) |
| Bailian knowledge base RAG | `bl knowledge search` / `chat` | API key + agent/workspace IDs |
| Upload a file as a step of a Bailian workflow | `bl file upload` | When you need `oss://` URL explicitly; not for generic hosting |
| Bailian model selection / recommendation | `bl advisor recommend` | Intent → candidate recall → LLM ranking |
| Bailian model catalog / pricing / params | `bl model list` | Console auth; `--model <family>` for detail, `--enrich` for input params |
| Install / list / update / remove registry skills | `bl skill add` / `list` / `update` / `remove` | Bailian skill registry; see [`reference/skill.md`](reference/skill.md) |
| Bailian MCP marketplace discovery / call | `bl mcp list` / `tools` / `call` | — |
| Bailian pipeline workflow (a step in a bl flow) | `bl pipeline run` / `validate` | JSON/YAML workflow definitions |
| Bailian rate limits / quota | `bl quota list` / `check` / `request` | Console auth; class 2 — ask which product first if unnamed |
| Bailian free tier / usage stats | `bl usage free` / `stats` / `freetier` | Console auth; class 2 — ask which product first if unnamed |
| Bailian Token Plan quota usage | `bl usage token-plan` | Console auth; class 2 — ask which product first if unnamed |
| Bailian Coding Plan quota usage | `bl usage coding-plan` | Console auth; class 2 — ask which product first if unnamed |
| Console API (advanced) | `bl console call` | Console auth |
| Bailian workspace listing | `bl workspace list` | Console auth |
| Switch CLI Help / Quick Start language | `bl config set --key language --value zh-CN` | Use `en-US` to switch back; follows the active config profile |
| Image / video / speech / omni / vision | → skill `bailian-gen` | Fallback: `bl image\|video\|speech\|omni\|vision --help` |
| Dataset / fine-tune / deploy | → skill `bailian-finetune` | Fallback: `bl dataset\|finetune\|deploy --help` |
| agents.yaml IaC / managed-agent sessions | → skill `bailian-managed-agent` | Fallback: `bl managed-agent --help`; `apply`/`destroy` need `--yes` after `plan` |
| Web search (model-aware routing) | → skill `bailian-web-search` | Token Plan vs MCP path + fallback; fallback: `bl search web --help` |
| User intent | Command | Notes |
| ------------------------------------------------ | --------------------------------------------- | -------------------------------------------------------------------------- |
| Explicit Bailian model chat / text execution | `bl text chat` | Default `qwen3.8-max` |
| Bailian agent / workflow | `bl app call` | Needs `--app-id` |
| Find app by name | `bl app list` then `bl app call` | Console auth |
| Bailian app memory CRUD (not host-agent memory) | `bl memory *` | [`reference/memory.md`](reference/memory.md) |
| Bailian knowledge base RAG | `bl knowledge search` / `chat` | API key + agent/workspace IDs |
| Upload a file as a step of a Bailian workflow | `bl file upload` | When you need `oss://` URL explicitly; not for generic hosting |
| Bailian model selection / recommendation | `bl advisor recommend` | Intent → candidate recall → LLM ranking |
| Bailian model catalog / pricing / params | `bl model list` | Console auth; `--model <family>` for detail, `--enrich` for input params |
| Install / list / update / remove registry skills | `bl skill add` / `list` / `update` / `remove` | Bailian skill registry; see [`reference/skill.md`](reference/skill.md) |
| Bailian MCP marketplace discovery / call | `bl mcp list` / `tools` / `call` | — |
| Bailian pipeline workflow (a step in a bl flow) | `bl pipeline run` / `validate` | JSON/YAML workflow definitions |
| Bailian rate limits / quota | `bl quota list` / `check` / `request` | Console auth; class 2 — ask which product first if unnamed |
| Bailian free tier / usage stats | `bl usage free` / `stats` / `freetier` | Console auth; class 2 — ask which product first if unnamed |
| Bailian Token Plan quota usage | `bl usage token-plan` | Console auth; class 2 — ask which product first if unnamed |
| Bailian Coding Plan quota usage | `bl usage coding-plan` | Console auth; class 2 — ask which product first if unnamed |
| Console API (advanced) | `bl console call` | Console auth |
| Bailian workspace listing | `bl workspace list` | Console auth |
| Switch CLI Help / Quick Start language | `bl config set --key language --value zh-CN` | Use `en-US` to switch back; follows the active config profile |
| Image / video / speech / omni / vision | → skill `bailian-gen` | Fallback: `bl image\|video\|speech\|omni\|vision --help` |
| Dataset / fine-tune / deploy | → skill `bailian-finetune` | Fallback: `bl dataset\|finetune\|deploy --help` |
| agents.yaml IaC / managed-agent sessions | → skill `bailian-managed-agent` | Fallback: `bl managed-agent --help`; `apply`/`destroy` also require `plan` |
| Web search (model-aware routing) | → skill `bailian-web-search` | Token Plan vs MCP path + fallback; fallback: `bl search web --help` |
Flags, usage, and examples: see hub [`reference/`](reference/index.md) or `bl <command> --help` — do not guess flags. Domain command details live in the owning skill's `reference/`.
@@ -123,6 +123,7 @@ schema-export commands.
- Usage / quota / credits questions that do not name a product → ask which product (Bailian or another AI service) first; run `bl usage` / `bl quota` only after the user picks Bailian or Bailian context is already established.
- "Remember this" and memory requests default to the host agent's own memory; `bl memory *` is only for Bailian app memory resources.
- `bl file upload` and `bl pipeline run` are steps inside a Bailian workflow; do not use them to capture generic "upload this file" or "run a pipeline" requests.
- `bl managed-agent apply` / `destroy` mutate remote resources and only execute with `--yes`; run `plan` first and show the diff before confirming a mutation.
- For `risk: high` commands or `requires_confirmation`, follow the shared protocol; never add `--yes` automatically.
- `bl managed-agent apply` / `destroy` have an additional domain rule: run `plan` first and show the diff before asking for confirmation.
- When a matched `bl` command accepts a file URL, pass local paths directly; never require the user to host the file first.
- Console login → always `--console-site domestic|international`; see [`../bailian-protocol/assets/setup.md`](../bailian-protocol/assets/setup.md#console-site-selection).
+71 -36
View File
@@ -82,12 +82,16 @@ bl knowledge category add --name sub --parent-id cate-xxx
### `bl knowledge category delete`
| Field | Value |
| ------------------ | --------------------------------------------------------- |
| **Name** | `knowledge category delete` |
| **Description** | Delete a data-center category |
| **Authentication** | API Key |
| **Usage** | `bl knowledge category delete --category-id <id> [flags]` |
| Field | Value |
| ------------------ | -------------------------------------------------------------------- |
| **Name** | `knowledge category delete` |
| **Description** | Delete a data-center category |
| **Authentication** | API Key |
| **Usage** | `bl knowledge category delete --category-id <id> [flags]` |
| **Risk** | `high` |
| **Risk message** | This deletes the selected data-center category and cannot be undone. |
> **Agent safety:** Never add `--yes` automatically. On `type="requires_confirmation"`, stop and ask for explicit user confirmation of the same action and scope.
#### Flags
@@ -110,6 +114,7 @@ bl knowledge category delete --category-id cate-xxx --workspace-id ws-xxx
```
```bash
# Only after explicit user confirmation:
bl knowledge category delete --category-id cate-xxx --yes
```
@@ -248,6 +253,10 @@ bl knowledge chunk add --index-id idx-xxx --field columnA=v1 --field columnB=v2
| **Description** | Delete chunks from a knowledge base (irreversible) |
| **Authentication** | API Key |
| **Usage** | `bl knowledge chunk delete --index-id <id> --chunk-id <id> [flags]` |
| **Risk** | `high` |
| **Risk message** | This permanently deletes the selected chunks and cannot be undone. |
> **Agent safety:** Never add `--yes` automatically. On `type="requires_confirmation"`, stop and ask for explicit user confirmation of the same action and scope.
#### Flags
@@ -271,6 +280,7 @@ bl knowledge chunk delete --index-id idx-xxx --chunk-id chunk-a --chunk-id chunk
```
```bash
# Only after explicit user confirmation:
bl knowledge chunk delete --index-id idx-xxx --chunk-id chunk-a --yes
```
@@ -461,12 +471,16 @@ bl knowledge create --name demo --description 'product docs' --category-id cate-
### `bl knowledge delete`
| Field | Value |
| ------------------ | --------------------------------------------------------- |
| **Name** | `knowledge delete` |
| **Description** | Delete a knowledge base with all its documents and chunks |
| **Authentication** | API Key |
| **Usage** | `bl knowledge delete --index-id <id> [flags]` |
| Field | Value |
| ------------------ | ------------------------------------------------------------------------------------------------------------------- |
| **Name** | `knowledge delete` |
| **Description** | Delete a knowledge base with all its documents and chunks |
| **Authentication** | API Key |
| **Usage** | `bl knowledge delete --index-id <id> [flags]` |
| **Risk** | `high` |
| **Risk message** | This permanently deletes the knowledge base and all of its documents and chunks. Data-center files are not deleted. |
> **Agent safety:** Never add `--yes` automatically. On `type="requires_confirmation"`, stop and ask for explicit user confirmation of the same action and scope.
#### Flags
@@ -490,17 +504,22 @@ bl knowledge delete --index-id idx-xxx --workspace-id ws-xxx
```
```bash
# Only after explicit user confirmation:
bl knowledge delete --index-id idx-xxx --yes
```
### `bl knowledge doc delete`
| Field | Value |
| ------------------ | --------------------------------------------------------------- |
| **Name** | `knowledge doc delete` |
| **Description** | Delete documents and their chunks from a knowledge base |
| **Authentication** | API Key |
| **Usage** | `bl knowledge doc delete --index-id <id> --doc-id <id> [flags]` |
| Field | Value |
| ------------------ | ------------------------------------------------------------------------ |
| **Name** | `knowledge doc delete` |
| **Description** | Delete documents and their chunks from a knowledge base |
| **Authentication** | API Key |
| **Usage** | `bl knowledge doc delete --index-id <id> --doc-id <id> [flags]` |
| **Risk** | `high` |
| **Risk message** | This permanently deletes the selected documents and all of their chunks. |
> **Agent safety:** Never add `--yes` automatically. On `type="requires_confirmation"`, stop and ask for explicit user confirmation of the same action and scope.
#### Flags
@@ -527,6 +546,7 @@ bl knowledge doc delete --index-id idx-xxx --doc-id file-xxx --workspace-id ws-x
```
```bash
# Only after explicit user confirmation:
bl knowledge doc delete --index-id idx-xxx --doc-id file-a --doc-id file-b --yes
```
@@ -728,12 +748,16 @@ bl knowledge doc upload --file ./docs/ --dry-run --verbose
### `bl knowledge file delete`
| Field | Value |
| ------------------ | ------------------------------------------------- |
| **Name** | `knowledge file delete` |
| **Description** | Permanently delete a file from the data center |
| **Authentication** | API Key |
| **Usage** | `bl knowledge file delete --file-id <id> [flags]` |
| Field | Value |
| ------------------ | -------------------------------------------------------------------------------------------------------------------- |
| **Name** | `knowledge file delete` |
| **Description** | Permanently delete a file from the data center |
| **Authentication** | API Key |
| **Usage** | `bl knowledge file delete --file-id <id> [flags]` |
| **Risk** | `high` |
| **Risk message** | This permanently deletes the data-center file. Knowledge-base document indexes that reference it may become invalid. |
> **Agent safety:** Never add `--yes` automatically. On `type="requires_confirmation"`, stop and ask for explicit user confirmation of the same action and scope.
#### Flags
@@ -757,6 +781,7 @@ bl knowledge file delete --file-id file-xxx --workspace-id ws-xxx
```
```bash
# Only after explicit user confirmation:
bl knowledge file delete --file-id file-xxx --yes
```
@@ -1032,12 +1057,16 @@ bl knowledge service create --name my-search --scene search --index-id idx-xxx
### `bl knowledge service delete`
| Field | Value |
| ------------------ | ---------------------------------------------------------- |
| **Name** | `knowledge service delete` |
| **Description** | Delete a retrieval / Q&A service (soft delete, idempotent) |
| **Authentication** | API Key |
| **Usage** | `bl knowledge service delete --agent-id <id> [flags]` |
| Field | Value |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------- |
| **Name** | `knowledge service delete` |
| **Description** | Delete a retrieval / Q&A service (soft delete, idempotent) |
| **Authentication** | API Key |
| **Usage** | `bl knowledge service delete --agent-id <id> [flags]` |
| **Risk** | `high` |
| **Risk message** | This deletes the service and makes its agent ID unavailable for search and chat calls. The operation cannot be undone. |
> **Agent safety:** Never add `--yes` automatically. On `type="requires_confirmation"`, stop and ask for explicit user confirmation of the same action and scope.
#### Flags
@@ -1062,17 +1091,22 @@ bl knowledge service delete --agent-id aid-xxx --workspace-id ws-xxx
```
```bash
# Only after explicit user confirmation:
bl knowledge service delete --agent-id aid-xxx --yes
```
### `bl knowledge service deploy`
| Field | Value |
| ------------------ | ----------------------------------------------------- |
| **Name** | `knowledge service deploy` |
| **Description** | Publish the beta draft of a service as a new version |
| **Authentication** | API Key |
| **Usage** | `bl knowledge service deploy --agent-id <id> [flags]` |
| Field | Value |
| ------------------ | ------------------------------------------------------------------------------------------------ |
| **Name** | `knowledge service deploy` |
| **Description** | Publish the beta draft of a service as a new version |
| **Authentication** | API Key |
| **Usage** | `bl knowledge service deploy --agent-id <id> [flags]` |
| **Risk** | `high` |
| **Risk message** | This publishes the current draft as a new version and changes the behavior seen by live callers. |
> **Agent safety:** Never add `--yes` automatically. On `type="requires_confirmation"`, stop and ask for explicit user confirmation of the same action and scope.
#### Flags
@@ -1098,6 +1132,7 @@ bl knowledge service deploy --agent-id aid-xxx --workspace-id ws-xxx
```
```bash
# Only after explicit user confirmation:
bl knowledge service deploy --agent-id aid-xxx --version-desc 'tuned rerank params' --yes
```
+13 -6
View File
@@ -109,12 +109,16 @@ bl permission list --output text
### `bl permission revoke`
| Field | Value |
| ------------------ | ----------------------------------------------------------------------------- |
| **Name** | `permission revoke` |
| **Description** | Revoke model permissions (inference / finetune / deploy) |
| **Authentication** | API Key |
| **Usage** | `bl permission revoke --model <models> [--action <actions>] \| --all [flags]` |
| Field | Value |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Name** | `permission revoke` |
| **Description** | Revoke model permissions (inference / finetune / deploy) |
| **Authentication** | API Key |
| **Usage** | `bl permission revoke --model <models> [--action <actions>] \| --all [flags]` |
| **Risk** | `high` |
| **Risk message** | This revokes model permissions and may interrupt inference, fine-tuning, or deployment workloads. With --all, it also clears all historical inference grants. |
> **Agent safety:** Never add `--yes` automatically. On `type="requires_confirmation"`, stop and ask for explicit user confirmation of the same action and scope.
#### Flags
@@ -137,14 +141,17 @@ bl permission list --output text
#### Examples
```bash
# Only after explicit user confirmation:
bl permission revoke --model qwen-plus --yes
```
```bash
# Only after explicit user confirmation:
bl permission revoke --model qwen-plus,qwen3-max --action inference,finetune --yes
```
```bash
# Only after explicit user confirmation:
bl permission revoke --all --yes
```
+1 -1
View File
@@ -33,7 +33,7 @@ description: >-
- Unsure which training methods a base model supports → `bl finetune capability --base-model <base>` or `--training-type sft|sft-lora|dpo|cpt`.
- Text `--training-type` values: `sft` / `sft-lora` / `dpo` / `dpo-lora` / `cpt`. Audio bases include `cosyvoice-v3-flash`; image bases include `wan2.7-image-pro`.
- Deployment plans: audio defaults to `--plan mu`; text/image default to `lora`.
- Preview write operations (create / delete / cancel / scale) with `--dry-run` first, and confirm with the user before deleting a job or dataset.
- For `risk: high` or `requires_confirmation`, follow `bailian-protocol`; never add `--yes` automatically.
## When to use which command
+10 -7
View File
@@ -8,7 +8,7 @@ description: >-
阿里云百炼托管 Agent 声明式基础设施入口:用户要创建agent、初始化 agents.yaml、校验或预览 agent 配置变更、
创建/更新/销毁百炼托管 Agent 或 Deployment、和托管 agent 对话、查会话事件历史、导入或取消跟踪远端资源时使用
`bl managed-agent`。以 agents.yaml 为唯一事实源做 IaC:init 建脚手架、validate 离线校验、plan 预览 diff、
apply / destroy 变更远端资源且必须带 `--yes`,务必先 plan 给用户看 diff 再让其确认。
apply / destroy 变更远端资源且受统一高风险确认闸门保护,务必先 plan 给用户看 diff 再让其确认,禁止自动添加 `--yes`。
反触发:调用已上线的百炼应用/智能体走 bailian-app-call 或 `bl app`;宿主 agent 自身的记忆、技能、
子代理不走本 skill;生图生视频走 bailian-gen。
官方安装:`bl skill init`(与共享协议 bailian-protocol 同装)。
@@ -16,15 +16,17 @@ description: >-
# Bailian managed agent IaC (`bl managed-agent`)
**CRITICAL — Before executing, MUST read the shared protocol in [`../bailian-protocol/SKILL.md`](../bailian-protocol/SKILL.md): Version & updates (pre-flight checklist) and CLI errors: report an issue. Command details are authoritative in [`reference/managed-agent.md`](reference/managed-agent.md) and `bl managed-agent --help` — do not guess flags. If that protocol file is missing, stop and run `bl skill init`; do not guess auth/consent.**
**CRITICAL — Before executing, MUST read the shared protocol in [`../bailian-protocol/SKILL.md`](../bailian-protocol/SKILL.md): High-risk operation confirmation, Version & updates (pre-flight checklist), and CLI errors: report an issue. Command details are authoritative in [`reference/managed-agent.md`](reference/managed-agent.md) and `bl managed-agent --help` — do not guess flags. If that protocol file is missing, stop and run `bl skill init`; do not guess auth/consent.**
## Safety guardrail (the most important rule)
`apply` / `destroy` **mutate remote resources** and only execute when `--yes` is passed:
`apply` / `destroy` **mutate remote resources** and add a domain-specific preview requirement on top of the shared high-risk confirmation protocol:
1. Always run `bl managed-agent plan` first and show the diff to the user.
2. Only after explicit user confirmation, retry `apply` / `destroy` with `--yes`.
3. Never add `--yes` on your own initiative before the user has confirmed.
2. Ask the user to confirm the exact action and scope shown in the plan.
3. Only then run `apply` / `destroy` with `--yes`; a changed plan requires confirmation again.
`session delete` and future `risk: high` commands follow the shared protocol.
## IaC lifecycle
@@ -32,8 +34,9 @@ description: >-
1. Init bl managed-agent init # scaffold agents.yaml
2. Validate bl managed-agent validate # offline, no network calls
3. Preview bl managed-agent plan # show the pending change diff
4. Apply bl managed-agent apply --yes # only after user confirmation
5. Destroy bl managed-agent destroy --yes # only after user confirmation
4. Confirm show the plan and ask the user # no automatic --yes
5. Apply bl managed-agent apply --yes # only after explicit confirmation
6. Destroy bl managed-agent destroy --yes # separate explicit confirmation
```
## Deployment as IaC
@@ -31,12 +31,16 @@ Index: [index.md](index.md)
### `bl managed-agent apply`
| Field | Value |
| ------------------ | -------------------------------------------------------------------------------- |
| **Name** | `managed-agent apply` |
| **Description** | Apply planned changes to create/update/delete agent resources |
| **Authentication** | API Key |
| **Usage** | `bl managed-agent apply [--file <path>] [--provider <name>] [--concurrency <n>]` |
| Field | Value |
| ------------------ | ----------------------------------------------------------------------------------------------- |
| **Name** | `managed-agent apply` |
| **Description** | Apply planned changes to create/update/delete agent resources |
| **Authentication** | API Key |
| **Usage** | `bl managed-agent apply [--file <path>] [--provider <name>] [--concurrency <n>]` |
| **Risk** | `high` |
| **Risk message** | This applies the current plan and may create, update, or delete remote managed Agent resources. |
> **Agent safety:** Never add `--yes` automatically. On `type="requires_confirmation"`, stop and ask for explicit user confirmation of the same action and scope.
#### Flags
@@ -59,21 +63,27 @@ Index: [index.md](index.md)
#### Examples
```bash
# Only after explicit user confirmation:
bl managed-agent apply --yes
```
```bash
# Only after explicit user confirmation:
bl managed-agent apply --provider bailian --yes
```
### `bl managed-agent destroy`
| Field | Value |
| ------------------ | ------------------------------------------------------ |
| **Name** | `managed-agent destroy` |
| **Description** | Destroy all managed agent resources tracked in state |
| **Authentication** | API Key |
| **Usage** | `bl managed-agent destroy [--file <path>] [--cascade]` |
| Field | Value |
| ------------------ | ---------------------------------------------------------------------------------------------------------- |
| **Name** | `managed-agent destroy` |
| **Description** | Destroy all managed agent resources tracked in state |
| **Authentication** | API Key |
| **Usage** | `bl managed-agent destroy [--file <path>] [--cascade]` |
| **Risk** | `high` |
| **Risk message** | This deletes every managed Agent resource tracked in state; --cascade may also delete dependent resources. |
> **Agent safety:** Never add `--yes` automatically. On `type="requires_confirmation"`, stop and ask for explicit user confirmation of the same action and scope.
#### Flags
@@ -94,10 +104,12 @@ bl managed-agent apply --provider bailian --yes
#### Examples
```bash
# Only after explicit user confirmation:
bl managed-agent destroy --yes
```
```bash
# Only after explicit user confirmation:
bl managed-agent destroy --yes --cascade
```
+9
View File
@@ -41,6 +41,15 @@ Ask templates for classes 2 and 3 (match the user's language):
After approval, treat Bailian as selected for the current task. Do not ask again for intermediate commands, polling, downloads, retries, or related follow-ups. Ask again only if the scope changes materially, such as a substantially larger cost or a destructive operation.
## High-risk operation confirmation (mandatory)
`risk: high` in a command reference or leaf `--help` marks a high-risk operation. For older CLI output without this field, treat `--yes` as the conservative fallback. Exit code **7** with `error.type: "requires_confirmation"` is an expected stop signal, not a CLI bug.
- Never add `--yes` automatically.
- Show the risk message and a safe summary of the action, target, and scope without exposing credentials, then ask for explicit confirmation.
- Only after confirmation, re-run the same operation with `--yes`. Any material change to the scope requires confirmation again.
- If the user declines or does not answer, stop.
## Family routing & hand-offs
业务路由(**软 hand-off**:按 skill **名**路由;已安装则 Read 其 `SKILL.md`,未安装则用 `bl <cmd> --help`,或提示整包安装
@@ -15,7 +15,7 @@ When `bl` fails, the agent first helps the user fix the problem. If the failure
function shouldOfferIssueReport(exitCode, apiCode, message, hint):
# Step 1: Unambiguous EXCLUDE by exit code
if exitCode in [2 (USAGE), 3 (AUTH), 4 (QUOTA), 10 (CONTENT_FILTER)]:
if exitCode in [2 (USAGE), 3 (AUTH), 4 (QUOTA), 7 (CONFIRMATION_REQUIRED), 10 (CONTENT_FILTER)]:
return EXCLUDE # help user fix; never offer reporting
# Step 2: NETWORK / TIMEOUT — exclude if hint is actionable
@@ -69,18 +69,19 @@ function matchesIncludeCriteria(exitCode, apiCode, message):
These are **user**, **environment**, or **service business** errors. Give fix hints; do not ask to file an issue.
| Category | Signal | Examples |
| -------------------------- | -------------------------------------- | ------------------------------------------------------------------------------- |
| **Usage / args** | Exit code **2** (USAGE) | Missing flag, invalid path, unknown subcommand, local file not found |
| **Auth** | Exit code **3** (AUTH) | No API key, invalid key, expired console token |
| **Quota** | Exit code **4** (QUOTA) | Free tier exhausted, rate limit / quota messages |
| **Content filter** | Exit code **10** (CONTENT_FILTER) | Content moderation blocked the request |
| **Model not found** | Message or `api_code` | `ModelNotFound`, `invalid_request_error` naming a bad model, HTTP 404 for model |
| **Invalid API params** | USAGE or service validation | `InvalidParameter`, `invalid_request_error` for bad `--size`, `--format`, etc. |
| **Free quota query** | `bl usage free` business result | Quota used up — not a CLI defect |
| **Obvious local env** | Hint is sufficient | `ENOENT` / `EACCES`, wrong file path, disk full |
| **Network (self-service)** | Exit code **6** (NETWORK) + clear hint | DNS, proxy, TLS — user fixes `DASHSCOPE_BASE_URL`, proxy, or network |
| **Timeout (self-service)** | Exit code **5** (TIMEOUT) + hint works | Increase `--timeout`, check `base_url` with `bl auth status` |
| Category | Signal | Examples |
| -------------------------- | ----------------------------------------- | ------------------------------------------------------------------------------- |
| **Usage / args** | Exit code **2** (USAGE) | Missing flag, invalid path, unknown subcommand, local file not found |
| **Auth** | Exit code **3** (AUTH) | No API key, invalid key, expired console token |
| **Quota** | Exit code **4** (QUOTA) | Free tier exhausted, rate limit / quota messages |
| **Confirmation required** | Exit code **7** + `requires_confirmation` | Expected high-risk control flow; ask the user, never auto-retry with `--yes` |
| **Content filter** | Exit code **10** (CONTENT_FILTER) | Content moderation blocked the request |
| **Model not found** | Message or `api_code` | `ModelNotFound`, `invalid_request_error` naming a bad model, HTTP 404 for model |
| **Invalid API params** | USAGE or service validation | `InvalidParameter`, `invalid_request_error` for bad `--size`, `--format`, etc. |
| **Free quota query** | `bl usage free` business result | Quota used up — not a CLI defect |
| **Obvious local env** | Hint is sufficient | `ENOENT` / `EACCES`, wrong file path, disk full |
| **Network (self-service)** | Exit code **6** (NETWORK) + clear hint | DNS, proxy, TLS — user fixes `DASHSCOPE_BASE_URL`, proxy, or network |
| **Timeout (self-service)** | Exit code **5** (TIMEOUT) + hint works | Increase `--timeout`, check `base_url` with `bl auth status` |
**Rule:** If the authoritative source of the error is the **service response** or **user input**, treat it as non-reportable (same boundary as the CLI repo’s error-handling docs).
@@ -337,15 +338,16 @@ Do **not** block on `gh` — always provide a manual path.
## Exit codes (reference)
| Code | Name | Usually reportable? |
| ---- | -------------- | ----------------------------------------------- |
| 0 | SUCCESS | — |
| 1 | GENERAL | Sometimes (if CLI bug, not service passthrough) |
| 2 | USAGE | No |
| 3 | AUTH | No |
| 4 | QUOTA | No |
| 5 | TIMEOUT | Rarely (after user fixes env) |
| 6 | NETWORK | Rarely (after user fixes env) |
| 10 | CONTENT_FILTER | No |
| Code | Name | Usually reportable? |
| ---- | --------------------- | ----------------------------------------------- |
| 0 | SUCCESS | — |
| 1 | GENERAL | Sometimes (if CLI bug, not service passthrough) |
| 2 | USAGE | No |
| 3 | AUTH | No |
| 4 | QUOTA | No |
| 5 | TIMEOUT | Rarely (after user fixes env) |
| 6 | NETWORK | Rarely (after user fixes env) |
| 7 | CONFIRMATION_REQUIRED | No — expected high-risk control flow |
| 10 | CONTENT_FILTER | No |
JSON errors use the same numeric `error.code` field when `--output json` is set.
+23 -3
View File
@@ -128,7 +128,11 @@ function formatFlagsTable(flags: FlagsDef | undefined): string {
].join("\n");
}
function formatExamples(path: string, exampleArgs: LocalizedText[] | undefined): string {
function formatExamples(
path: string,
exampleArgs: LocalizedText[] | undefined,
highRisk: boolean,
): string {
if (!exampleArgs?.length) return "_No examples._\n";
// Commands store argument-only examples; prepend `bl <path>` for the reference.
return (
@@ -136,7 +140,11 @@ function formatExamples(path: string, exampleArgs: LocalizedText[] | undefined):
.map((example) => {
const text = referenceText(example);
const line = text.startsWith("#") ? text : `bl ${path}${text ? ` ${text}` : ""}`;
return ["```bash", line, "```"].join("\n");
const confirmationComment =
highRisk && /(?:^|\s)--yes(?:\s|$)/.test(text)
? ["# Only after explicit user confirmation:"]
: [];
return ["```bash", ...confirmationComment, line, "```"].join("\n");
})
.join("\n\n") + "\n"
);
@@ -157,8 +165,20 @@ function commandSection(path: string, cmd: AnyCommand): string {
// Commands store argument-only usage; the `bl <path>` prefix is added here.
const usage = `bl ${path}${cmd.usageArgs ? ` ${cmd.usageArgs}` : ""}`;
lines.push(`| **Usage** | \`${escCell(usage)}\` |`);
if (cmd.risk !== undefined) {
lines.push(`| **Risk** | \`${cmd.risk.level}\` |`);
lines.push(`| **Risk message** | ${escCell(referenceText(cmd.risk.message))} |`);
}
lines.push("");
if (cmd.risk !== undefined) {
lines.push(
'> **Agent safety:** Never add `--yes` automatically. On `type="requires_confirmation"`, ' +
"stop and ask for explicit user confirmation of the same action and scope.",
"",
);
}
// 与命令 help 的 Flags 区一致:自有 + 该命令可见的凭证域 flag。
lines.push("#### Flags", "");
lines.push(
@@ -175,7 +195,7 @@ function commandSection(path: string, cmd: AnyCommand): string {
}
lines.push("#### Examples", "");
lines.push(formatExamples(path, cmd.exampleArgs));
lines.push(formatExamples(path, cmd.exampleArgs, cmd.risk !== undefined));
return lines.join("\n");
}