# CHANGELOG 与 Changesets 指南

# 1. 概述

# 1.1. 核心原则

  • CHANGELOG 只记录用户可见的变更,不记录内部开发过程中的临时修改、重构中间态、待办事项
  • 对比基准是 main 分支的上一个发布版本,不是最近的 git commit 或功能开发分支
  • 统一使用 changeset 模式:所有包通过 changeset 文件驱动版本管理
  • 发布时统一格式:最终 CHANGELOG 格式完全一致——先中文后英文的双语结构
  • 日常维护仅写中文,发布时再添加英文——减少日常维护负担

# 1.2. 包模式

所有包统一使用 changeset 模式,包括 cmtx-vscode。不再区分双轨。

# 2. 格式标准

# 2.1. 文件结构

每个包目录下有 CHANGELOG.md 文件。发布后统一采用先中文后英文的双语结构。发布前按第 4 章流程精修为统一格式。

# 2.2. 双语规范

  • 文件标题使用双语:# @cmtx/<name> 更新日志 / Changelog
  • 每个版本均采用先中文后英文的双语模式,用 --- 分隔
  • 中文与英文条目内容应一一对应,信息一致
  • 初始发布版本可省略 ---,但双语必须完整

# 2.3. 标题规范

位置 格式 说明
文件第一行 # @cmtx/<name> 更新日志 / Changelog 双语命名
日常维护 无固定标题,由 changeset 驱动 创建 CHANGESET-XXX 文件,发布时 changeset version 自动生成
发布后 ## [<version>] - <YYYY-MM-DD> 由脚本自动替换

# 2.4. 变更类型

类型 说明 使用时机
Added 新功能 新增面向用户的特性、API、CLI 命令
Changed 现有功能变更 API 行为变化、内部重构但不影响签名
Deprecated 即将弃用的功能 标记即将移除的功能,并说明替代方案
Removed 已移除的功能 实际删除已弃用的功能
Fixed 错误修复 修复任何用户可见的 bug
Security 安全漏洞 安全修复(可附带 CVE 编号)

# 2.5. 条目编写规范

通用 Markdown 格式规则见 DEV-010 文档布局,本节仅定义 CHANGELOG 专有的条目规范。

  • 每个条目以 - 开头,末尾不加句号
  • 英文条目首字母大写,中文条目直接写不加引号
  • 如果条目标题不足以说明,另起一行缩进补充细节:
### Added
- **ConfigAdapter**: 新增 `getMaxRetries()` 方法
    返回最大重试次数,默认值为 3,可通过构造函数注入
  • 条目面向 CHANGELOG 读者(包的使用者),描述"做了什么"和"为什么做",而不是"怎么实现"
  • 如果某个变更需要更详细的迁移指南,在 CHANGELOG 中写简要说明,另开文档详述

# 2.6. 禁止写入 CHANGELOG 的内容

  • WIP(Work in Progress)的部分实现
  • 仅测试代码变更(新增/修改测试用例)
  • 仅文档代码变更(修改 JSDoc、README)
  • 仅配置变更(修改 CI、打包配置、lint 规则)
  • 内部重构但无 API/行为变化
  • 依赖版本更新但无行为变化

# 3. 日常维护流程

Changesets 是一个版本管理工具,用于解决 Monorepo 中的版本发布问题。它的核心思想是将「变更意图」与「代码提交」同步记录,而非在发布时回忆。一个 changeset 是一个 Markdown 文件(含 YAML front matter),声明哪些包需要发布、bump 类型以及变更描述。

# 3.1. changeset 模式

不维护 CHANGELOG.md 中的 [Unreleased],通过 changeset 文件驱动。完成一个用户可见功能或修复后,立即创建 changeset 文件:

NEXT_NUM=$(python3 .agents/skills/changeset-workflow/scripts/next-changeset-number.py .changeset)

格式参考 changeset-workflow skill。

禁止直接编辑 CHANGELOG.md——由 changeset version 自动生成 CHANGELOG 条目。

# 3.2. 确定受影响的包

根据变更影响的包来决定:

  • 修改了 packages/core/src/filter.ts -> 影响 @cmtx/core
  • 修改了 packages/rule-engine/src/index.ts -> 影响 @cmtx/rule-engine
  • 修改了跨包的类型定义 -> 影响所有受影响包

# 3.3. 比较基准

日常维护只需要关注本次 CHANGELOG 撰写期间的变更范围,即自上一次该包 CHANGELOG 更新以来发生的变化,而非从上一个发布版本开始的全量 diff。

