2bbfa453d3
leo 2026-08-08 真機看到 v0.18.24 的更新畫面:
「不要這麼長的散文,簡短講改了什麼,細節去 docs 讀。」
畫面是一整面文字牆,`**粗體**` 還原樣露出來。
真兇不是文案,是**最後一哩沒有機制**:
- 單一真相源(changelog.md)08-06 就立好了(30f726b),
changelog-section.sh 也有 --check 閘擋「忘了寫更新內容」。
- 但它的**投影**那一段是 `tr '\n' ' '`——把整段散文壓成一坨,
而且 grep 全 repo **沒有任何東西呼叫它**(build-*.sh 只用 --check)。
- ⇒ 每次出貨都是有人臨時寫一段 python 折行塞進 manifest,
每次重寫一次、沒人檢查結果長什麼樣。
為什麼只能是一行短句(不是排版沒做好):
main.js:215 是 `<div class="d">${esc(u.notes)}</div>`
① esc() ⇒ 任何 markdown 符號都會原樣露出
② .d 沒有 white-space:pre ⇒ 塞 \n 也不會分行
改法:
- 新增 installer/scripts/daemon-notes.mjs =**唯一的投影器**:
只取 changelog 每條的粗體標題、串成一行、超長截斷並導去說明文件。
- changelog-section.sh 的投影段改成委派給它(--check 閘原樣保留),
兩邊同一份規則不會漂移。
- ship.mjs 新增 notes 步驟:每次出貨自動套用,手改過的會被改回來。
- release.mjs 的 verifyManifest 加第四條規則:notes 必須存在、無 markdown、
單行、不超長,且**等於 changelog 的機械投影**——手改一律擋下。
實測:
· v0.18.24/23/22 三版各自產出 62/51/80 字,零手工調整
· 手改成一段散文 → verify-manifest exit 1,兩條規則都抓到
· 再跑一次管線 → 自己改回正確那一行
· 用 daemon 真實 style.css + main.js 的真實 markup 渲染兩版對照並截圖:
舊 576 字(含 8 個原樣露出的 **)vs 新 62 字三行讀完
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
75 lines
3.8 KiB
Bash
Executable File
75 lines
3.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# changelog-section.sh — 抽出某一版的「更新內容」,並在缺漏時擋下打包(2026-08-06)
|
||
#
|
||
# 🔴 leo 08-06:「更新內容還要寫在 docs 裡,機械化要怎麼做」
|
||
#
|
||
# 答:改的是「**寫在哪**」,不是「誰來寫」。
|
||
# 文字一定得人寫(機器編不出「語意搜尋什麼都搜不到」這種人話),
|
||
# 但**只准寫一個地方**= docs-site/src/content/docs/help/changelog.md(用戶語言那份)。
|
||
# 其餘全是投影、不准手改(=頂層 principles「投影不可手改,要改去改源頭」):
|
||
# · manifest.daemon.notes ← 打包時由本腳本抽出
|
||
# · docs-site 的「版本說明」頁 ← 本來就是它自己
|
||
# · portal/rag.arcrun.dev/App 的「版本與更新」 ← 讀同一份 manifest
|
||
#
|
||
# **關鍵是這道閘**:打包時若 changelog 找不到這一版的段落 ⇒ 直接中止、不准打包。
|
||
# ⇒ 「忘了寫更新內容」變成**不可能**,而不是靠誰記得。
|
||
# (病根:manifest.daemon.notes 過去是手寫的,於是可以跟產物完全脫節。)
|
||
#
|
||
# 用法:
|
||
# ./changelog-section.sh v0.18.7 # 印出該版段落(純文字,供 manifest.notes 用)
|
||
# ./changelog-section.sh v0.18.7 --check # 只檢查存不存在
|
||
set -euo pipefail
|
||
cd "$(dirname "$0")"
|
||
REPO_ROOT="$(git rev-parse --show-toplevel)"
|
||
FILE="$REPO_ROOT/docs-site/src/content/docs/help/changelog.md"
|
||
|
||
VERSION="${1:?用法:changelog-section.sh <版本,例 v0.18.7> [--check]}"
|
||
CHECK_ONLY="${2:-}"
|
||
|
||
[ -f "$FILE" ] || { echo "❌ 找不到 changelog:$FILE" >&2; exit 1; }
|
||
|
||
# 段落格式:「## v0.18.7(2026-08-06)」——標題行以 `## <版本>(` 開頭。
|
||
SECTION="$(awk -v ver="## ${VERSION}(" '
|
||
index($0, ver) == 1 { inside = 1; next }
|
||
inside && /^## / { exit }
|
||
inside { print }
|
||
' "$FILE")"
|
||
|
||
if [ -z "$(printf '%s' "$SECTION" | tr -d '[:space:]')" ]; then
|
||
cat >&2 <<MSG
|
||
❌ changelog 裡沒有 ${VERSION} 的段落,不准打包。
|
||
|
||
請在 docs-site/src/content/docs/help/changelog.md 最上面加一段:
|
||
|
||
## ${VERSION}($(date '+%Y-%m-%d'))
|
||
|
||
**建議更新**——(一句話說明「這版對你意味什麼」)
|
||
|
||
- 🔴 **(用戶看得懂的白話標題)**:(發生什麼、現在怎樣)
|
||
|
||
⚠️ 寫給用戶看,不是寫給工程師看:說「以前會怎樣、現在會怎樣」,
|
||
不要寫函式名或 commit 編號。
|
||
MSG
|
||
exit 1
|
||
fi
|
||
|
||
[ "$CHECK_ONLY" = "--check" ] && { echo " ✅ changelog 有 ${VERSION} 的段落"; exit 0; }
|
||
|
||
# 給 manifest.daemon.notes 用的投影——**只有一個投影器**:installer/scripts/daemon-notes.mjs
|
||
#
|
||
# 🔴 2026-08-08 修(leo 真機看到 v0.18.24 的更新畫面):
|
||
# leo 原話「**不要這麼長的散文,簡短講改了什麼,細節去 docs 讀。**」
|
||
#
|
||
# 本檔原本這一段是 `tr '\n' ' '`——**把整段散文壓成一大坨**。而畫面那個欄位是純文字
|
||
# (`main.js:215` 是 `esc(u.notes)`,且 `.d` 沒有 white-space:pre)
|
||
# ⇒ 既不分行、markdown 符號還會原樣露出來 ⇒ 使用者看到一整面文字牆。
|
||
#
|
||
# 更根本的問題:**grep 全 repo,沒有任何東西呼叫這段投影**(build-*.sh 只用 --check)。
|
||
# ⇒ 出貨當下都是有人臨時寫一段 python 折行塞進 manifest,每次重寫一次、沒人檢查結果。
|
||
# ⇒ 這正是「機制存在但沒被接上=等於不存在」的又一例。
|
||
#
|
||
# 現在改成委派給那唯一的投影器(只取每條的粗體標題、串成一行、超長就截並導去 docs),
|
||
# 而 `installer/scripts/ship.mjs` 的 notes 步驟會在每次出貨時自動套用它。
|
||
# ⇒ 兩邊同一份規則,不會漂移。上面的 --check 閘原樣保留(build-*.sh 仍靠它)。
|
||
exec node "$REPO_ROOT/installer/scripts/daemon-notes.mjs" "$VERSION"
|