--- name: changelog-writing description: 写或修改 CHANGELOG.md(待发布条目、版本亮点段、GitHub Release 说明)时使用。含按改动性质分组落位、中英双语体例、发版前的两道门禁(三处版本号同步 + 亮点段抽取会 fail-fast)与写后自检命令。 --- # CHANGELOG 写作(dsh-config-manager) 这份 changelog 是**发布说明的唯一来源**:打 tag 时 CI 直接抽取当前版本段当 GitHub Release 描述。 所以它既要给人读,也要能被机器切段 —— 写错位置、写错版本号、漏写当前版本段,都会在发版那一刻变成红灯或一条错误的发布公告。 本 Skill 只规定**落位、体例与自检**;具体改哪些功能、有没有发布权限由当前任务决定。 ## 何时使用 / 何时跳过 用: - 用户可见的变化(新功能 / 行为变更 / 修复 / 移除 / 安全)准备写进 CHANGELOG 时。 - 发版前补「当前版本亮点段」时。 跳过: - 只改注释、重构、内部测试且**用户可感知行为没变**(这类不写条目;没把握就问一句)。 - 纯文档改动(除非它改变了用户的操作方式)。 ## 1. 落位:写进哪一段 - 文件 = 仓库根 `CHANGELOG.md`,格式遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/)。 - **未发布的内容一律写进 `## [Unreleased]`**,按**改动性质**分组,顺序固定: | 分组 | 放什么 | |---|---| | `### 🆕 新增 · Added` | 新功能、新来源、新通道、新入口 | | `### 🔧 变更 · Changed` | 行为/口径改变、原本静默的变可见、性能与体验变化 | | `### 🐛 修复 · Fixed` | 修 bug、修误报、补护栏 | | `### 🗑️ 移除 · Removed` | 删功能(**有内容才写这个标题**) | | `### 🔐 安全 · Security` | 安全修复(**有内容才写这个标题**) | - **没有内容的分组不写标题**;分组内的条目之间空一行;分组之间空一行。 - 已发布的历史版本段**保留当时写法,不回改**(那 40 多个版本段是发布记录,整批重排只会产生巨大无意义 diff)。用户明确要求时才动。 - 分组标题下的子条目如果本来有自己的小节标题,用 `####`(比分组低一级)。 ## 2. 体例:一条条目怎么写 - **中英双语**,两种写法都算合规(同一条目内): - 段落式:中文块(`> **中文标题**…`)在前,英文块(`> **English title**…`)紧随,中间空行 —— Unreleased 段常用; - 行内式:一条 bullet 里先中文、后英文加粗点 —— 已发布段常用。 - 标题用**加粗块**,不用 `###` 顶掉分组:`> **中文标题**:一句话说清症状/变化`。 - 每条尽量带:**症状 → 根因 → 改法 → 护栏(哪个测试/脚本钉住)→ issue 编号**(`(issue #75)`)。 - emoji 可选:分组标题必须带(见上表);条目内可用(`🔌` `🧩` `🐛` `🔐` 等本仓已有用法)。 ### 口径纪律(本仓最看重的一条) - **不得夸大**:没做的写没做 ——「只报不修」「真机未逐家验证」「本轮收益为零」「未验证(unavailable 不算验证成功)」都要如实写。 - **不把计划写成已完成**:还没合并/还没验证的东西不进 changelog。 - **不承诺未发布的版本号**:发版前不写「将在 v0.1.x 修复」。 - **数字要带口径**:写清是哪个快照、哪台机器、什么时间(例:`(2026-10-06 真机快照:units 1195)`)。 - **证据要可复现**:点名测试文件 / 复核脚本 / 命令。 ## 3. 发版时才做(不是现在) 两道门禁,漏一条 CI 直接 fail: 1. **三处版本号同步**:`package.json.version` ≡ `src/index.ts` 的 `PLUGIN_VERSION` ≡ `package-lock.json` 的根对象与 `packages[""].version`。 守卫 = `tests/packaging-contract.test.ts` 的 `V-1`(源码级正则,任一处漏改即 `npm test` 红灯)。 2. **在文件顶部加当前版本段**:`## [X.Y.Z] - YYYY-MM-DD`,正文是本版本的中英双语亮点。 CI 用 `.github/scripts/extract-release-notes.py` 从 `## [X.Y.Z]` 切到**下一条 `## `**(`###` 子分组原样进发布说明);**抽不到或为空 → fail fast 拒绝发版**。 **不发布的时候**:不要 bump 版本号、也不要写 `## [X.Y.Z]` 段 —— 内容留在 `## [Unreleased]`(版本号 = 最近已发布的版本)。 ## 4. 写后自检(必须做) ```bash # ① 结构与分组(Unreleased 段应当只有「有内容」的分组标题) grep -nE '^### |^#### ' CHANGELOG.md | head -20 # bash Select-String -Path CHANGELOG.md -Pattern '^### |^#### ' # PowerShell # ② 中英配平:中文块与英文块数量应当一致(段落式体例) grep -c '^> \*\*' CHANGELOG.md # ③ 发版前:本地跑一次抽取,确认当前版本段非空(这一步就是 CI 的门禁) python3 .github/scripts/extract-release-notes.py "$(node -p 'require("./package.json").version')" CHANGELOG.md | head -20 ``` 自检不通过就别宣布完成:宁可让用户看见「还差一段」,也不要让 CI 在打 tag 时才发现。 ## 5. 常见错误 | 错误 | 后果 | 正确做法 | |---|---|---| | 新条目直接写 `## [X.Y.Z]` 段 | 版本号没 bump 就对不上;发版时又得搬一次 | 未发布一律写 `## [Unreleased]` 的对应分组 | | 修复写进「新增」、变更写进「修复」 | 发布说明误导读者 | 按第 1 节的分组表落位 | | 空分组也留标题 | 发布说明里全是空壳 | 没内容就不写那个标题 | | 只写中文或只写英文 | 本仓 changelog 是双语的 | 中英成对写 | | 把「计划做」写成「已做」 | 失信;读者按它决策 | 只写已合并、已验证的变化 | | 顺手回改历史版本段 | 巨大无意义 diff,且改动已发布的记录 | 只动 `## [Unreleased]`(用户明确要求除外) | | 改了分组约定但只改代码 | 约定漂移 | 三处一起改:`CHANGELOG.md` 头部「条目落位」、本 Skill、必要时 `DEVELOPERS.md` §自动发布 |