# 4. 发布流程

# 4.1. Changeset 与 CHANGELOG 的关系

维度 CHANGELOG Changeset
维护者 changeset version 生成 + 开发者精修 开发者手动
内容 详细的功能描述(中英文双语) 简短的版本变更说明(中文)
用途 面向用户阅读 驱动 changeset version bump
发布时 release-changelog.mjs 添加日期,开发者精修标题和双语 消费后删除

# 4.2. 发布后格式统一

最终发布的 CHANGELOG 格式完全一致:先中文后英文的双语结构,使用标准 Keep a Changelog 分类标题。

精修的目标是让 CHANGELOG.md 达到此统一格式。精修过程中只修改 CHANGELOG.md,不修改 changeset 文件

禁止删除版本号。 即使 changeset version 生成的该版本条目内容没什么用,也要根据 commit 提炼一些内容出来,确保每个版本号都对应有内容的版本。删除版本号会导致 CHANGELOG 与 package.json 的 version 脱节。

# 4.3. changeset 模式精修步骤

pnpm changeset version 执行后,CHANGELOG.md 中新增了自动生成的半成品内容,精修在 CHANGELOG.md 上进行(不修改 changeset 文件):

  • 删除 ### Patch Changes含依赖更新的块(- Updated dependencies [sha]),这不是用户可见变更
  • ### Minor Changes / ### Patch Changes 重命名为 Keep a Changelog 标准类型(### Added / ### Changed / ### Fixed 等),根据实际变更内容判断归属,不留映射规则
  • 移除条目中的 commit SHA 前缀(a539714: 部分)
  • 展开条目内容,将一行简写拆分为多行完整描述

# 4.4. 共同精修步骤

所有包都需要执行以下三步:

# 4.4.1. 步骤 1:验证标题格式与日期

确认版本标题格式为 ## [<version>] - YYYY-MM-DD,与上一个版本的基准对齐。

# 4.4.2. 步骤 2:对比 git diff 审核内容

根据上一次实际发布的版本,对比 git diff 审核当前 CHANGELOG 内容:

# 查找包的上一个发布 tag
LAST_TAG=$(git tag --list '@cmtx/core/*' --sort=-v:refname | head -1)

# 查看自上一个版本以来的 src 变更
git diff "$LAST_TAG"...HEAD -- packages/core/src/ packages/core/package.json | head -100

审核点:

  • 发现 diff 中有变更但 CHANGELOG 没有记录 -> 补齐遗漏
  • 发现 CHANGELOG 记录了但 diff 中找不到证据 -> 删除虚构条目(可能是中间 commit 走了弯路,实际上不存在的变更)
  • 确认所有用户可见的变更都已覆盖

# 4.4.3. 步骤 3:添加英文翻译

每个中文章节完成后,用 --- 分隔,添加对应的英文版本。英文与中文条目一一对应。

# 4.5. 完整示例:精修前后对比

# 4.5.1. Before:changeset version 自动生成

# @cmtx/core 更新日志 / Changelog

## [0.4.0] - 2026-05-06

### Minor Changes

- a539714: frontmatter-id FF1 配置解耦与校验增强

  - `ff1` 新增可选 `length`/`radix` 字段,可独立覆盖 counter 格式配置
  - `ff1.useCounter` 引用的 counter ID 不存在时返回可读错误,而非静默降级

- 862fc95: - ID 生成器重构:支持多 counter 模板化 ID 生成,移除废弃的 id-generate-rule
  - Counter 服务重构:新增 `peek()`/`commit()` 模式,支持多 counter 状态管理
  - 新增 `frontmatter-slug` 规则,支持 transform/extract/ai 三种 slug 生成策略
  - 集成 `@cmtx/ai` 包,支持 AI 驱动的 slug 生成
  - 新增 `transfer-images` 规则,支持跨存储图片转移
  - Service registry 注册 `TransferService``FrontmatterSlugRule`
  - `formatForPublish` 更新适配新的 template 化 ID 生成
  - 配置类型扩展:新增 counter 配置、FF1 配置、slug 配置、transfer 配置
  - frontmatter-id 模板化:`ff1` 新增可选 `length`/`radix` 字段,`useCounter` 引用无效 ID 时报错而非静默降级
  - counter 格式配置从顶层移至规则级别,简化配置结构

### Patch Changes

