mirror of
https://github.com/modelstudioai/cli.git
synced 2026-09-14 19:49:23 +08:00
docs(agents): align maintenance guides with split CLI architecture
This commit is contained in:
@@ -1,45 +1,54 @@
|
||||
# bailian-cli — AI 维护指南
|
||||
|
||||
本文件是 AI agent 维护本仓库时的契约。每次进入项目首先读这里,从下方"业务场景索引"挑一条,跳到对应的详细文档,按它的清单完成改动。
|
||||
本文件是 AI agent 维护本仓库时的契约。每次进入项目先读这里,从"业务场景索引"挑一条,再进入对应 `docs/agents/*.md` 清单。
|
||||
|
||||
## 项目地图
|
||||
|
||||
monorepo 双包结构:
|
||||
monorepo 现在按"纯逻辑 → 运行时框架 → 命令库 → 产品入口"分层:
|
||||
|
||||
- `packages/cli` — `bailian-cli` 包,CLI 命令、UI、入口
|
||||
- `packages/core` — `bailian-cli-core` 包,鉴权 / HTTP / 类型,纯逻辑层
|
||||
- `packages/core` — `bailian-cli-core`,纯逻辑层:鉴权、配置、HTTP client、错误、类型、文件工具
|
||||
- `packages/runtime` — `bailian-cli-runtime`,通用 CLI 运行时:`createCli`、参数解析、registry/help、middleware、error handler、输出、pipeline
|
||||
- `packages/commands` — `bailian-cli-commands`,可复用命令实现库,只导出 command,不决定产品路径
|
||||
- `packages/cli` — `bailian-cli`,完整 `bl` 产品入口;`src/commands.ts` 组装 `bl` 暴露的命令路径
|
||||
- `packages/rag` — `bailian-cli-rag`,知识库向入口;`src/main.ts` 复用 commands 并重映射为 `rag` 路径
|
||||
|
||||
### `packages/cli` 目录要点
|
||||
### 关键文件
|
||||
|
||||
```
|
||||
packages/cli/
|
||||
├── src/
|
||||
│ ├── main.ts # 入口、鉴权分支、调用 registry
|
||||
│ ├── registry.ts # 命令树解析、动态 help(读 catalog)
|
||||
│ ├── commands/
|
||||
│ │ ├── catalog.ts # 命令总表(登记处,构建脚本也读它)
|
||||
│ │ ├── index.ts # re-export commands
|
||||
│ │ └── <group>/...ts # 各命令 defineCommand 实现
|
||||
│ ├── output/ # CLI 输出、prompt、progress
|
||||
│ └── urls.ts # 控制台/文档 URL(仅 cli)
|
||||
└── tests/e2e/
|
||||
packages/cli/src/main.ts # bl 入口,注入 binName/version/clientName/npmPackage
|
||||
packages/cli/src/commands.ts # bl 产品命令 map,tools/generate-reference.ts 也读它
|
||||
packages/rag/src/main.ts # rag 入口和命令 map
|
||||
|
||||
packages/commands/src/index.ts # re-export 单个命令实现
|
||||
packages/commands/src/commands/ # defineCommand({ auth, flags, usageArgs, exampleArgs, run })
|
||||
|
||||
packages/runtime/src/create-cli.ts # createCli(commands, identity)
|
||||
packages/runtime/src/registry.ts # 命令树解析 + 动态 help
|
||||
packages/runtime/src/middleware.ts # auth / telemetry / update / run command
|
||||
packages/runtime/src/urls.ts # 用户面控制台 URL
|
||||
|
||||
packages/core/src/types/command.ts # Command / flags / auth 类型
|
||||
packages/core/src/config/ # ConfigFile / Settings / source 解析
|
||||
packages/core/src/auth/ # apiKey / console credential 解析与落盘
|
||||
packages/core/src/client/ # HTTP client / endpoints / console gateway
|
||||
```
|
||||
|
||||
Skill / 命令手册随 `skills/bailian-cli/` 经 `npx skills add modelstudioai/cli` 安装。`tools/generate-reference.ts` 从 `catalog.ts` 生成命令手册到 `skills/bailian-cli/reference/`(纳入 git);与 `tools/sync-skill-metadata.ts` 一起在 **pre-commit**(`.vite-hooks/pre-commit`)及根脚本 `pnpm run sync:skill-assets` 中执行。
|
||||
|
||||
非代码资产:
|
||||
|
||||
- `tools/release/` — 发版自动化(CI 驱动,见 `.github/workflows/publish.yml`)
|
||||
- `tools/generate-reference.ts` — 从 `catalog.ts` 生成命令手册到 `skills/bailian-cli/reference/`
|
||||
- `tools/sync-skill-metadata.ts` — 从 `packages/cli/package.json` 同步 `skills/bailian-cli/SKILL.md` 的 `metadata.version`(与 `generate:reference` 一并由根目录 `pnpm run sync:skill-assets` 及 pre-commit 执行)
|
||||
- `README.md` / `README.zh.md` — npm 和 GitHub 主页
|
||||
Skill / 命令手册随 `skills/bailian-cli/` 经 `npx skills add modelstudioai/cli` 安装。`tools/generate-reference.ts` 从 **`packages/cli/src/commands.ts`** 生成 `skills/bailian-cli/reference/`(纳入 git);`tools/sync-skill-metadata.ts` 从 `packages/cli/package.json` 同步 `skills/bailian-cli/SKILL.md` 的 `metadata.version`。两者由根脚本 `pnpm run sync:skill-assets` 和 `.vite-hooks/pre-commit` 执行。
|
||||
|
||||
约定:
|
||||
|
||||
- core 是纯库,不依赖 cli(详见下方通用约定)
|
||||
- 文件路径与命令路径一一对应:`commands/text/chat.ts` ↔ `bl text chat`
|
||||
- 单级命令:`commands/<name>.ts`(如 `update.ts`);两级:`commands/<group>/<action>.ts`
|
||||
- 命令登记在 **`catalog.ts`**;`bl --help` 与 `tools/generate-reference.ts` 生成的命令手册同源,见 [command-add-remove.md](docs/agents/command-add-remove.md)
|
||||
- 命令实现文件路径仍按能力放置:`packages/commands/src/commands/text/chat.ts`
|
||||
- 产品命令路径由入口 map 决定:同一个实现可暴露为 `bl knowledge retrieve` 或 `rag retrieve`
|
||||
- `defineCommand` 只写命令元数据与逻辑: `auth`、`flags`、`usageArgs`、`exampleArgs`、`validate`、`run`
|
||||
- `usageArgs` / `exampleArgs` 不写 `bl` 或 `rag` 前缀;runtime / reference 生成器按产品路径补前缀
|
||||
- 不再使用 `catalog.ts` 作为登记处;新增/重命名命令必须同时看命令库导出和产品入口 map
|
||||
|
||||
非代码资产:
|
||||
|
||||
- `tools/release/` — 发版自动化(CI 驱动,见 `.github/workflows/publish.yml`)
|
||||
- `tools/generate-reference.ts` — 从 `packages/cli/src/commands.ts` 生成 `skills/bailian-cli/reference/`
|
||||
- `tools/sync-skill-metadata.ts` — 同步 `skills/bailian-cli/SKILL.md` 的 `metadata.version`
|
||||
- `README.md` / `README.zh.md` — npm 和 GitHub 主页
|
||||
|
||||
## 业务场景索引
|
||||
|
||||
@@ -47,7 +56,7 @@ Skill / 命令手册随 `skills/bailian-cli/` 经 `npx skills add modelstudioai/
|
||||
|
||||
| 场景 | 何时进入 | 详见 |
|
||||
| -------------- | -------------------------------------------- | ------------------------------------------------------------------------ |
|
||||
| 命令增删改 | 增加 / 删除 / 重命名 `bl xxx` | [docs/agents/command-add-remove.md](docs/agents/command-add-remove.md) |
|
||||
| 命令增删改 | 增加 / 删除 / 重命名 `bl xxx` 或入口命令路径 | [docs/agents/command-add-remove.md](docs/agents/command-add-remove.md) |
|
||||
| E2E 测试维护 | 新增/改命令或 e2e 用例、补 help/缺参/dry-run | [docs/agents/cli-e2e-tests.md](docs/agents/cli-e2e-tests.md) |
|
||||
| 批量压测 | 改/跑多能力并发压测、`test:stress`、fixtures | [docs/agents/stress-batch-tests.md](docs/agents/stress-batch-tests.md) |
|
||||
| 选项变更 | 给已有命令加 `--flag` 或改默认值 | [docs/agents/command-flag-change.md](docs/agents/command-flag-change.md) |
|
||||
@@ -57,26 +66,24 @@ Skill / 命令手册随 `skills/bailian-cli/` 经 `npx skills add modelstudioai/
|
||||
| 鉴权扩展 | 加 OAuth / SSO / 换 token 来源 | [docs/agents/auth-change.md](docs/agents/auth-change.md) |
|
||||
| 配置项扩展 | 新 env var 或 `~/.bailian/config.json` 字段 | [docs/agents/config-add.md](docs/agents/config-add.md) |
|
||||
| 发布 | channel / stable 发布到 npm(CI 驱动) | [docs/agents/publish.md](docs/agents/publish.md) |
|
||||
| Change Log | 发版说明 / 历史版本说明 | [docs/agents/changelog-write.md](docs/agents/changelog-write.md) |
|
||||
| 工具链调整 | lint 规则 / 构建配置 / 依赖升级 | [docs/agents/lint-toolchain.md](docs/agents/lint-toolchain.md) |
|
||||
|
||||
如果当前任务无法对应任何场景,先按经验完成,然后**回来评估这是不是一类新场景** —— 是就新增一份 `docs/agents/<scenario>.md`,把清单沉淀下来。
|
||||
如果当前任务无法对应任何场景,先按经验完成,然后**回来评估这是不是一类新场景** —— 是就新增 `docs/agents/<scenario>.md`,把清单沉淀下来。
|
||||
|
||||
## 通用约定
|
||||
|
||||
下面两条与场景无关,任何改动都适用。每次完成改动后自查。
|
||||
### 1. 发布包版本号同步
|
||||
|
||||
### 1. cli 和 core 版本号同步
|
||||
源码包的 `version` 当前保持一致: `packages/core`、`packages/runtime`、`packages/commands`、`packages/cli`、`packages/rag`。做版本 bump 时一动多动。release 工具当前强校验 / 发布范围以 `tools/release/lib/packages.mjs` 为准;把新包纳入发布前必须同步该清单和 [publish.md](docs/agents/publish.md)。
|
||||
|
||||
`packages/cli/package.json` 和 `packages/core/package.json` 的 `version` 字段必须始终相等。一动两动。
|
||||
### 2. 分层边界
|
||||
|
||||
### 2. core 是纯库,cli 是 core 的 UI 层
|
||||
|
||||
core 不应该知道 cli 的存在。具体表现:
|
||||
|
||||
- core 不写 stderr,不调 `process.exit`(用 `console.*` 或 `throw`)
|
||||
- core 抛的 `BailianError`,hint 字符串不出现 `bl xxx` 命令名
|
||||
- core 不写死域名 / region / 追踪参数(URL 集中在 `packages/cli/src/urls.ts`)
|
||||
- core 接收 cli 通过 `Config` 注入的 metadata(`clientName` / `clientVersion`)
|
||||
- `core` 是纯库:不依赖 `runtime` / `commands` / 产品入口;不调 `process.exit`;新增/改动时不硬编码 `bl` / `rag` 命令名、控制台 URL 或渠道追踪参数。当前遗留项见 [error-hint-change.md](docs/agents/error-hint-change.md) 与 [url-change.md](docs/agents/url-change.md),触碰相关代码时顺手收敛
|
||||
- `runtime` 是通用 CLI 框架:可以处理 TTY、help、错误输出、middleware,但不写具体业务命令逻辑
|
||||
- `commands` 是命令实现库:不决定产品路径;不在 `usageArgs` / `exampleArgs` / hint 里硬编码产品 bin 前缀
|
||||
- `cli` / `rag` 是产品层:负责命令路径 map、产品 identity、README、技能 reference、发版入口
|
||||
- URL 集中在 `packages/runtime/src/urls.ts`(用户面控制台)和 `packages/core/src/config/schema.ts` / client 层(API)
|
||||
|
||||
### 3. 错误处理边界:CLI 不翻译服务端错误
|
||||
|
||||
@@ -86,30 +93,22 @@ CLI 只为「自己能权威解释的错误」发出语义化信号,服务端的
|
||||
| ---------------------------------------------------- | -------- | ----------------------------------------------------------- |
|
||||
| 命令解析、缺 flag、参数校验 | **内部** | `BailianError(USAGE)` |
|
||||
| 文件 I/O(ENOENT/EACCES/...) | **内部** | `BailianError(GENERAL)` + errno-specific hint |
|
||||
| 本地 credentials 缺失(resolver/ensure-key/AK-SK 等) | **内部** | `BailianError(AUTH)` |
|
||||
| 本地 credentials 缺失(resolver / auth stage 等) | **内部** | `BailianError(AUTH)` |
|
||||
| `fetch` 自身失败(DNS/TCP/TLS/proxy) | **内部** | `BailianError(NETWORK)` + 读 `err.cause.code` 给 errno-hint |
|
||||
| polling 客户端超时 | **内部** | `BailianError(TIMEOUT)` |
|
||||
| HTTP 4xx/5xx、HTTP 200 + 业务错码、async task FAILED | **服务** | `BailianError(GENERAL)`,**message 原样透传**,不分类、不替换 |
|
||||
|
||||
不要扮演服务端错误的翻译官——我们没有最新的错误码体系认知,二次包装只会撒谎(详见 `docs/agents/error-hint-change.md` 中的反面 case)。
|
||||
不要扮演服务端错误的翻译官——我们没有最新的错误码体系认知,二次包装只会撒谎。
|
||||
|
||||
### 4. Console Gateway 命令必须声明 console 全局 flags
|
||||
### 4. Console Gateway 命令必须声明鉴权域
|
||||
|
||||
如果新命令使用了 `callConsoleGateway`,必须在 `options` 中添加以下三个全局 flag 的说明,以便 `--help` 中展示:
|
||||
|
||||
```ts
|
||||
{ flag: "--console-region <region>", description: "Console region" },
|
||||
{ flag: "--console-site <site>", description: "Console site: domestic, international" },
|
||||
{ flag: "--console-switch-agent <uid>", description: "Switch agent UID", type: "number" },
|
||||
```
|
||||
|
||||
这些 flag 已在 `GLOBAL_OPTIONS`(`packages/core/src/types/command.ts`)中注册,由 `loadConfig` 写入 `config.consoleRegion` / `config.consoleSite` / `config.consoleSwitchAgent`,`callConsoleGateway` 自动读取——命令无需手动提取或传递。
|
||||
如果命令调用 Console Gateway,`defineCommand` 必须设置 `auth: "console"`。runtime 会基于 `CONSOLE_AUTH_FLAGS` 自动在 help 中展示 `--console-region`、`--console-site`、`--console-switch-agent`、`--workspace-id`,并由 `authStage` 解析/注入 console credential。命令不要重复声明这些凭证域 flag,也不要手动从 env/config 解析 token。
|
||||
|
||||
## 完成改动后的快速验证
|
||||
|
||||
```sh
|
||||
vp check # format + lint + type check
|
||||
vp test # unit + e2e (e2e 需 API key)
|
||||
vp test # unit + e2e (真实集成需 API key / console token)
|
||||
```
|
||||
|
||||
## 这份指南本身怎么演化
|
||||
|
||||
+79
-61
@@ -2,97 +2,106 @@
|
||||
|
||||
## 触发条件
|
||||
|
||||
- 增加新的鉴权方式(OAuth、SSO、控制台回调登录)
|
||||
- 增加新的 token 来源(env / config / flag / 文件)
|
||||
- 调整凭证解析优先级
|
||||
- 改 `bl auth login` 流程
|
||||
- 增加新的鉴权域或 token 来源(env / config / flag / 文件)
|
||||
- 调整 API Key / Console token 解析优先级
|
||||
- 改 `bl auth login` / `auth status` / `auth logout` 流程
|
||||
- 改 runtime 对 command `auth` 的 gating 或 credential 注入
|
||||
|
||||
## 鉴权链路
|
||||
|
||||
```
|
||||
flag 优先 ─→ config 文件 ─→ env var
|
||||
│ │ │
|
||||
└──── resolveCredential() (core) ───┐
|
||||
│
|
||||
▼
|
||||
cli/utils/ensure-key.ts (启动时拦)
|
||||
命令注入 Authorization 头
|
||||
argv flags ─┐
|
||||
env var ──┼─ buildSources(flags) ─┐
|
||||
config ──┘ │
|
||||
├─ buildSettings(sources) → ctx.settings
|
||||
│
|
||||
├─ resolveApiKey(sources) → model-domain Client
|
||||
└─ resolveConsole(sources) → console-domain Client
|
||||
|
||||
defineCommand({ auth }) → runtime/authStage → ctx.client → command.run(ctx)
|
||||
```
|
||||
|
||||
凭证类型(`AuthMethod`):
|
||||
当前 command 鉴权域(`AuthRequirement`):
|
||||
|
||||
- `api-key` — DashScope SK(`sk-...`),走 Bearer 头
|
||||
- `access-token` — 控制台 OAuth 回调拿到的临时 token,走 Bearer + 不同 endpoint
|
||||
- `ak/sk` — Alibaba Cloud 标准 AK/SK,走 ROA 签名(只用于知识库)
|
||||
- `apiKey` — DashScope / OpenAI-compatible 模型域,用 API key 与 model base URL
|
||||
- `console` — Bailian Console Gateway,用 console access token + region/site/switchAgent/workspace
|
||||
- `none` — 本地命令、登录/配置类命令、无需 credential 的命令
|
||||
|
||||
### 双凭证并存(API Key + Console)
|
||||
|
||||
`~/.bailian/config.json` 可同时保存 `api_key` 与 `access_token`。**登录任一种方式不得删除另一种**(`bl auth login --api-key` / `--console` 只更新对应字段)。
|
||||
`~/.bailian/config.json` 可同时保存 `api_key` 与 `access_token`。登录任一种方式不得删除另一种:
|
||||
|
||||
- `bl auth login --api-key ...` 只更新 `api_key` / `base_url`
|
||||
- `bl auth login --console` 只更新 `access_token` 以及回调携带的 console 作用域字段
|
||||
- `bl auth logout --console` 只清 `access_token`
|
||||
- `bl auth logout` 清 `api_key` + `access_token`
|
||||
|
||||
解析分工:
|
||||
|
||||
- `resolveCredential()` — DashScope API 命令(`text chat`、`file upload` 等);config 里两者都有时 **优先 `api_key`**
|
||||
- `resolveConsoleGatewayCredential()` — 控制台网关(`app list`、`usage free`、`console call`);**只用** env/file 的 `access_token`,忽略 `api_key`
|
||||
- `resolveApiKey()` — `auth: "apiKey"` 命令;优先级 `--api-key` > `DASHSCOPE_API_KEY` > config `api_key`
|
||||
- `resolveModelBaseUrl()` — model base URL;优先级 `--base-url` > `DASHSCOPE_BASE_URL` > config `base_url` > `REGIONS.cn`
|
||||
- `resolveConsole()` — `auth: "console"` 命令;当前 token 来自 config `access_token`,region/site/switchAgent 来自 flag > config > 默认
|
||||
- `describeAuthState()` — `auth status` / banner / telemetry 使用的只读快照
|
||||
|
||||
必改调用点: 凡 `callConsoleGateway` 必须用 `resolveConsoleGatewayCredential`,不能误用 `resolveCredential`(否则 config 仅有 api_key 时会拿 sk- 打网关)。
|
||||
|
||||
`bl auth logout --console` 只清 `access_token`;全量 `bl auth logout` 清两者。
|
||||
命令不要直接解析 token、env 或 config。业务请求统一走 `ctx.client`;登录/配置命令通过 `ctx.authStore()` / `ctx.configStore()` 的窄接口操作落盘。
|
||||
|
||||
## 必查清单
|
||||
|
||||
### A. core 层(类型 + 解析)
|
||||
|
||||
- [ ] `packages/core/src/types/command.ts`:
|
||||
- 如新增鉴权域,扩展 `AuthRequirement`
|
||||
- 更新 `credentialFlagDefs()` 暴露该域可见的 flag
|
||||
- 必要时新增 `*_AUTH_FLAGS`
|
||||
- [ ] `packages/core/src/auth/types.ts`:
|
||||
- 新增 `AuthMethod` 字面量
|
||||
- 新增 `ResolvedCredential` 字段(如 token 类型 / 过期时间)
|
||||
- 新增 credential 类型 / source / scope 字段
|
||||
- [ ] `packages/core/src/auth/resolver.ts`:
|
||||
- `resolveCredential()` 增加新分支
|
||||
- 控制台网关命令用 `resolveConsoleGatewayCredential()`(与 DashScope 解析分离)
|
||||
- 优先级注释保持清晰(数字标号)
|
||||
- [ ] `packages/core/src/auth/credentials.ts`:
|
||||
- 如果新方式需要持久化,加 `save*` / `load*` / `clear*`
|
||||
- 新增或调整 resolver,保持优先级注释清晰
|
||||
- 新增/调整 resolver hint 时保持产品无关,不要新增 `bl` / `rag` 硬编码;当前遗留的 `bl auth login` hint 如被触碰,迁到 runtime `enhanceHint`
|
||||
- [ ] `packages/core/src/auth/store.ts`:
|
||||
- 如果新方式需要持久化,扩展 `AuthStore` / `AuthPersistPatch`
|
||||
- [ ] `packages/core/src/config/schema.ts`:
|
||||
- `Config` 接口加新字段(如 `fileAccessToken`、`accessTokenEnv`)
|
||||
- `ConfigFile` 接口加对应 disk 字段(snake_case)
|
||||
- `ConfigFile` 加 disk 字段(snake_case)
|
||||
- `Settings` 加运行时字段(如果命令需要读取)
|
||||
- [ ] `packages/core/src/config/loader.ts`:
|
||||
- `loadConfig()` 把 env / 文件读到 Config 上
|
||||
- `buildSources()` / `buildSettings()` 把 flag/env/file 读到正确层
|
||||
|
||||
### B. core 客户端
|
||||
### B. runtime 层
|
||||
|
||||
- [ ] `packages/core/src/client/http.ts`:
|
||||
- 不同 `credential.method` 走不同分支(参考已有 `access-token` 分支走 console gateway)
|
||||
- Authorization 头注入正确
|
||||
- [ ] `packages/runtime/src/create-cli.ts`:
|
||||
- parse flags 时纳入新的全局/凭证域 flag
|
||||
- `globalFlags` 与 `ownFlags` 分流正确
|
||||
- [ ] `packages/runtime/src/middleware.ts:authStage`:
|
||||
- 根据 `command.auth` 解析 credential 并注入 `ctx.client`
|
||||
- `settings.dryRun` 下是否允许缺 credential 的策略明确
|
||||
- [ ] `packages/runtime/src/error-handler.ts`:
|
||||
- AUTH hint 增强使用 `binName`,不要硬编码 `bl`
|
||||
- URL 从 `packages/runtime/src/urls.ts` import
|
||||
|
||||
### C. cli 层
|
||||
### C. command 层
|
||||
|
||||
- [ ] `packages/cli/src/utils/ensure-key.ts`:
|
||||
- 启动时检查新凭证方式是否已配置,缺的话提示
|
||||
- 如果是交互式 setup(类似 `bl auth login --console`),增加新分支
|
||||
- [ ] `packages/cli/src/commands/auth/login.ts`:
|
||||
- 新增 `--xxx` flag 触发新登录流程
|
||||
- 持久化到 config(调用 core 的 save 函数)
|
||||
- [ ] `packages/cli/src/commands/auth/status.ts`:
|
||||
- 分别显示 `api_key` / `access_token` 是否已配置,以及 DashScope vs 控制台网关各自生效的 credential
|
||||
- [ ] `packages/cli/src/output/status-bar.ts`:
|
||||
- 顶部状态条显示新凭证 method
|
||||
- [ ] `packages/commands/src/commands/auth/login.ts`:
|
||||
- 新增/调整登录 flag 与流程
|
||||
- 持久化只走 `ctx.authStore().login(...)`
|
||||
- [ ] `packages/commands/src/commands/auth/status.ts`:
|
||||
- 分别显示 model / console 鉴权状态,并 mask token
|
||||
- [ ] `packages/commands/src/commands/auth/logout.ts`:
|
||||
- 清理范围与双凭证并存规则一致
|
||||
- [ ] 新的业务命令设置正确 `auth`:
|
||||
- 模型域请求 → `auth: "apiKey"`
|
||||
- Console Gateway → `auth: "console"`
|
||||
- 本地/登录/配置 → `auth: "none"`
|
||||
|
||||
### D. main 启动逻辑
|
||||
|
||||
- [ ] 若新增命令**自行处理鉴权**或**不应在入口触发默认 API key 引导**,在对应 `defineCommand` 上设 `skipDefaultApiKeySetup: true`(见 `packages/core/src/types/command.ts`;`packages/cli/src/main.ts` 在 `registry.resolve` 后读取 `command.skipDefaultApiKeySetup`)
|
||||
|
||||
### E. 错误文案
|
||||
|
||||
- [ ] core 的 `BailianError` 鉴权失败 hint **保持通用**(不写 cli 命令名,见 [error-hint-change.md](error-hint-change.md))
|
||||
- [ ] cli 的 `enhanceHint` (error-handler.ts) 按 `ExitCode.AUTH` 注入新方式的 cli 命令引导
|
||||
|
||||
### F. 用户面文档
|
||||
### D. 用户面文档
|
||||
|
||||
- [ ] `README.md` / `README.zh.md` "Authentication" 段落
|
||||
- [ ] `skills/bailian-cli/reference/` 通过 `pnpm run sync:skill-assets` 重建
|
||||
|
||||
### G. 测试
|
||||
### E. 测试
|
||||
|
||||
- [ ] `packages/cli/tests/e2e/auth.e2e.test.ts` 增加新方式的 happy / failure 路径
|
||||
- [ ] mask token 的输出格式不变(避免泄漏)
|
||||
- [ ] 如调整 resolver 优先级,补 core/runtime 单测覆盖 flag > env > file
|
||||
|
||||
## 完成后自查
|
||||
|
||||
@@ -105,12 +114,21 @@ HOME=/tmp/empty node packages/cli/src/main.ts auth status
|
||||
node packages/cli/src/main.ts auth status --api-key sk-xxx
|
||||
|
||||
# env 注入
|
||||
DASHSCOPE_ACCESS_TOKEN=xxx node packages/cli/src/main.ts auth status
|
||||
DASHSCOPE_API_KEY=sk-xxx node packages/cli/src/main.ts auth status
|
||||
```
|
||||
|
||||
Console 登录/网关相关改动:
|
||||
|
||||
```sh
|
||||
node packages/cli/src/main.ts auth login --console
|
||||
node packages/cli/src/main.ts usage stats --dry-run --output json
|
||||
```
|
||||
|
||||
## 常见漏点
|
||||
|
||||
- ✗ 加了新 token 来源但忘了改 `resolveCredential` 优先级,实际不生效
|
||||
- ✗ `Config` 加字段但 `loadConfig` 没读 → 字段永远 undefined
|
||||
- ✗ `bl auth login` 写成功但 `bl auth status` 不识别(两边走的 storage path 不一致)
|
||||
- ✗ 加了新 token 来源但忘了改 resolver 优先级,实际不生效
|
||||
- ✗ `ConfigFile` / `Settings` 加字段但 `parseConfigFile` 或 `buildSettings` 没读
|
||||
- ✗ `auth login` 写成功但 `auth status` 不识别(两边走的 storage path 不一致)
|
||||
- ✗ token mask 显示完整 token,日志泄漏
|
||||
- ✗ `auth: "console"` 命令误用 `apiKey` 域,config 只有 API key 时会把 `sk-...` 发到网关
|
||||
- ✗ 新增 core resolver hint 时写死产品命令,导致 `rag` 等入口提示错误
|
||||
|
||||
@@ -50,13 +50,13 @@ git diff --name-only <base>...<head>
|
||||
- [ ] **`package.json` 没破坏发布元数据**:`bin` / `exports` / `files` / `inlinedDependencies` 字段任何删除或改名都要单独评估
|
||||
- [ ] **公共依赖没被悄悄升级**:catalog / 根 lockfile 改动要列出来
|
||||
- [ ] **`package.json` version 没倒退**:目标分支已经更高时(如 main 1.0.3 vs head 1.0.0-beta.1),手动对齐版本号,不要被 head 覆盖
|
||||
- [ ] **全局表没冲突**:`registry.ts`、`defineCommand` 的 `skipDefaultApiKeySetup`(见 `packages/core/src/types/command.ts`)、`ExitCode` 三处新增项不和现有项冲突
|
||||
- [ ] **全局表没冲突**:`packages/cli/src/commands.ts` / `packages/rag/src/main.ts` command map、`defineCommand({ auth })`、`GLOBAL_FLAGS` / `MODEL_AUTH_FLAGS` / `CONSOLE_AUTH_FLAGS`、`ExitCode` 新增项不和现有项冲突
|
||||
|
||||
## 清单 B:用户透出(用户可见的新东西必看)
|
||||
|
||||
- [ ] **新命令 / 新 flag** 已同步到用户面文档:
|
||||
- [README.md](README.md) + [README.zh.md](README.zh.md)(中英文都要,常漏 `_CN`)
|
||||
- (SKILL.md 已迁出本仓库,由 `npx add skills` 机制独立维护,不在本仓库 review 范围)
|
||||
- `skills/bailian-cli/reference/` + `skills/bailian-cli/SKILL.md` 通过 `pnpm run sync:skill-assets` 更新并提交
|
||||
- [ ] **`bl <cmd> --help`** 文案完整:`description` / `examples` 都填了
|
||||
- [ ] **demo / quickstart**:用户可调用的新命令至少有一个示例
|
||||
- [ ] **行为变化的老命令**:在 commit message / CHANGELOG 注明用户感知的差异
|
||||
@@ -80,7 +80,7 @@ git diff --name-only <base>...<head>
|
||||
解冲突要点(merge 时不要漏):
|
||||
- <冲突文件> + <字段/段落> + <怎么取舍>
|
||||
↑ 放"合并那一刻才会出现"的细节,例如 package.json 的 files/scripts/devDependencies 各取并集、
|
||||
`skipDefaultApiKeySetup` 这类命令元数据两边都加项时不要丢一侧、pnpm-lock.yaml 直接 rm 后 pnpm install 重生等。
|
||||
command map / `auth` / 全局 flags 这类元数据两边都加项时不要丢一侧、pnpm-lock.yaml 直接 rm 后 pnpm install 重生等。
|
||||
建议修(可后置):
|
||||
- ...
|
||||
仅信息(无需动作,告知即可):
|
||||
@@ -94,11 +94,11 @@ git diff --name-only <base>...<head>
|
||||
|
||||
## 常见漏点(基于历史踩坑)
|
||||
|
||||
| 漏点 | 后果 |
|
||||
| ------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
|
||||
| `pnpm-workspace.yaml` 把 `packages/*` 收窄成显式列表 | 合并后目标分支的新子包不再被 workspace 识别,`pnpm install` 看似正常但子包失联 |
|
||||
| 源分支 version 比目标分支低,直接 merge 覆盖 | npm 上版本号回退,latest tag 错乱 |
|
||||
| `registry.ts` 注册新命令但忘了 [README](README.md) / [README.zh](README.zh.md) | 用户完全感知不到新功能 |
|
||||
| 共享 util 重构(抽公共函数)只改了一处调用方 | 其它调用方静默走旧分支,行为分裂 |
|
||||
| 不该跳过默认 API key 引导的命令误设 `skipDefaultApiKeySetup: true` | 安全风险,用户没配置 key 也能调付费 API |
|
||||
| `catalog.ts` / `skipDefaultApiKeySetup` 这类元数据两边都加项,解冲突时被合掉一侧 | 某个命令突然要求登录 / 某个新命令注册丢失,编译能过、回归不易察觉 |
|
||||
| 漏点 | 后果 |
|
||||
| -------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
|
||||
| `pnpm-workspace.yaml` 把 `packages/*` 收窄成显式列表 | 合并后目标分支的新子包不再被 workspace 识别,`pnpm install` 看似正常但子包失联 |
|
||||
| 源分支 version 比目标分支低,直接 merge 覆盖 | npm 上版本号回退,latest tag 错乱 |
|
||||
| `packages/cli/src/commands.ts` 注册新命令但忘了 [README](README.md) / [README.zh](README.zh.md) | 用户完全感知不到新功能 |
|
||||
| 共享 util 重构(抽公共函数)只改了一处调用方 | 其它调用方静默走旧分支,行为分裂 |
|
||||
| 命令 `auth` 域设错(如 Console Gateway 用了 `apiKey`) | 凭证域 flag/help/credential 注入都错,运行期才暴露 |
|
||||
| `packages/cli/src/commands.ts` / `packages/rag/src/main.ts` 这类 map 两边都加项,解冲突时被合掉一侧 | 某个新命令注册丢失,编译能过、回归不易察觉 |
|
||||
|
||||
@@ -81,11 +81,12 @@ git merge-base --is-ancestor 12f2b1b 3fc54ae && echo "IN" || echo "NOT IN"
|
||||
光看 commit 还不够,要确认目标功能的代码 / 文件在 release commit 上真的存在:
|
||||
|
||||
```sh
|
||||
# 列出 release commit 下某目录的文件
|
||||
git ls-tree -r <releaseCommit> --name-only -- packages/cli/src/commands/
|
||||
# 列出 release commit 下命令实现与产品入口
|
||||
git ls-tree -r <releaseCommit> --name-only -- packages/commands/src/commands/
|
||||
git show <releaseCommit>:packages/cli/src/commands.ts | head
|
||||
|
||||
# 看 release commit 下某文件的内容
|
||||
git show <releaseCommit>:packages/cli/src/commands/console/call.ts | head
|
||||
git show <releaseCommit>:packages/commands/src/commands/console/call.ts | head
|
||||
```
|
||||
|
||||
特别注意被一行带过的"杂项" commit。本仓库历史踩过坑:`feat(cli): enhance output options and add new commands` 这种标题里藏了**新命令** + **新输出格式** + **logout 增强**三件事,粗看会全部漏掉。
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
## 触发条件
|
||||
|
||||
- 新增/修改 `packages/cli/src` 下的 command(`commands/catalog.ts` 登记、`defineCommand` 实现、options/usage)
|
||||
- 新增/修改 `packages/commands/src/commands` 下的 command 实现
|
||||
- 新增/修改 `packages/cli/src/commands.ts` 的 `bl` 命令路径 map
|
||||
- 新建或扩展 `packages/cli/tests/e2e/*.e2e.test.ts` 用例
|
||||
- 为命令补 help / 缺参 / dry-run / 真实集成测试
|
||||
|
||||
@@ -59,8 +60,8 @@ describe.skipIf(<ready>)("e2e: <topic>(DashScope …)", () => {
|
||||
|
||||
## 新增 command 检查清单
|
||||
|
||||
- [ ] `commands/catalog.ts` 登记 + `tests/e2e/<topic>.e2e.test.ts`(新建或扩展)
|
||||
- [ ] 若改了 `usage` / `options` / `examples`,跑 `pnpm --filter bailian-cli run generate:reference` 更新 `skills/bailian-cli/reference/` 并提交
|
||||
- [ ] `packages/commands/src/index.ts` 导出 + `packages/cli/src/commands.ts` 暴露路径 + `tests/e2e/<topic>.e2e.test.ts`(新建或扩展)
|
||||
- [ ] 若改了 `usageArgs` / `flags` / `exampleArgs`,跑 `pnpm --filter bailian-cli run generate:reference` 更新 `skills/bailian-cli/reference/` 并提交
|
||||
- [ ] 顶层:分组 help + 子命令 `--help`(多子命令则各一条 help)
|
||||
- [ ] skip 块:每个 required flag 缺参;可 dry-run 则加一条
|
||||
- [ ] 至少一条真实集成(或说明为何仅 smoke);不破坏已有集成用例顺序
|
||||
|
||||
@@ -5,89 +5,126 @@
|
||||
- 增加新的 `bl xxx` 命令
|
||||
- 删除已有命令
|
||||
- 重命名命令(包括从单级 `bl x` 改成 `bl x y` 或反向)
|
||||
- 调整某个 shared command 在 `bl` / `rag` 等产品入口里的暴露路径
|
||||
|
||||
## 命令路径与文件路径的对应规则
|
||||
## 命令实现与产品路径的关系
|
||||
|
||||
命令实现住在 `packages/commands`,产品路径由入口包决定。实现文件路径按能力组织,但不再等同于最终命令路径。
|
||||
|
||||
```
|
||||
单级命令(无 group): commands/<name>.ts ↔ bl <name>
|
||||
例: commands/update.ts ↔ bl update
|
||||
|
||||
两级命令(有 group): commands/<group>/<action>.ts ↔ bl <group> <action>
|
||||
例: commands/text/chat.ts ↔ bl text chat
|
||||
|
||||
三级命令(子组,慎用): commands/<group>/<sub>/<action>.ts ↔ bl <group> <sub> <action>
|
||||
例: commands/memory/profile/create.ts ↔ bl memory profile create
|
||||
仅当子组下有 ≥2 个 action 时合理(否则拍平到两级)
|
||||
实现文件:
|
||||
packages/commands/src/commands/knowledge/retrieve.ts
|
||||
↓ packages/commands/src/index.ts export { default as knowledgeRetrieve }
|
||||
产品入口:
|
||||
packages/cli/src/commands.ts "knowledge retrieve": knowledgeRetrieve ↔ bl knowledge retrieve
|
||||
packages/rag/src/main.ts "retrieve": knowledgeRetrieve ↔ rag retrieve
|
||||
```
|
||||
|
||||
文件路径与命令路径必须 1:1 对齐。
|
||||
常见路径形态:
|
||||
|
||||
```
|
||||
单级命令: packages/commands/src/commands/update.ts ↔ bl update
|
||||
两级命令: packages/commands/src/commands/text/chat.ts ↔ bl text chat
|
||||
子组命令: packages/commands/src/commands/memory/profile-get.ts ↔ bl memory profile get
|
||||
```
|
||||
|
||||
子组要慎用:只有子组下有 ≥2 个 action 时才合理,否则优先拍平到两级。
|
||||
|
||||
## CLI 命令注册架构(必读)
|
||||
|
||||
命令元数据以 **`catalog.ts` 为单一登记处**;`registry.ts` 只负责解析与打印 help,不再内嵌命令表或手写 Resources 列表。
|
||||
`packages/commands` 是命令库,只导出单个 command;不内置 path presets,不关心 `bl` / `rag`。每个产品入口传入自己的 command map,`runtime` 负责解析、help、鉴权、遥测、执行。
|
||||
|
||||
```
|
||||
commands/<...>.ts defineCommand({ name, description, usage, options, examples, run })
|
||||
packages/commands/src/commands/<...>.ts
|
||||
defineCommand({ auth, flags, usageArgs, exampleArgs, validate, run })
|
||||
↓
|
||||
commands/catalog.ts export const commands: Record<string, Command>
|
||||
packages/commands/src/index.ts
|
||||
export { default as xxxCommand } from "./commands/...ts"
|
||||
↓
|
||||
┌────┴────┬──────────────────────┬─────────────────────┐
|
||||
↓ ↓ ↓ ↓
|
||||
registry.ts main.ts tools/generate-reference.ts export-schema.ts
|
||||
(解析/help) (入口) → skills/bailian-cli/reference/index.md + <group>.md
|
||||
┌──────────────────────────────┬──────────────────────────────┐
|
||||
│ packages/cli/src/commands.ts │ packages/rag/src/main.ts │
|
||||
│ { "text chat": textChat } │ { "retrieve": knowledge... } │
|
||||
└──────────────┬───────────────┴──────────────┬───────────────┘
|
||||
↓ ↓
|
||||
createCli(commands, identity) → runtime registry/help/middleware
|
||||
↓
|
||||
tools/generate-reference.ts reads packages/cli/src/commands.ts
|
||||
```
|
||||
|
||||
- **`packages/cli/src/commands/catalog.ts`**: `import` 命令模块 + `"<path>": handler` 映射;**不** `import registry.ts`(避免构建时循环依赖)
|
||||
- **`packages/cli/src/commands/index.ts`**: `export { commands } from "./catalog.ts"`(给包内 re-export 用)
|
||||
- **`packages/cli/src/registry.ts`**: `import { commands } from "./commands/catalog.ts"`,建树、`resolve`、`printHelp`;Commands / Global Flags 从 `Command` 元数据与 `GLOBAL_OPTIONS` **动态生成**
|
||||
- **`tools/generate-reference.ts`**: pre-commit / `pnpm run sync:skill-assets` 时读 `catalog.ts`,写 `skills/bailian-cli/reference/index.md`(索引) + `skills/bailian-cli/reference/<一级命令>.md`(详情,勿手改)。该目录**纳入 git**,随 `npx skills add modelstudioai/cli` 分发
|
||||
- **`packages/commands/src/commands/<...>.ts`**:命令实现;`usageArgs` / `exampleArgs` 只写参数片段,不写 `bl` / `rag` 前缀
|
||||
- **`packages/commands/src/index.ts`**:导出命令实现;新增命令必须在这里 re-export
|
||||
- **`packages/cli/src/commands.ts`**:`bl` 产品命令 map;新增/删除/重命名 `bl` 命令必须改这里
|
||||
- **`packages/rag/src/main.ts`**:`rag` 产品命令 map;只有该入口需要暴露/变更时才改
|
||||
- **`packages/runtime/src/registry.ts`**:通用 registry,从传入 map 建树;不要在这里登记业务命令
|
||||
- **`tools/generate-reference.ts`**:pre-commit / `pnpm run sync:skill-assets` 时读 `packages/cli/src/commands.ts`,写 `skills/bailian-cli/reference/index.md` + `<一级命令>.md`。该目录**纳入 git**,勿手改
|
||||
|
||||
已删除、勿再引用:`commands/help.ts`、`registry.ts` 内联 `new CommandRegistry({...})`、`printRootHelp` 手写命令行。
|
||||
已删除/勿再引用:旧的 `packages/cli/src/commands/catalog.ts`、旧的 `packages/cli/src/commands/index.ts` catalog re-export、`packages/cli/src/registry.ts`、`skipDefaultApiKeySetup`、`ensureApiKey` 启动拦截、`config/export-schema.ts`。
|
||||
|
||||
## 必查清单
|
||||
|
||||
### A. 代码层
|
||||
### A. 命令库
|
||||
|
||||
- [ ] **新建/删除/移动**对应的 `packages/cli/src/commands/<...>.ts` 文件
|
||||
- [ ] **`packages/cli/src/commands/catalog.ts`**:
|
||||
- 增删 `import xxx from "./.../xxx.ts"`
|
||||
- 在 `export const commands` 里增删 `"<group> <action>": xxx`(key 与 `defineCommand({ name })` 一致)
|
||||
- [ ] **不要**在 `registry.ts` 里重复登记命令(已从 catalog 读取)
|
||||
- [ ] 如果命令需要跳过入口的默认 DashScope API key 引导(`ensureApiKey`),在对应 `defineCommand` 上设 `skipDefaultApiKeySetup: true`(字段定义见 `packages/core/src/types/command.ts`;`main.ts` 根据已解析的 `command` 读取)
|
||||
- [ ] **`config/export-schema.ts`**: 若新命令不适合作为 agent tool,评估是否加入 `SKIP_PREFIXES`;该文件在 `run()` 内 `import("../catalog.ts")`,勿顶层 import catalog 以免循环依赖
|
||||
- [ ] 新建/删除/移动对应的 `packages/commands/src/commands/<...>.ts`
|
||||
- [ ] `defineCommand` 字段使用当前 schema:
|
||||
- `auth: "apiKey" | "console" | "none"`
|
||||
- `flags`(camelCase key,由 runtime 渲染为 kebab-case)
|
||||
- `usageArgs`(不含 bin/path 前缀)
|
||||
- `exampleArgs`(不含 bin/path 前缀)
|
||||
- `validate`(跨 flag 校验)
|
||||
- 普通业务命令的 `run(ctx)` 只读 `ctx.flags` / `ctx.settings` / `ctx.client`
|
||||
- `commands/auth/**` 可用 `ctx.authStore()`,`commands/config/**` 可用 `ctx.configStore()`;不要把这些 store accessor 扩散到普通业务命令
|
||||
- [ ] `packages/commands/src/index.ts`:新增或移除对应 export
|
||||
- [ ] 如果命令调用 Console Gateway,设置 `auth: "console"`;不要重复声明 console 凭证域 flags
|
||||
- [ ] 如果命令不需要网络或自己管理配置/登录,设置 `auth: "none"`;不要绕过 runtime auth stage
|
||||
|
||||
### B. 文档层
|
||||
### B. 产品入口
|
||||
|
||||
- [ ] `packages/cli/src/commands.ts`:按需增删 `import` 与 `commands` map key
|
||||
- [ ] 新 map key 就是 `bl` 下的命令路径;重命名时全仓 grep 旧路径字符串
|
||||
- [ ] 如果 `rag` 入口也要暴露/移除该能力,同步 `packages/rag/src/main.ts`
|
||||
- [ ] 不要在 `packages/runtime/src/registry.ts` 或 `create-cli.ts` 里写业务命令表
|
||||
|
||||
### C. 文档层
|
||||
|
||||
- [ ] 运行 `pnpm run sync:skill-assets`(或正常 `git commit` 走 pre-commit),刷新 `skills/bailian-cli/reference/` 与 `SKILL.md` 的 `metadata.version` 并提交
|
||||
- [ ] `README.md` / `README.zh.md`: Quick Start、命令一览(用户向,与 help 对齐即可)
|
||||
- [ ] `skills/bailian-cli/SKILL.md`: 若安装说明或能力边界有变,同步更新
|
||||
- [ ] `README.md` / `README.zh.md`:Quick Start、命令一览、认证说明(用户向,与 help 对齐)
|
||||
- [ ] `skills/bailian-cli/SKILL.md`:若安装说明或能力边界有变,同步更新
|
||||
|
||||
### C. 测试层
|
||||
### D. 测试层
|
||||
|
||||
- [ ] 按 [cli-e2e-tests.md](cli-e2e-tests.md) 新建或更新 `packages/cli/tests/e2e/<topic>.e2e.test.ts`
|
||||
- [ ] 删除命令时一并删对应 e2e
|
||||
- [ ] 删除命令时一并删对应 e2e / README 示例 / reference 生成结果
|
||||
- [ ] 如果 shared command 在不同入口路径下复用,至少确保 `bl` 入口 e2e 覆盖;`rag` 入口改动需补对应入口测试或手工 smoke
|
||||
|
||||
### D. 重命名特殊处理
|
||||
### E. 重命名特殊处理
|
||||
|
||||
- [ ] 全仓 grep **旧命令名字符串**,确保以下位置全部更新:
|
||||
- `catalog.ts` 的 key
|
||||
- error hints(cli 层)
|
||||
- `packages/cli/src/commands.ts` map key
|
||||
- `packages/rag/src/main.ts` map key(如适用)
|
||||
- 用户可见 hint / README / tests
|
||||
- `skills/bailian-cli/reference/`(重建后检查并提交)
|
||||
- README 示例
|
||||
- 测试断言
|
||||
- [ ] 检查 `usageArgs` / `exampleArgs` 没有硬编码旧的 `bl <path>` 前缀
|
||||
|
||||
## 完成后自查
|
||||
|
||||
```sh
|
||||
pnpm run sync:skill-assets # reference/ + SKILL metadata.version 与 catalog / package.json 一致
|
||||
pnpm run sync:skill-assets
|
||||
node packages/cli/src/main.ts <new-command> --help
|
||||
node packages/cli/src/main.ts # 根 help 列表含新命令
|
||||
vp test packages/cli/tests/e2e/<topic>.e2e.test.ts # 相关 e2e
|
||||
node packages/cli/src/main.ts
|
||||
vp test packages/cli/tests/e2e/<topic>.e2e.test.ts
|
||||
```
|
||||
|
||||
如改了 `rag` 入口:
|
||||
|
||||
```sh
|
||||
node packages/rag/src/main.ts <command> --help
|
||||
```
|
||||
|
||||
## 常见漏点
|
||||
|
||||
- ✗ 只改了命令文件,忘了 **`catalog.ts`** → 命令不存在或 help 里没有
|
||||
- ✗ 手改 **`skills/bailian-cli/reference/*.md`** → 下次 generate 被覆盖;应改 `defineCommand` 后重新 generate 并提交
|
||||
- ✗ 在 `export-schema.ts` 顶层 `import catalog` → 可能与 registry 循环依赖
|
||||
- ✗ 只新增 `packages/commands/src/commands/...` 文件,忘了在 `packages/commands/src/index.ts` 导出
|
||||
- ✗ 只导出了命令实现,忘了在 `packages/cli/src/commands.ts` 暴露路径 → `bl --help` 看不到
|
||||
- ✗ 手改 `skills/bailian-cli/reference/*.md` → 下次 generate 被覆盖;应改 command metadata 后重新 generate 并提交
|
||||
- ✗ 在 `usageArgs` / `exampleArgs` 写死 `bl text chat` → `rag` 等入口复用时 help 错
|
||||
- ✗ Console Gateway 命令忘设 `auth: "console"` → console flags / credential 注入都不生效
|
||||
- ✗ 单 action 的子组是反模式,新增时优先拍平为两级
|
||||
|
||||
@@ -11,20 +11,21 @@
|
||||
|
||||
### A. 命令文件本身
|
||||
|
||||
- [ ] `packages/cli/src/commands/<group>/<action>.ts`:
|
||||
- `defineCommand({ options: [...] })` 数组里增删/改 `{ flag, description, type, required }`
|
||||
- `usage` 字段(如 `"bl text chat --message <text> [flags]"`)反映新签名
|
||||
- `examples` 数组覆盖新 flag 至少一个示例
|
||||
- `run()` 里读取 flag 的代码:
|
||||
- 类型转换正确(`type: "number"` 时 `flags.x as number`,`"array"` 时 `as string[]`)
|
||||
- 必填校验:`if (!flags.x) failIfMissing("x", ...)` 或交互式 prompt
|
||||
- 默认值 fallback
|
||||
- [ ] `packages/commands/src/commands/<group>/<action>.ts`:
|
||||
- `defineCommand({ flags: { ... } })` 里增删/改 camelCase flag key 与 `{ type, valueHint, description, required }`
|
||||
- `usageArgs` 字段只写参数片段(如 `"--message <text> [flags]"`),不写 `bl <path>`
|
||||
- `exampleArgs` 数组覆盖新 flag 至少一个示例,同样不写 bin/path 前缀
|
||||
- `run()` 里只从 `ctx.flags` 读取本命令 flag,从 `ctx.settings` 读取全局/config 解析结果
|
||||
- 类型由 `ParsedFlags<typeof FLAGS>` 推导;避免手写 `flags.x as number` 这类断言
|
||||
- 单 flag 必填用 `required: true`;跨 flag / 值相关校验放 `validate`
|
||||
- 默认值 fallback 写在命令实现或 `Settings` 解析层,不要重复解析 env/config
|
||||
|
||||
### B. 鉴权 / 全局选项
|
||||
|
||||
- [ ] 如果是**全局 flag**(所有命令通用),改 `packages/core/src/types/command.ts` 的 `GLOBAL_OPTIONS`
|
||||
- [ ] 如果新 flag 影响 `Config`,改 `packages/core/src/config/schema.ts` 的 `Config` 接口
|
||||
- [ ] 如果对应 env var,改 `packages/core/src/config/loader.ts` 的 `loadConfig`
|
||||
- [ ] 如果是**全局 flag**(所有命令通用),改 `packages/core/src/types/command.ts` 的 `GLOBAL_FLAGS`
|
||||
- [ ] 如果是凭证域 flag,优先确认是否属于 `MODEL_AUTH_FLAGS` 或 `CONSOLE_AUTH_FLAGS`;不要在单个命令里重复声明
|
||||
- [ ] 如果新 flag 影响有效配置面,改 `packages/core/src/config/schema.ts` 的 `Settings` 接口
|
||||
- [ ] 如果对应 env var 或 config 文件字段,改 `packages/core/src/config/loader.ts` 的 `buildSettings`
|
||||
|
||||
### C. 文档层
|
||||
|
||||
@@ -44,13 +45,13 @@
|
||||
## 完成后自查
|
||||
|
||||
```sh
|
||||
node packages/cli/src/main.ts <command> --help # 看新 flag 出现在 Options
|
||||
node packages/cli/src/main.ts <command> --help # 看新 flag 出现在 Flags
|
||||
node packages/cli/src/main.ts <command> --new-flag x # 实测一遍
|
||||
```
|
||||
|
||||
## 常见漏点
|
||||
|
||||
- ✗ 加 `type: "number"` 但 `String(flags.x)` 触发 lint 警告(参考已修过的 memory/list.ts)
|
||||
- ✗ 加了 array 型 flag 但没考虑用户可能传多次
|
||||
- ✗ 改默认值忘记更新 description 里的 "(default: xxx)" 文案
|
||||
- ✗ Required flag 缺失时直接抛硬错而不是 prompt(交互友好性问题,参考已实现 prompt 的命令文件作为示例)
|
||||
- ✗ 在 `usageArgs` / `exampleArgs` 里写死 `bl <path>`,导致其它产品入口复用时 help 错
|
||||
- ✗ required flag 缺失又在 `run()` 里重复手写校验,与 parser/`validate` 的错误文案不一致
|
||||
|
||||
+15
-15
@@ -11,46 +11,46 @@
|
||||
|
||||
```
|
||||
flag (--xxx) ─┐
|
||||
├─ loadConfig() 合并 ─→ Config(运行时单一对象)
|
||||
├─ buildSources() + buildSettings() ─→ Settings(命令读取面)
|
||||
env (XXX=yyy) ─┤
|
||||
│
|
||||
config 文件 ─┘
|
||||
~/.bailian/config.json
|
||||
```
|
||||
|
||||
优先级一般是 **flag > env > config 文件 > 默认值**,具体见 `core/config/loader.ts`。
|
||||
优先级一般是 **flag > env > config 文件 > 默认值**,具体见 `packages/core/src/config/loader.ts`。
|
||||
|
||||
## 必查清单
|
||||
|
||||
### A. 类型定义
|
||||
|
||||
- [ ] `packages/core/src/config/schema.ts`:
|
||||
- `Config`(运行时形状)加新字段
|
||||
- `Settings`(运行时有效配置面)加新字段
|
||||
- `ConfigFile`(disk 形状,snake_case)加新字段(如果允许写文件)
|
||||
- `parseConfigFile()` 解析新字段
|
||||
- 如果是 enum 字段,加校验
|
||||
|
||||
### B. 加载逻辑
|
||||
|
||||
- [ ] `packages/core/src/config/loader.ts:loadConfig()`:
|
||||
- 加新字段的合并逻辑(`flags.x ?? process.env.XXX ?? file.x ?? default`)
|
||||
- [ ] `packages/core/src/config/loader.ts`:
|
||||
- `buildSources()` 如需新增来源,把 flag/file/env 纳入 sources
|
||||
- `buildSettings()` 加新字段的合并逻辑(`flags.x ?? process.env.XXX ?? file.x ?? default`)
|
||||
- 校验(数值范围、枚举合法性等)
|
||||
- 校验失败抛 `BailianError(USAGE)`
|
||||
|
||||
### C. 全局 flag(如果加的是 flag)
|
||||
|
||||
- [ ] `packages/core/src/types/command.ts:GLOBAL_OPTIONS` 数组
|
||||
- [ ] `registry.ts` 的 `buildGlobalFlagLines` 会**自动**从 `GLOBAL_OPTIONS` 生成 `bl --help` 与 `reference/index.md` 的全局 flag 段,无需手写
|
||||
- [ ] flag 的 type 标注(`boolean` / `number` / `array`),让 args.ts 正确解析
|
||||
- [ ] `packages/core/src/types/command.ts:GLOBAL_FLAGS`
|
||||
- [ ] `packages/runtime/src/registry.ts` 会**自动**从 `GLOBAL_FLAGS` 生成 root help;`tools/generate-reference.ts` 会生成 `reference/index.md` 的全局 flag 段
|
||||
- [ ] flag 的 type 标注(`switch` / `boolean` / `number` / `array` / `string`),让 `packages/runtime/src/args.ts` 正确解析
|
||||
- [ ] 改完全局 flag 后跑 `pnpm --filter bailian-cli run generate:reference`
|
||||
|
||||
### D. 命令使用方
|
||||
|
||||
- [ ] 用到新字段的命令文件直接读 `config.xxx`,不要重复解析
|
||||
- [ ] 用到新字段的命令文件直接读 `ctx.settings.xxx`,不要重复解析 env/config
|
||||
- [ ] 配置展示 / 修改命令同步:
|
||||
- `packages/cli/src/commands/config/show.ts` 显示新字段
|
||||
- `packages/cli/src/commands/config/set.ts` 允许 set
|
||||
- `packages/cli/src/commands/config/export-schema.ts` 在 schema 输出里
|
||||
- `packages/commands/src/commands/config/show.ts` 显示新字段
|
||||
- `packages/commands/src/commands/config/set.ts` 的 `VALID_KEYS` / `KEY_ALIASES` / description 允许 set
|
||||
|
||||
### E. 文档
|
||||
|
||||
@@ -70,15 +70,15 @@ node packages/cli/src/main.ts config show --output json | grep <new-field>
|
||||
XXX=value node packages/cli/src/main.ts config show --output json | grep <new-field>
|
||||
node packages/cli/src/main.ts config show --xxx value --output json | grep <new-field>
|
||||
|
||||
# 写到文件
|
||||
# 写到文件(会改用户 HOME,必要时先用临时 HOME)
|
||||
node packages/cli/src/main.ts config set --key <key> --value <value>
|
||||
cat ~/.bailian/config.json
|
||||
```
|
||||
|
||||
## 常见漏点
|
||||
|
||||
- ✗ `Config` 接口加字段但 `loadConfig` 没填,运行时永远 undefined
|
||||
- ✗ `Settings` 接口加字段但 `buildSettings` 没填,运行时永远 undefined
|
||||
- ✗ `ConfigFile` 用 camelCase 字段名(disk schema 应该是 snake_case)
|
||||
- ✗ 全局 flag 没标 `type: "boolean"`,被当成需要值的 `--xxx <value>`
|
||||
- ✗ 全局 switch 没标 `type: "switch"`,被当成需要值的 `--xxx <value>`
|
||||
- ✗ 加了 env var 但 README 表格没更新,用户不知道有这条
|
||||
- ✗ `config show` 不显示新字段,用户改了无法回查
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
## 触发条件
|
||||
|
||||
- 修改 `BailianError` 的 message 或 hint
|
||||
- 调整 cli 的 hint 增强逻辑(`enhanceHint`)
|
||||
- 改 ensure-key 的 setup 流程文案
|
||||
- 调整 runtime 的 hint 增强逻辑(`enhanceHint`)
|
||||
- 改 auth stage / resolver 的鉴权失败文案
|
||||
- 改任何抛错位置的分类(exitCode)
|
||||
|
||||
> 注意:`mapApiError` **不再做错误分类**(参见下方"边界原则")。如果你想给某种 HTTP 错误码加白名单分类,请先回到本文档读完"边界原则"再说。
|
||||
@@ -17,7 +17,7 @@
|
||||
| ---------------------------------------------------- | -------- | ----------------------------------------------------------- |
|
||||
| 命令解析、缺 flag、参数校验 | **内部** | `BailianError(USAGE)` |
|
||||
| 文件 I/O(ENOENT/EACCES/...) | **内部** | `BailianError(GENERAL)` + errno-specific hint |
|
||||
| 本地 credentials 缺失(resolver/ensure-key/AK-SK 等) | **内部** | `BailianError(AUTH)` |
|
||||
| 本地 credentials 缺失(resolver / authStage 等) | **内部** | `BailianError(AUTH)` |
|
||||
| `fetch` 自身失败(DNS/TCP/TLS/proxy) | **内部** | `BailianError(NETWORK)` + 读 `err.cause.code` 给 errno-hint |
|
||||
| polling 客户端超时 | **内部** | `BailianError(TIMEOUT)` |
|
||||
| HTTP 4xx/5xx、HTTP 200 + 业务错码、async task FAILED | **服务** | `BailianError(GENERAL)`,**message 原样透传**,不分类、不替换 |
|
||||
@@ -39,9 +39,9 @@
|
||||
```
|
||||
core 抛出 BailianError(message, exitCode, hint, cause?)
|
||||
↓ 沿调用栈冒泡
|
||||
cli/main.ts: main().catch(handleError)
|
||||
runtime/create-cli.ts: dispatch().catch(handleError)
|
||||
↓
|
||||
cli/error-handler.ts:
|
||||
runtime/error-handler.ts:
|
||||
- 服务端错误(BailianError(GENERAL)) → text 直接打 message
|
||||
- 内部 AUTH/USAGE/NETWORK/TIMEOUT → 走 enhanceHint(只 AUTH 还有增强)
|
||||
- TypeError("fetch failed") → 读 err.cause.code 翻成 NETWORK
|
||||
@@ -62,36 +62,42 @@ process.exit(err.exitCode)
|
||||
|
||||
- ❌ 不要回退到"401 → AUTH、429 → QUOTA"那套白名单
|
||||
- ✅ message 把 status / apiCode / request_id 拼进去就够,exit 统一 GENERAL
|
||||
- 例外:CLI **自己**因为本地状态产生的 BailianError(resolver、ensure-key 等)可以用语义化 exitCode
|
||||
- 例外:CLI/runtime **自己**因为本地状态产生的 BailianError(resolver、authStage 等)可以用语义化 exitCode
|
||||
|
||||
### 3. core 的 hint 必须不含 cli 关切
|
||||
|
||||
- ❌ 不写 `bl xxx` 命令名
|
||||
- ❌ 不写控制台 URL 或 region
|
||||
- ❌ 不写渠道追踪参数(`source_channel=xxx`)
|
||||
- ❌ 新增/改动时不写 `bl xxx` 命令名
|
||||
- ❌ 新增/改动时不写 `rag xxx` 等产品入口命令名
|
||||
- ❌ 新增/改动时不写控制台 URL 或 region
|
||||
- ❌ 新增/改动时不写渠道追踪参数(`source_channel=xxx`)
|
||||
- ✅ 只描述抽象做法(如 `"Set DASHSCOPE_API_KEY environment variable, or pass --api-key."`)
|
||||
- 当前遗留:`packages/core/src/auth/resolver.ts` 仍含 `bl auth login` hint;触碰鉴权错误时迁到 runtime `enhanceHint`
|
||||
|
||||
### 4. cli 端可以自由使用 cli 命令名 + URL
|
||||
### 4. runtime / 产品层可以使用入口名 + URL
|
||||
|
||||
- 命令文件、`error-handler.ts`、`utils/ensure-key.ts` 是 cli 层,内部可以写 `bl xxx`
|
||||
- URL 必须从 `packages/cli/src/urls.ts` import,不能硬编码
|
||||
- `packages/runtime/src/error-handler.ts` 通过 `binName` 渲染 `bl` / `rag` 等入口名,不要硬编码
|
||||
- 产品入口 / README / E2E 可以写具体入口命令
|
||||
- shared command 实现不写 `bl` / `rag` 前缀;`usageArgs` / `exampleArgs` 只写参数片段
|
||||
- URL 必须从 `packages/runtime/src/urls.ts` import,不能硬编码
|
||||
|
||||
## 必查清单
|
||||
|
||||
### A. core 改动(message / hint)
|
||||
|
||||
- [ ] `packages/core/src/errors/api.ts` 的 `mapApiError`:**保持透传形态**,不要加白名单分支
|
||||
- [ ] `packages/core/src/auth/resolver.ts` 改 throw 语句:hint 不含 cli 关切
|
||||
- [ ] 任何 core 文件 throw 的 BailianError:同上
|
||||
- [ ] `packages/core/src/auth/resolver.ts` 新增/改 throw 语句时:hint 不含 cli 关切;已有 `bl auth login` 遗留点被触碰时要收敛
|
||||
- [ ] 任何 core 文件新增/改 BailianError:同上
|
||||
|
||||
### B. cli 增强(`enhanceHint`)
|
||||
### B. runtime 增强(`enhanceHint`)
|
||||
|
||||
- [ ] `packages/cli/src/error-handler.ts:enhanceHint`:**当前只为 internal AUTH 增强**(因为只有 resolver/ensure-key 等内部位置会发 AUTH)
|
||||
- [ ] `packages/runtime/src/error-handler.ts:enhanceHint`:**当前只为 internal AUTH 增强**(因为 resolver / authStage 等内部位置会发 AUTH)
|
||||
- [ ] 命令名使用 `binName`,不要硬编码 `bl`
|
||||
- [ ] URL 必须是 `import { API_KEY_PAGE } from "./urls.ts"`
|
||||
|
||||
### C. cli 直接抛错(`ensure-key`、命令文件)
|
||||
### C. command / runtime 直接抛错
|
||||
|
||||
- [ ] cli 层抛 BailianError 时,hint 里可以放 cli 命令名,但 **URL 一律走 `urls.ts` import**
|
||||
- [ ] runtime 层抛 BailianError 时,hint 里可以放 `binName` 渲染的入口命令,但 **URL 一律走 `urls.ts` import**
|
||||
- [ ] `packages/commands` 作为 shared command 库,默认不硬编码产品 bin;如果确需用户操作提示,优先依赖 runtime error handler 或 `ctx.identity.binName`
|
||||
- [ ] 抛错位置如果**已经在调用服务端**,catch 时不要替换 message——重新评估是否需要 catch
|
||||
|
||||
### D. 文案一致性
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
- [ ] `package.json` 的 `engines.node` 与 README 的 Node.js 徽章一致
|
||||
- [ ] `pnpm-lock.yaml` 同步生成(运行 `pnpm install`)
|
||||
- [ ] 三处 `tsconfig.json`(根 + cli + core)的 target / module 设置一致
|
||||
- [ ] 各源码包 `tsconfig.json`(根 + core + runtime + commands + cli + rag)的 target / module 设置一致
|
||||
|
||||
### B. lint / format 规则改动
|
||||
|
||||
@@ -26,13 +26,15 @@
|
||||
|
||||
### C. 构建配置
|
||||
|
||||
- [ ] `packages/cli/vite.config.ts` 和 `packages/core/vite.config.ts` 的 entry / external / dts 设置
|
||||
- [ ] cli 的 bundle 必须把 `bailian-cli-core` 当 **external**(不内联),确认 `dist/bailian.mjs` 第一行有 `from "bailian-cli-core"`
|
||||
- [ ] cli 的 bundle 第一行必须有 `#!/usr/bin/env node` shebang(`tools/release.mjs check` 会断言)
|
||||
- [ ] `packages/*/vite.config.ts` 的 entry / dts / exports 设置符合包类型:
|
||||
- library 包(core/runtime/commands):导出 `dist/index.mjs` + dts + `@bailian-cli/source` dev export
|
||||
- binary 包(cli/rag):entry 指向 `src/main.ts`,有 shebang,`exports: true`
|
||||
- [ ] cli / rag 的 bundle 必须把 workspace 包(`bailian-cli-core` / `bailian-cli-runtime` / `bailian-cli-commands`)当 **external**(不内联),确认 dist 中仍是 package import
|
||||
- [ ] cli / rag 的 binary bundle 第一行必须有 `#!/usr/bin/env node` shebang
|
||||
|
||||
### D. 依赖升级
|
||||
|
||||
- [ ] 检查 `bailian-cli-core` 在 cli 的 `dependencies` 里仍是 `"workspace:*"`(不要变成实际版本号 — `tools/release.mjs` 会拦)
|
||||
- [ ] 检查 workspace 内部依赖在 `dependencies` 里仍是 `"workspace:*"`(不要手改成实际版本号;发布时由 pack/publish 流程解析)
|
||||
- [ ] 升级后跑 `vp check && vp test`
|
||||
- [ ] 升级 `@types/node` 时注意 Node API 变化(如 fs.existsSync 行为)
|
||||
|
||||
@@ -44,7 +46,7 @@
|
||||
|
||||
### F. CI / 发版工具
|
||||
|
||||
- [ ] `tools/release.mjs` 中如有版本/规则相关的硬编码,同步更新
|
||||
- [ ] `tools/release/` 中如有版本/规则相关的硬编码,同步更新
|
||||
- [ ] 比如 `secretPatterns` 添加新的敏感值识别
|
||||
|
||||
## 完成后自查
|
||||
@@ -54,13 +56,13 @@
|
||||
pnpm install --frozen-lockfile
|
||||
vp check
|
||||
vp test
|
||||
node tools/release.mjs check
|
||||
node tools/release/check.mjs
|
||||
```
|
||||
|
||||
## 常见漏点
|
||||
|
||||
- ✗ 升级 Node engines 但忘了 README 徽章
|
||||
- ✗ 改 lint 规则后没全仓 `--fix`,新人 PR 报红一片
|
||||
- ✗ 改 cli 的 vite config 把 core 不小心打成 inline,bundle 体积暴涨
|
||||
- ✗ 改 cli/rag 的 vite config 把 core/runtime/commands 不小心打成 inline,bundle 体积暴涨
|
||||
- ✗ Oxlint 配置改了但 IDE 缓存还是旧的(IDE 可能要重启 ts server)
|
||||
- ✗ 升级依赖一并升 lockfile,改动量大但没拆 commit
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
### Do
|
||||
|
||||
- 写清晰的 **must / must-not / 必查**,不写"建议"性语气
|
||||
- 用 file path + 具体 action 的句式(`packages/cli/src/commands/catalog.ts:增加 import 与 commands 条目`)
|
||||
- 用 file path + 具体 action 的句式(`packages/cli/src/commands.ts:增加产品命令 map 条目`)
|
||||
- 在每份场景末尾留**常见漏点**段,持续累积真实经验
|
||||
- 在跨场景的不变量上互相引用,不复制
|
||||
|
||||
|
||||
@@ -12,12 +12,13 @@
|
||||
|
||||
### A. 命令实现
|
||||
|
||||
- [ ] `packages/cli/src/commands/<group>/<action>.ts`:
|
||||
- [ ] `packages/commands/src/commands/<group>/<action>.ts`:
|
||||
- `--model` flag 的 description 里"default:"反映新默认值
|
||||
- 命令内部 `const model = (flags.model as string) || "<default>"` 的 fallback 字符串
|
||||
- 命令内部 `const model = flags.model || settings.defaultXxxModel || "<default>"` 的 fallback 字符串
|
||||
- 如果命令维护一个 supported-models 列表(如 `speech/synthesize.ts:MODEL_VOICES`),增删条目
|
||||
- 如果不同模型有不同 endpoint / 请求体形状,确保 `if (model.startsWith("xxx"))` 分支覆盖
|
||||
- [ ] 模型如有特殊 endpoint,看 `packages/core/src/client/endpoints.ts`
|
||||
- [ ] 如果新增的是某产品入口专属能力,确认 `packages/cli/src/commands.ts` 或其它入口 map 是否需要暴露/隐藏
|
||||
|
||||
### B. 类型层
|
||||
|
||||
|
||||
+27
-23
@@ -26,7 +26,7 @@
|
||||
|
||||
### stable 发布
|
||||
|
||||
1. 确保 `packages/cli/package.json` 和 `packages/core/package.json` 已升到目标版本且一致
|
||||
1. 确保当前 release tooling 覆盖的包(`tools/release/lib/packages.mjs`,现为 `packages/core` / `packages/cli`)已升到目标版本且一致;同时人工检查源码包版本(`runtime` / `commands` / `rag`)是否需要跟随
|
||||
2. 在 GitHub 触发 Publish workflow,mode 选 `stable`
|
||||
3. 需要 production environment 审批人批准
|
||||
4. CI 自动:自检 → 构建 → 发布到 latest → 打 git tag
|
||||
@@ -36,16 +36,16 @@
|
||||
|
||||
两种模式都会先跑 `check.mjs`,覆盖以下检查:
|
||||
|
||||
| 检查项 | 说明 |
|
||||
| -------------------------------- | ----------------------------------------- |
|
||||
| `pnpm install --frozen-lockfile` | lockfile 一致性 |
|
||||
| README 同步 | `packages/cli/README.md` 与根 README 一致 |
|
||||
| 版本号一致 | cli 与 core 的 version 字段相同 |
|
||||
| `workspace:*` 替换 | cli 对 core 的依赖解析为真实版本号 |
|
||||
| 构建 core + cli | `pnpm build` |
|
||||
| pnpm pack | 打 tarball |
|
||||
| publint | 包元数据校验 |
|
||||
| gitleaks | 敏感信息扫描 |
|
||||
| 检查项 | 说明 |
|
||||
| -------------------------------- | ----------------------------------------------------------------------------- |
|
||||
| `pnpm install --frozen-lockfile` | lockfile 一致性 |
|
||||
| README 同步 | `packages/cli/README.md` 与根 README 一致 |
|
||||
| 版本号一致 | `tools/release/lib/packages.mjs` 中列出的包 version 相同(当前为 core + cli) |
|
||||
| `workspace:*` 替换 | 发布包间 workspace 依赖解析为真实版本号 |
|
||||
| 构建 | 当前 check 会构建 core + cli |
|
||||
| pnpm pack | 打 tarball |
|
||||
| publint | 包元数据校验 |
|
||||
| gitleaks | 敏感信息扫描 |
|
||||
|
||||
本地可以 dry-run 验证:
|
||||
|
||||
@@ -58,13 +58,15 @@ node tools/release/publish-channel.mjs --channel test --dry-run
|
||||
- **认证**:npm OIDC Trusted Publishing(无 token),需要 `id-token: write` 权限
|
||||
- **Node 版本**:24(npm 11.5+ 才支持 OIDC token 交换)
|
||||
- **Actions 版本**:checkout/setup-node/pnpm-action 均为 v6(Node 24 兼容)
|
||||
- **npm 配置**:两个包的 Trusted Publisher 都指向 `modelstudioai/cli` 的 `publish.yml`,environment 留空
|
||||
- **npm 配置**:当前 release tooling 发布的包(core + cli)的 Trusted Publisher 指向 `modelstudioai/cli` 的 `publish.yml`,environment 留空;新增发布包时同步 npm Trusted Publisher
|
||||
|
||||
## `check.mjs` 不覆盖的(手动确认)
|
||||
|
||||
### 版本号目标(仅 stable)
|
||||
|
||||
- [ ] `packages/cli/package.json` 和 `packages/core/package.json` 已升到目标版本
|
||||
- [ ] `tools/release/lib/packages.mjs` 覆盖的包已升到目标版本且一致
|
||||
- [ ] 源码包 `packages/runtime/package.json`、`packages/commands/package.json`、`packages/rag/package.json` 是否需要同步升版已人工确认;当前仓库通常保持五包版本一致
|
||||
- [ ] `tools/release/lib/packages.mjs` 的 `PACKAGES` 覆盖所有本次实际要发布的包;如果新增发布包,同步 `publish-stable.mjs` / `publish-channel.mjs` 的 bump、publish、idempotency 逻辑
|
||||
- [ ] pre-release 格式正确(`1.0.0-beta.0` / `1.0.0-rc.1`,**不要直接用 `1.0.0` 当 beta**)
|
||||
|
||||
### CHANGELOG(仅 stable)
|
||||
@@ -78,7 +80,7 @@ node tools/release/publish-channel.mjs --channel test --dry-run
|
||||
- [ ] `README.md` / `README.zh.md` 的 Quick Start 命令仍能跑通
|
||||
- [ ] README 的 Node.js 徽章版本与 `cli/package.json.engines.node` 一致
|
||||
- [ ] README 宣传的 bin 名称在 `cli/package.json.bin` 都真的注册
|
||||
- [ ] `LICENSE` 文件存在(根 + cli + core 各一份)
|
||||
- [ ] `LICENSE` 文件存在(根 + 当前实际发布包;新增发布包时补该包 LICENSE)
|
||||
|
||||
## 完成后
|
||||
|
||||
@@ -87,12 +89,14 @@ node tools/release/publish-channel.mjs --channel test --dry-run
|
||||
|
||||
## 常见漏点(基于历史踩坑)
|
||||
|
||||
| 漏点 | 后果 |
|
||||
| -------------------------------------------------------- | -------------------------------------------------- |
|
||||
| cli 升版号但 core 没升 | check.mjs 会拦下 |
|
||||
| 发版漏更 CHANGELOG,或分类写成规范外的 `优化`/`Improved` | 用户看不到本次变更,分类与历史不一致 |
|
||||
| `1.0.0` 当 beta 直接发 | 占了 `latest` tag,所有用户被强升,撤回成本极高 |
|
||||
| README 写的 bin 名实际 `package.json.bin` 没注册 | 用户复制命令报 `command not found` |
|
||||
| Node 徽章 `>=18`、engines `>=22.12` 不一致 | 用户在 Node 18 上 `npm i` 被 engine 警告或直接失败 |
|
||||
| npm Trusted Publisher 的 workflow filename 改了没同步 | OIDC 匹配不上,publish 报 404 |
|
||||
| CI 用 Node 22(npm 10)跑 publish | npm 10 不支持 OIDC token 交换,publish 报 404 |
|
||||
| 漏点 | 后果 |
|
||||
| -------------------------------------------------------- | --------------------------------------------------------- |
|
||||
| 只升 cli/core,漏升 runtime/commands/rag | 当前 check.mjs 不一定拦下,但 workspace 发布会出现版本漂移 |
|
||||
| 新增发布包但没加 `tools/release/lib/packages.mjs` | CI 不会 bump/publish/校验该包 |
|
||||
| cli 升版号但 core 没升 | check.mjs 会拦下 |
|
||||
| 发版漏更 CHANGELOG,或分类写成规范外的 `优化`/`Improved` | 用户看不到本次变更,分类与历史不一致 |
|
||||
| `1.0.0` 当 beta 直接发 | 占了 `latest` tag,所有用户被强升,撤回成本极高 |
|
||||
| README 写的 bin 名实际 `package.json.bin` 没注册 | 用户复制命令报 `command not found` |
|
||||
| Node 徽章 `>=18`、engines `>=22.12` 不一致 | 用户在 Node 18 上 `npm i` 被 engine 警告或直接失败 |
|
||||
| npm Trusted Publisher 的 workflow filename 改了没同步 | OIDC 匹配不上,publish 报 404 |
|
||||
| CI 用 Node 22(npm 10)跑 publish | npm 10 不支持 OIDC token 交换,publish 报 404 |
|
||||
|
||||
@@ -15,7 +15,7 @@ core/config/schema.ts ← API endpoint / 文档站(region-awar
|
||||
DOCS_HOSTS{cn, us, intl} help.aliyun.com/zh/model-studio
|
||||
BAILIAN_HOST bailian.cn-beijing.aliyuncs.com (POP API)
|
||||
|
||||
cli/src/urls.ts ← 用户面控制台 URL(cn-only)
|
||||
runtime/src/urls.ts ← 用户面控制台 URL(cn-only)
|
||||
BAILIAN_CONSOLE_ROOT bailian.console.aliyun.com
|
||||
BAILIAN_CONSOLE BAILIAN_CONSOLE_ROOT/cn-beijing
|
||||
API_KEY_PAGE BAILIAN_CONSOLE/?tab=app#/api-key
|
||||
@@ -29,14 +29,16 @@ core/files/upload.ts ← 文件上传 endpoint(cn-pinned)
|
||||
### A. TS 源码(必须 import,不准硬编码)
|
||||
|
||||
- [ ] `packages/core/src/config/schema.ts` 是所有 API/docs 基址的源头
|
||||
- [ ] `packages/cli/src/urls.ts` 是所有用户面控制台 URL 的源头
|
||||
- [ ] `packages/runtime/src/urls.ts` 是所有用户面控制台 URL 的源头
|
||||
- [ ] 改完后 grep 验证:
|
||||
|
||||
```sh
|
||||
# 控制台 URL — 应只在 urls.ts 出现
|
||||
grep -rnE "https://bailian\.console\.aliyun\.com" packages/ --include="*.ts" \
|
||||
| grep -v "node_modules" | grep -v "/dist/"
|
||||
# 期望:只匹配 packages/cli/src/urls.ts
|
||||
# 期望:匹配 packages/runtime/src/urls.ts;
|
||||
# 当前遗留例外:packages/commands/src/commands/auth/login-console.ts(登录站点映射)、
|
||||
# packages/core/src/advisor/recommend.ts(模型文档 deep link)。触碰时优先收敛到统一 URL 模块。
|
||||
|
||||
# API endpoint — 应只在 schema.ts 和 upload.ts 出现
|
||||
grep -rnE "https://dashscope[a-z-]*\.aliyuncs\.com" packages/ --include="*.ts" \
|
||||
@@ -51,9 +53,9 @@ grep -rnE "https://dashscope[a-z-]*\.aliyuncs\.com" packages/ --include="*.ts" \
|
||||
|
||||
### C. 渠道追踪参数
|
||||
|
||||
- [ ] **当前现状**:全仓不带 `source_channel=aliway` 等追踪参数
|
||||
- [ ] 如未来要恢复以收集分析数据,**统一评估再加回**(不要单点恢复造成不一致)
|
||||
- [ ] 全仓 grep `source_channel=`,确认无残留
|
||||
- [ ] **当前现状**:TS 源码不带 `source_channel=...`;README / package README 中保留 `cli_github` / `key_github` 等用户入口追踪参数
|
||||
- [ ] 如未来调整追踪参数,统一评估 README、`packages/cli/README*`、`packages/core/README*` 与 package homepage,不要单点改造成不一致
|
||||
- [ ] grep `source_channel=`,确认每个残留都属于预期用户面文档或已批准的追踪入口
|
||||
|
||||
## 完成后自查
|
||||
|
||||
@@ -69,6 +71,6 @@ node packages/cli/src/main.ts help # help 命令
|
||||
|
||||
## 常见漏点
|
||||
|
||||
- ✗ 改了 `urls.ts` 但忘记同步 README(用户最先看到)
|
||||
- ✗ 在 cli 命令文件里 inline `https://bailian.console.aliyun.com/...` 而不是 `${API_KEY_PAGE}`
|
||||
- ✗ 改了 `urls.ts` / 登录站点 / 文档 deep link 但忘记同步 README(用户最先看到)
|
||||
- ✗ 在 runtime / command 文件里 inline `https://bailian.console.aliyun.com/...` 而不是从 `urls.ts` import
|
||||
- ✗ 在 core 的 hint 里写 URL(违反 [error-hint-change.md](error-hint-change.md) 不变量 1)
|
||||
|
||||
@@ -24,22 +24,24 @@ Index: [index.md](index.md)
|
||||
|
||||
#### Flags
|
||||
|
||||
| Flag | Type | Required | Description |
|
||||
| -------------------------- | ------- | -------- | ----------------------------------------------------------------------- |
|
||||
| `--image <url>` | array | yes | Source image URL or local file path (repeatable for multi-image merge) |
|
||||
| `--prompt <text>` | string | yes | Edit instruction text |
|
||||
| `--model <model>` | string | no | Model ID (default: qwen-image-2.0) |
|
||||
| `--size <W*H>` | string | no | Output image size: ratio (3:4, 16:9) or pixels (2048\*2048) |
|
||||
| `--n <count>` | number | no | Number of images (default: 1, max: 6) |
|
||||
| `--seed <n>` | number | no | Random seed for reproducible results |
|
||||
| `--negative-prompt <text>` | string | no | Negative prompt to exclude unwanted content |
|
||||
| `--prompt-extend <bool>` | boolean | no | Enable prompt extend (true/false). Omit flag to use CLI default (true). |
|
||||
| `--watermark <bool>` | boolean | no | Enable watermark (true/false). Omit flag to use CLI default (true). |
|
||||
| `--out-dir <dir>` | string | no | Download images to directory |
|
||||
| `--out-prefix <prefix>` | string | no | Filename prefix (default: edited) |
|
||||
| `--concurrent <n>` | number | no | Run N parallel requests (default: 1) |
|
||||
| `--api-key <key>` | string | no | API key |
|
||||
| `--base-url <url>` | string | no | API base URL |
|
||||
| Flag | Type | Required | Description |
|
||||
| --------------------------- | ------- | -------- | ----------------------------------------------------------------------- |
|
||||
| `--image <url>` | array | yes | Source image URL or local file path (repeatable for multi-image merge) |
|
||||
| `--prompt <text>` | string | yes | Edit instruction text |
|
||||
| `--model <model>` | string | no | Model ID (default: qwen-image-2.0) |
|
||||
| `--size <W*H>` | string | no | Output image size: ratio (3:4, 16:9) or pixels (2048\*2048) |
|
||||
| `--n <count>` | number | no | Number of images (default: 1, max: 6) |
|
||||
| `--seed <n>` | number | no | Random seed for reproducible results |
|
||||
| `--negative-prompt <text>` | string | no | Negative prompt to exclude unwanted content |
|
||||
| `--prompt-extend <bool>` | boolean | no | Enable prompt extend (true/false). Omit flag to use CLI default (true). |
|
||||
| `--watermark <bool>` | boolean | no | Enable watermark (true/false). Omit flag to use CLI default (true). |
|
||||
| `--out-dir <dir>` | string | no | Download images to directory |
|
||||
| `--out-prefix <prefix>` | string | no | Filename prefix (default: edited) |
|
||||
| `--async` | switch | no | Return async task id without waiting |
|
||||
| `--concurrent <n>` | number | no | Run N parallel requests (default: 1) |
|
||||
| `--poll-interval <seconds>` | number | no | Polling interval when waiting (default: 3) |
|
||||
| `--api-key <key>` | string | no | API key |
|
||||
| `--base-url <url>` | string | no | API base URL |
|
||||
|
||||
#### Examples
|
||||
|
||||
@@ -83,7 +85,6 @@ bl image edit --image ./photo.png --prompt "Replace the background with a beach"
|
||||
| `--negative-prompt <text>` | string | no | Negative prompt to exclude unwanted content |
|
||||
| `--prompt-extend <bool>` | boolean | no | Enable prompt extend (true/false). Omit flag: true for qwen-image sync; parameter omitted on async models (API default). |
|
||||
| `--watermark <bool>` | boolean | no | Enable watermark (true/false). Omit flag to use CLI default (true). |
|
||||
| `--no-wait` | switch | no | Return task ID immediately without waiting (async models only) |
|
||||
| `--async` | switch | no | Return async task id without waiting |
|
||||
| `--concurrent <n>` | number | no | Run N parallel requests (default: 1) |
|
||||
| `--out-dir <dir>` | string | no | Download images to directory |
|
||||
@@ -119,7 +120,7 @@ bl image generate --prompt "An alien in the space" --watermark false
|
||||
```
|
||||
|
||||
```bash
|
||||
bl image generate --prompt "sunset" --model wan2.6-t2i --no-wait --quiet
|
||||
bl image generate --prompt "sunset" --model wan2.6-t2i --async --quiet
|
||||
```
|
||||
|
||||
```bash
|
||||
|
||||
@@ -34,7 +34,6 @@ Index: [index.md](index.md)
|
||||
| `--vocabulary-id <id>` | string | no | Hot-word vocabulary ID for improved accuracy |
|
||||
| `--channel-id <n>` | number | no | Audio channel ID (default: 0) |
|
||||
| `--out <path>` | string | no | Save full transcription result to JSON file |
|
||||
| `--no-wait` | switch | no | Return task ID immediately without polling |
|
||||
| `--async` | switch | no | Return async task id without waiting |
|
||||
| `--poll-interval <seconds>` | number | no | Polling interval in seconds (default: 2) |
|
||||
| `--api-key <key>` | string | no | API key |
|
||||
@@ -67,7 +66,7 @@ bl speech recognize --url https://example.com/audio.mp3 --out result.json
|
||||
```
|
||||
|
||||
```bash
|
||||
bl speech recognize --url https://example.com/audio.mp3 --no-wait --quiet
|
||||
bl speech recognize --url https://example.com/audio.mp3 --async --quiet
|
||||
```
|
||||
|
||||
### `bl speech synthesize`
|
||||
|
||||
@@ -69,8 +69,8 @@ bl video download --task-id 3b256896-xxxx --out video.mp4 --quiet
|
||||
| `--watermark <bool>` | boolean | no | Enable watermark (true/false). Omit flag to use CLI default (true). |
|
||||
| `--seed <n>` | number | no | Random seed for reproducible generation |
|
||||
| `--download <path>` | string | no | Save video to file on completion |
|
||||
| `--no-wait` | switch | no | Return task ID immediately without waiting |
|
||||
| `--async` | switch | no | Return async task id without waiting |
|
||||
| `--concurrent <n>` | number | no | Run N parallel requests (default: 1) |
|
||||
| `--poll-interval <seconds>` | number | no | Polling interval when waiting (default: 15) |
|
||||
| `--api-key <key>` | string | no | API key |
|
||||
| `--base-url <url>` | string | no | API base URL |
|
||||
@@ -116,7 +116,6 @@ bl video edit --video https://example.com/input.mp4 --prompt "Put clothes on the
|
||||
| `--watermark <bool>` | boolean | no | Enable watermark (true/false). Omit flag to use CLI default (true). |
|
||||
| `--seed <n>` | number | no | Random seed for reproducible generation |
|
||||
| `--download <path>` | string | no | Save video to file on completion |
|
||||
| `--no-wait` | switch | no | Return task ID immediately without waiting |
|
||||
| `--async` | switch | no | Return async task id without waiting |
|
||||
| `--concurrent <n>` | number | no | Run N parallel requests (default: 1) |
|
||||
| `--poll-interval <seconds>` | number | no | Polling interval when waiting (default: 5) |
|
||||
@@ -170,8 +169,8 @@ bl video generate --prompt "A cat playing with a ball" --watermark false
|
||||
| `--watermark <bool>` | boolean | no | Enable watermark (true/false). Omit flag to use CLI default (true). |
|
||||
| `--seed <n>` | number | no | Random seed for reproducible generation |
|
||||
| `--download <path>` | string | no | Save video to file on completion |
|
||||
| `--no-wait` | switch | no | Return task ID immediately without waiting |
|
||||
| `--async` | switch | no | Return async task id without waiting |
|
||||
| `--concurrent <n>` | number | no | Run N parallel requests (default: 1) |
|
||||
| `--poll-interval <seconds>` | number | no | Polling interval when waiting (default: 15) |
|
||||
| `--api-key <key>` | string | no | API key |
|
||||
| `--base-url <url>` | string | no | API base URL |
|
||||
|
||||
Reference in New Issue
Block a user