- Updated dependencies [862fc95]
- Updated dependencies [862fc95]
- Updated dependencies [862fc95]
- Updated dependencies [862fc95]
- Updated dependencies [862fc95]
  - @cmtx/asset@0.2.0-alpha.3
  - @cmtx/autocorrect-wasm@0.1.1-alpha.2
  - @cmtx/core@0.4.0-alpha.3
  - @cmtx/fpe-wasm@0.1.1-alpha.3
  - @cmtx/storage@0.1.1-alpha.3
  - @cmtx/template@0.2.0-alpha.3

# 4.5.2. After:精修后(双语 + 标准分类,两条 changeset 合并)

# @cmtx/core 更新日志 / Changelog

## [0.4.0] - 2026-05-06

### Added

- **FF1 配置解耦**: frontmatter-id FF1 配置解耦与校验增强
  - `ff1` 新增可选 `length`/`radix` 字段,可独立覆盖 counter 格式配置
  - `ff1.useCounter` 引用的 counter ID 不存在时返回可读错误,而非静默降级
- **ID 生成器重构**: 支持多 counter 模板化 ID 生成,移除废弃的 id-generate-rule
- **Counter 服务重构**: 新增 `peek()`/`commit()` 模式,支持多 counter 状态管理
- **frontmatter-slug 规则**: 新增 transform/extract/ai 三种 slug 生成策略
- **transfer-images 规则**: 新增跨存储图片转移能力
- **配置类型扩展**: 新增 counter、FF1、slug、transfer 等配置类型

---

### Added

- **FF1 Config Decoupling**: Decoupled FF1 config with enhanced validation
  - Added optional `length`/`radix` fields to `ff1` for independent counter format config
  - `ff1.useCounter` now returns a readable error for invalid counter IDs
- **ID Generator Refactor**: Multi-counter template-based ID generation, removed deprecated id-generate-rule
- **Counter Service Refactor**: New `peek()`/`commit()` pattern for multi-counter state management
- **frontmatter-slug Rule**: Three slug strategies: transform, extract, and AI
- **transfer-images Rule**: Cross-storage image transfer support
- **Config Type Extensions**: Added counter, FF1, slug, and transfer configs

(依赖更新块已删除,commit SHA 已移除,### Minor Changes 改为 ### Added,条目按功能拆分合并。)

# 4.6. 补充示例

多个 changeset 合并(同一包)

三个 changeset 文件:

CHANGESET-021-url-check.md:
---
"@cmtx/asset": minor
---
- URL 存在性检测

CHANGESET-022-head-fallback.md:
---
"@cmtx/asset": patch
---
- HEAD 降级策略

CHANGESET-023-batch-check.md:
---
"@cmtx/asset": minor
---
- 批量 URL 检测

changeset version 自动合并后,开发者精修为:

## [0.3.0] - 2026-05-06

### Added

- **URL 存在性检测**: 新增 `checkUrlExists()` 函数
- **批量 URL 检测**: 新增 `checkUrlExistsBatch()` 函数

### Fixed

- **HEAD 降级策略**: HEAD 请求返回 405/501 时自动降级为 GET + Range

---

### Added

- **URL Existence Check**: Added `checkUrlExists()` function
- **Batch URL Checking**: Added `checkUrlExistsBatch()` function

### Fixed

- **HEAD Fallback Strategy**: Auto-fallback to GET + Range on 405/501
破坏性变更
## [0.3.0] - 2026-05-06

### Breaking Changes

- **`uploadImage()` 签名变更**: 第二个参数从 `options` 改为 `config`
    迁移方法: 将 `{ timeout, retry }` 改为 `{ strategy, maxRetries }`

---

### Breaking Changes

- **`uploadImage()` signature changed**: Second parameter changed from `options` to `config`
    Migration: Replace `{ timeout, retry }` with `{ strategy, maxRetries }`

# 4.7. 发布前验证:对比 git diff

这是发布前最重要的验证步骤。 必须验证 CHANGELOG 内容与实际代码变更一致。

# 1. 查找包的上一个发布 tag
LAST_TAG=$(git tag --list '@cmtx/core/*' --sort=-v:refname | head -1)

# 2. 查看自上一个版本以来的 src 变更
git diff "$LAST_TAG"...HEAD -- packages/core/src/ packages/core/package.json | head -100

# 3. 查看具体新增/删除的函数和导出
git diff "$LAST_TAG"...HEAD -- packages/core/src/index.ts

验证清单:

  • [ ] CHANGELOG(或 changeset)中的所有条目都能在 git diff 中找到对应证据
  • [ ] 没有"虚构条目"(diff 中不存在的变更)
  • [ ] 没有遗漏用户可见的变更(新增/删除的导出函数、API 签名变化、破坏性变更)
  • [ ] 移除的公开 API/类型必须在 ### Removed 中记录
  • [ ] 内部重构(仅修改实现、不修改导出签名)不写入 CHANGELOG
  • [ ] 仅修改测试文件、JSDoc、lint 配置、CI 配置等不写入 CHANGELOG

# 4.8. 完整发布命令链

# 版本计算(自动触发 CHANGELOG 版本标题添加日期)
pnpm changeset version

# 精修 CHANGELOG(删除依赖更新块 + 重命名分类标题 + 移除 commit SHA + 展开条目)
# 审核内容完整性(对比 git diff,补齐遗漏、删除虚构条目)
# 添加英文翻译

# 验证构建
pnpm prepublish:validate

# 提交 & 发布
git add -A
git commit -m "Release v<version>"
pnpm changeset publish
git push --follow-tags

# 5. CMTX Changesets 配置

# 5.1. 当前 config.json

{
    "$schema": "https://unpkg.com/@changesets/config@3.1.4/schema.json",
    "changelog": "@changesets/cli/changelog",
    "commit": false,
    "fixed": [],
    "linked": [],
    "access": "public",
    "baseBranch": "main",
    "updateInternalDependencies": "patch",
    "ignore": []
}
  • changelog: "@changesets/cli/changelog" — 启用 changelog 生成,changeset version 自动生成 CHANGELOG 条目
  • access: "public" — scoped 包公开发布
  • ignore — 所有包均参与版本管理,包括 cmtx-vscode

# 5.2. 发布脚本

{
    "postchangeset:version": "node scripts/release-changelog.mjs",
    "release:version": "pnpm changeset version",
    "release:publish": "pnpm changeset publish && git push --follow-tags",
    "release:all": "pnpm changeset version && pnpm prepublish:validate && pnpm changeset publish && git push --follow-tags"
}

单步操作直接使用 pnpm changeset <command> 命令,不再通过包装脚本间接调用。

# 5.3. 参与版本管理的包

所有包均参与版本管理:

  • @cmtx/ai
  • @cmtx/asset
  • @cmtx/core
  • @cmtx/fpe-wasm
  • @cmtx/markdown-it-presigned-url
  • @cmtx/markdown-it-presigned-url-adapter-nodejs
  • @cmtx/rule-engine
  • @cmtx/storage
  • @cmtx/template
  • @cmtx/autocorrect-wasm(新包,尚未发布)
  • cmtx-vscode

# 6. 命令速查

# 6.1. Git 查询命令

# 查找包的上一个版本标签
git tag --list '@cmtx/core/*' --sort=-v:refname | head -1

# 查看自上一个版本以来的变化(按包筛选)
git diff <last-tag>...HEAD -- packages/core/

# 查看所有提交(按包筛选)
git log <last-tag>...HEAD -- packages/core/

# 查看变更的文件列表
git diff <last-tag>...HEAD --name-only -- packages/core/

# 6.2. npm scripts 参考

脚本 命令 触发时机 说明
postchangeset:version node scripts/release-changelog.mjs 自动 给版本标题添加日期
release:version pnpm changeset version 发布 版本计算 + CHANGELOG 生成
release:publish pnpm changeset publish && git push --follow-tags 发布 发布到 npm 并推送 tag
release:all pnpm changeset version && pnpm prepublish:validate && pnpm changeset publish && git push --follow-tags 发布 完整发布流程
prepublish:validate validate:build + validate:tests + validate:typecheck 发布前 发布前验证三件套

# 6.3. 常用操作速查

# 日常:创建 changeset(手动,推荐)
# 直接在 .changeset/ 下创建 CHANGESET-XXX-<描述>.md 文件

# 查看待发布状态
pnpm changeset status --verbose

# 发布:版本计算 + CHANGELOG 版本标题添加日期
pnpm changeset version

# 发布:验证
pnpm prepublish:validate

# 发布:提交
git add -A && git commit -m "Release v<version>"

# 发布:推送到 npm
pnpm changeset publish && git push --follow-tags

# 调试:单独运行 changelog 替换
node scripts/release-changelog.mjs

# 预览发布效果(dry-run)
pnpm changeset version --dry-run
pnpm changeset publish --dry-run

# 7. 参考文档

最后更新: 2026-07-31 19:58:33 +0800 在 GitHub 上编辑此页