2026-08-22

維護記錄 完成的工作 刪除 layouts/partials/footer.html(1 行 wrapper) 刪除 layouts/partials/custom_footer.html(156 行,PaperMod footer 的本地 fork) 刪除 hugo.toml 中 [params.cloudflareAnalytics] 配置塊 Hugo --minify 構建通過,確認 Cloudflare Web Analytics 注入消失(cf-beacon 匹配 0 次),PaperMod 自帶 footer 功能保留(top-link / scroll-to-top JS / 版權 / Powered by) 決策 移除 Cloudflare 站點統計:custom_footer.html 相對於 PaperMod 原版 footer 唯一真正的差異就是 Cloudflare beacon 注入;既然沒用價值,把 footer 部分整體還原回 PaperMod 默認,避免 PaperMod 升級 footer 時本地 fork 不同步的問題(2026-08-01 已記錄此風險) 保留 layouts/_partials/cover.html:該 override 解決了 PaperMod resources.ByType "image" 不識別 SVG 封面導致 404 的問題,不能刪 下次建議 如果以後又想加自定義站點統計,可以直接在 Hugo 配置啟用內置埋點,或 inline 在 layouts/partials/extend_footer.html(PaperMod 已留 hook),不需要再 fork 整個 footer 維護記錄 完成的工作 修正 CLAUDE.md 中 prettier 安裝命令的事實錯誤:實際是 deno install -g -A npm:prettier@3.9.6 落到 ~/.deno/bin/,不需要 setup-node 修正 scripts/format-markdown.ts 頂部 docstring 的過時描述 給 check-dead-links.yml / test-scripts.yml / validate-posts.yml 三個 push-trigger workflow 加上 if: github.actor != 'github-actions[bot]' 守衛,跟 deploy.yml / sync-covers.yml / update-papermod.yml 一致;節省 bot 推送後再次觸發 CI 的時間 刪除 assets/images/covers/covers/ 死目錄(220 個 SVG,5.4MB):該批封面是 2026-07-21 第一次批量生成時落在 assets/images/covers/ 的;後來 gen-covers.ts 的 COVERS_DIR 改成 static/images/covers/,但舊的沒清;grep 確認沒有任何 .ts / .md / .yml / .toml 引用該路徑 下次建議 第三方 action 仍用浮動 tag(@v4/@v3/@v2);可考慮釘 SHA 防供應鏈投毒 format-markdown.ts(27 行)/ optimize-images.ts(182 行) 仍無單測 維護記錄 完成的工作 刪除全部 31 篇文章中的 categories: 字段(都是 inline categories: ["X"] 格式)— 決定只用 tag 做分類 hugo.toml 的 [taxonomies] 中刪掉 category = "categories" 行;現在只剩 tag = "tags" 和 series = "series"(series 也無人使用,可後續考慮一併刪除) Hugo --minify 構建通過(221 篇,466 ms) 決策 分類統一用 tag:之前 categories 和 tags 語義重疊(categories 僅 3 種且只覆蓋 31 篇;tag 是文章主要分類手段);統一後所有文章都通過 tag 分組,/tags/ 頁面真正反映全部分類 下次建議 series = "series" 在 [taxonomies] 中也是死配置(無人用 series:),可順手刪 維護記錄 完成的工作 把 14 篇文章中的 軟路由 tag 改為 硬件(語義上 軟路由 是軟件配置路由器,硬件 是更廣義的物理設備類目;後續硬件折騰文也歸這裡) 下次建議 tag 表仍偏多(8 個),繼續精簡可考慮:把 日誌(97 篇,大雜燴)拆成 雜記 + 併入 開發/思考;刪除 學習(已基本退役,2021 起再沒用過);刪除 雜談(3 篇,可併入 雜記/思考) 維護記錄 完成的工作 把 50 篇文章的 開發 tag 改為 學習(包括 2 篇原本就有 學習 的:Stack by Rust / Tree by Rust,dedup 後剩 1 個 學習) 順手修了 20200406-Rails-ENV-u0k.md 的 tag: 單數 typo(之前是死配置,Hugo 不會識別),改為 tags: ["學習"] Hugo --minify 通過(370 ms,221 篇) 決策 學習 現在承擔"技術學習/開發"語義(吸收了原 開發),覆蓋 58 篇;原 學習 主要貼在 2020 年早期學習筆記上,語義自然延伸 下次建議 當前 tag:日誌 97 / 學習 58 / 思考 40 / 硬件 14 / 安全 6 / 雜談 3 / 書評 1 仍有 日誌(大雜燴)和 雜談(3 篇,邊緣)可以繼續精簡 維護記錄 完成的工作 給全部 221 篇文章補全 description: 字段(原來只有 9 篇有內容、30 篇是空 "",其餘完全缺失) 日誌類 94 篇:直接寫日期(2020年04月06日 風格),機械處理 非日誌類 117 篇:4 個 subagent 並行讀取正文,生成 80-150 字中文摘要(已驗證 PaperMod 把 description 渲染到 meta[name=description]、og:description、twitter:description 三處) 2 篇 draft 但空正文(20200407-Linux-Process-0ca / 20250115-AHK的快捷鍵腳本方案-0ca)用標題生成了佔位描述 Hugo --minify 通過(288 ms,221 篇全部有 description) 決策 全部 description 用中文雙引號包裹(description: "..."),保持博客中文環境一致 插入位置統一在 date: 行之後;空 description: "" 直接在原位替換 摘要規則:不重複標題信息、客觀中性、長度可控 下次建議 部分早期文章(2020-2021)的標題比較模糊(如 Log 14、2020-9-19),AI 生成的 description 可能不太有意義,但仍優於完全缺失 沒有動 hugo.toml 中 [params] 的 description = ""(全站 fallback);如果想統一,可以改為 blog 簡介 維護記錄 完成的工作 啟用 Hugo 多語言:在 hugo.toml 加 [languages] 塊,簡體 zh(默認,URL 不帶前綴)+ 繁體 zh-tw(URL 帶 /zh-tw/);defaultContentLanguageInSubdir = false 讓默認語言留在根路徑 用 pip install opencc-python-reimplemented 裝到 .tools/pip/(sandbox 不讓裝到 HOME),用 OpenCC('s2tw') 把所有內容轉繁中臺灣標準 轉換 222 個 content/posts/*.md → *.zh-tw.md;16 個 content/claudelog/*.md → *.zh-tw.md;另外 about.md / archives.md / search.md / posts/_index.md 也都加了對應 zh-tw 版本 每個 zh-tw 文件 front matter 加 language: "zh-tw"(Hugo 多語言約定) 複製 PaperMod 的 themes/PaperMod/i18n/zh-tw.yaml 到本地 i18n/zh-tw.yaml(UI 文案:分鐘/字/目錄/上一頁/下一頁/語言 等) zh-tw 菜單用中文繁體顯示名:文章 / 維護日誌 / 原始碼 / 彙整 / 搜尋 / 標籤 / 關於;homeInfoParams.Content 也轉繁中(假如我走進海裡, 你會拉住我麼?) Hugo 修復 languageCode 棄用警告,改用 locale(zh-CN / zh-TW) Hugo --minify 雙語構建通過:ZH 259 頁 / ZH-TW 257 頁(差 2 個是歷史 alias 重定向目錄,不重要) 已驗證生成的 zh-tw HTML 含 <html lang=zh-tw>、og:locale=zh_TW、og:description 是繁體中文、hreflang 雙向鏈接、語言切換器菜單正確顯示 決策 用 s2tw(簡體→臺灣繁體)而不是 s2t(僅字符轉換):前者同時做用詞轉換(軟件→軟件、網絡→網絡、視頻→影片、內存→記憶體);後者只轉字符會保留大陸用詞 OpenCC 轉換覆蓋整篇文件(包括 front matter):會把 title/description/tags 等中文值的字符也轉;英文字段/URL/代碼塊不動 claudelog 也一起轉了:雖然不是"文章",但既然公開在站點,雙語可讀性更一致 不動 defaultContentLanguageInSubdir = false:保持簡體版 URL 不帶 /zh/ 前綴(避免破壞現有 SEO/外鏈),只有繁體版帶 /zh-tw/ 下次建議 Hugo 0.161 還有 3 個 PaperMod 模板的棄用警告(LanguageDirection / LanguageCode / LanguageName),等 PaperMod 升級時自然解決 2 個差量(20260805-qds / 20260817-jtc)是歷史 alias 目錄只在 zh 出現,不影響正常瀏覽,可加忽略 s2tw 自動轉換的術語可能在少數地方不準確(如博客自創詞、品牌名),需要人工抽查 OpenCC 對 emoji/英文標點不轉換,只動中文字符,所以不會破壞 Markdown 語法 推送 本批未推送,等待用戶授權。

2026年08月22日 · 5 分鐘 · 2454 字

2026-08-19

維護記錄 完成的工作 應用戶要求,把 scripts 工作流從 Node.js + tsc 全面遷移到 Deno ✅ 新增 deno.json:tasks 列出全部 14 個入口(test / validate-posts / check-dead-links / format-markdown / sync-covers / gen-covers / rename-posts / optimize-images / git-commit-push + 各 *-dry 變體),unstable: ["sloppy-imports"] 避免改 28 處 .js 後綴 import,imports: { sharp: "npm:sharp@0.33.5" } 鎖定 sharp 版本,nodeModulesDir: "none" 拒絕自動創建 node_modules/ 更新 5 個 workflow yml(validate-posts / sync-covers / check-dead-links / test-scripts / deploy):替換 setup-node@v4 + npm install + npx tsc 三件套為 denoland/setup-deno@v2,把 node scripts/dist/xxx.js 全部換成 deno task xxx 或 deno run -A scripts/xxx.ts 刪除 package.json / package-lock.json / tsconfig.scripts.json / scripts/dist/(168K 編譯產物,git 歷史裡也會清) 新增 deno.lock(212 行,鎖定 sharp + 平臺原生包 + transitive deps),跟 package-lock.json 一樣入倉 更新 .gitignore:scripts/dist/ 改為 .tools/(Deno 二進制 + cache,本地用,不入倉)+ .npm-cache/(舊依賴) 更新 CLAUDE.md 反映新結構(Deno 命令、scripts 目錄樹、修正 content/maintenance/ → content/claudelog/、刪除不存在的 format-markdown.yml 引用) POC 5 項全過:Deno 直接吃 .ts / node:test 原生兼容 / node:child_process.execSync 工作 / npm:sharp 預編譯包自動下載 / denoland/setup-deno@v2 一行可換 測試 39 passed (162 steps),0 failed — 與 Node + tsc 完全等價 ✅ 所有 9 個腳本 dry-run 驗證可加載/可執行 遇到的問題 沙箱 HOME 不可寫 ⚠️ deno_install 默認裝到 ~/.deno,沙箱拒絕 curl ... | sh 不接受 inline DENO_INSTALL=... env(子 shell 不繼承 export 之前的賦值) 解決:export DENO_INSTALL="$PWD/.tools/deno" && curl ... | sh -s -- -y Deno 默認緩存路徑也不可寫 ⚠️ DENO_DIR 默認是 ~/.cache/deno,沙箱拒 解決:本地開發設 export DENO_DIR="$PWD/.tools/deno-cache",CI runner 不存在此問題 --sloppy-imports 是攔路虎 ⚠️ 全部 28 處 from './lib/xxx.js'(實際 .ts 文件)在 Deno 默認嚴格模式下報錯 三種解法:加 --sloppy-imports(每次手動)、deno.json 配 unstable: ["sloppy-imports"](項目級)、手工改 28 處後綴(易出錯) 採用 #2,0 行代碼改動,vs 改 28 處 import + 擔心 typo sharp 自動下載有警告 ⚠️ Deno 默認跳過 npm 包 lifecycle scripts,提示 “Enable nodeModulesDir: auto” sharp 不需要 postinstall(平臺預編譯包 @img/sharp-darwin-arm64 等),警告可忽略 Linux CI 同理:會自動下 @img/sharp-linux-x64 Deno task 不解析 -- 分隔符 ⚠️ 原計劃用 deno task xxx -- --message "..."(像 npm 那樣) 實測 Deno 2.9 把 -- 原樣透傳給腳本,被 parseArgs 當成 -- flag 解決:workflow 裡改用 deno run -A scripts/xxx.ts --message "..." 直接調用 CLAUDE.md 文檔漂移 ⚠️ 原本引用了 .github/workflows/format-markdown.yml,但文件根本不存在(deploy.yml 裡有 format-markdown.ts 調用,不是獨立 workflow) content/maintenance/ 是錯的,實際是 content/claudelog/ 順手一起修了 決策點 保留 Node + prettier:Deno 沒有等價 prettier 的內置格式化器,且 prettier 跨語言一致性強。deploy.yml 裡 format-markdown.ts shell 調用 prettier 是最乾淨的邊界。代價:workflow 仍需 setup-node@v4 + npm install -g prettier@3.9.6,但 node_modules 不存在,體積零增量 保留 migrate-slug-scheme.ts(一次性腳本,無測試,workflow 裡沒引用):雖然功能已結束,但刪用戶寫過的代碼得用戶授權。留著,以後清理 不加 nodeModulesDir: "auto":會強制創建 node_modules/ 目錄,違背"零 npm"目標。sharp 無 postinstall,警告忽略 CI 影響 before:4 個 workflow 各 5 步(checkout → setup-node → npm install → npx tsc → node scripts/dist/xxx.js),平均每 job ~45 秒在 npm 上 after:3 步(checkout → setup-deno → deno task xxx),setup-deno 幾秒,deno 跑 .ts 是緩存熱路徑 預計 CI 時間省 30-40% 下次建議 觀察第一次 push 觸發 deploy.yml 的運行,確認 sharp 在 Linux runner 上跑通(@img/sharp-linux-x64 自動下載) 如果 deno task test 在 CI 比 node --test scripts/dist/__tests__/*.js 慢(不太可能,但 Deno 冷啟動比 node 慢),考慮加 cache: 'deno' 或類似策略到 setup-deno migrate-slug-scheme.ts 可以獨立刪(下次大掃除時),無功能影響 如果哪天不需要 prettier 了,可以把 deploy.yml 的 setup-node@v4 也去掉,實現純 Deno 文件變更清單 新增:deno.json、deno.lock 刪除:package.json、package-lock.json、tsconfig.scripts.json、scripts/dist/(含 11 .js + 3 .js in lib/ + 10 .js in tests/) 修改:.github/workflows/{deploy,validate-posts,sync-covers,check-dead-links,test-scripts}.yml + CLAUDE.md + .gitignore 腳本源碼(scripts/**/*.ts):0 行改動

2026年08月19日 · 4 分鐘 · 1659 字

2026-08-18

維護記錄 完成的工作 拉取 origin/master 的 6 個新提交(fast-forward),工作樹已同步 ✅ 應用戶要求,只優化工作流 #1(拆分 chore: auto-fix content 噪音 commit),其他建議(PR 預覽、URL 穩定、Dependabot)不動 ✅ 實現 scripts/git-commit-push.ts 的自動 commit message 分類: 5 個分類路徑:rename / fm / format / covers / posts 混合或無法識別時回退到 --message-fallback 新增 --message-fallback 參數,deploy.yml 調用改為同時傳 --message 和 --message-fallback 頂層 CLI 代碼包到 isMain 守衛,避免被 import 時誤執行(之前 import 會因 process.exit(1) 失敗) 新增 scripts/__tests__/git-commit-push.test.ts,13 個測試覆蓋所有分類路徑 測試 + E2E dry-run 驗證:rename 漂移 → chore(rename): sync post slugs (N files);fm 注入 → chore(fm): inject frontmatter (N files);混合 → fallback 全部測試 164/164 通過,Hugo 構建 clean ✅ 遇到的問題 測試陷阱 1:git rename 檢測對短文件失敗 ⚠️ 最初測試 fixture 只寫 10 行 body,git -M20% 閾值下也檢測不出 rename 實際 rename-posts.js 跑的都是 30+ 行文章,body 微調 < 20% 行 解決:測試 fixture 加到 40 段,模擬真實文章密度 測試陷阱 2:git mv vs 文件系統 mv ⚠️ 最初用 mv 改文件名 + writeFileSync 覆蓋,git 不識別為 rename(變 A+D) 解決:改用 git mv + 追加一行,模擬 rename-posts.js 真實操作 測試陷阱 3:Apple Git 的 git rm 副作用 ⚠️ git rm 刪除 tracked 文件後,git 2.x 會清理空目錄 後續 writeFileSync 寫新 SVG 時 ENOENT 解決:測試 setup 時預放 .gitkeep 佔位文件 模塊化陷阱:頂層代碼副作用 ⚠️ 把分類函數 export 給測試用後,import 時頂層 if (!message) process.exit(1) 會觸發 解決:用 pathToFileURL(process.argv[1]).href === import.meta.url 守衛 CLI 代碼 未用 import ⚠️ 測試文件 import 了 join from 'node:path',但實際用的是 Array.prototype.join 自審時發現並清理,避免汙染 決策點 不改 sync-covers.yml 的調用方式:它只傳 --message 不傳 --message-fallback,新腳本會讓 fallback = --message(原行為)。而且它的場景(cover IO)會被自動分類為 chore(covers): ...,永遠走不到 fallback 分支。比之前更精確 ✅ 降級策略而非強制分類:當改動是"rename + 改了正文"或"fm 注入 + 新建 cover"這種混合,分類不可靠,返回 null 讓 fallback 接住。不冒險亂分類 下次建議 觀察接下來幾天的 auto-fix commit,如果 chore(rename) / chore(fm) 頻繁出現,說明分類正確;如果大量 chore: auto-fix content (fallback) 出現,說明有分類邏輯沒覆蓋的場景,需要擴展 sync-covers.yml 也可以從 chore(assets): remove orphan cover images 升級到自動分類(會產出 chore(covers): -N cover image(s)),讓兩個 workflow 的 commit 風格統一 文件變更清單 新增:scripts/__tests__/git-commit-push.test.ts(13 測試) 修改:scripts/git-commit-push.ts(+196 行:isMain 守衛 + classifyStagedChanges + 子函數) 修改:.github/workflows/deploy.yml(commit step 加 --message-fallback + 註釋)

2026年08月18日 · 3 分鐘 · 1095 字

2026-08-17

維護記錄 完成的工作 拉取 origin/master 的 18 個新提交(fast-forward),並同步 PaperMod 子模塊到 v8.0-139 ✅ 創建新文章 content/posts/20260817[05hog4].md(標題「文章的變化」),作者口述風格,半角逗號佔位符寫法,參考近期 20260807[01jma3].md 的日誌類 frontmatter ✅ 用 rename-posts.js 由 body 算出 hash 並重命名佔位文件為 20260817[05hog4].md ✅ 用 gen-covers.js --files ... --force 生成封面 static/images/covers/20260817[05hog4].svg(teal / patternConcentric)✅ 手動修正 front matter 中 cover.image 引用(rename-posts 不會同步更新 cover 路徑,這是已知 bug)⚠️ hugo --minify 構建通過,新頁面 public/posts/2026081705hog4/ 正常生成,封面路徑正確解析 ✅ 更新 content/claudelog/2026-08-17.md ✅ 遇到的問題 gen-covers.js --files 接受相對路徑時會被腳本拼接成 content/posts/content/posts/...,必須傳 basename(不帶 content/posts/ 前綴) ⚠️ - 已規避 rename-posts.js 在重命名佔位文件後不會同步更新 front matter 裡的 cover.image 路徑 ⚠️ - 已手動修正;建議下次讓用戶或腳本執行後立即檢查 front matter 完整性 下次建議 可以考慮給 rename-posts.js 加一個 --sync-cover-fm 開關,自動同步 cover.image 引用,避免遺漏 1raw=$(hashed-slug) 2old="images/covers/<oldSlug>.svg" 3new="images/covers/<newSlug>.svg" 4raw.replace(old, new) 維護記錄 (追加 - 命名規則重構 + CI 修復) 完成的工作 命名規則改造 目標:改造 posts 命名規則 YYYYMMDD[hash].md → YYYYMMDD-{slug}-{hash3}.md,讓文件名一眼能讀懂文章標題 ✅ 方案選型:經 ask_user_question 與用戶確認方案 B(日期 + slug + 3 位 hash)、slug 從 title 自動生成、中文保留、遷移全部 221 篇歷史文章、生成 Hugo aliases 自動 301 scripts/rename-posts.ts 改造: 新增 computeHash3 純函數(SHA-256 前 2 字節 → 16-bit base36) 新增 slugify 純函數(保留 CJK unicode + 拉丁字母數字,其餘替換為連字符,長度上限 80,空串兜底 'untitled') 新增 oldUrlFromSlug 純函數(支持 YYYYMMDD[hash] 和 YYYY-MM-DD-slug 兩種歷史格式推導舊 URL) RenamePlan 接口擴展:新增 title、oldUrl、hash3 字段(替代 hash6) buildReport 改用 slugify + computeHash3 命名 executePlan 無需改動(已 git mv + 同步 cover) 新增 scripts/migrate-slug-scheme.ts:一次性遷移腳本 默認 dry-run,加 --apply 才落地 調用 buildReport + executePlan,並在 front matter 注入 aliases: ["/posts/{oldSlug}/"] injectAliases 支持合併已有 aliases(數組/字符串兩種格式) 碰撞檢測 + 失敗即停 測試套件更新: rename-posts.test.ts 中已有斷言 plans[0]!.newSlug.startsWith('20240115') 驗證 date 前綴保留 → 收緊為正則 /^20240115-.+-[a-z0-9]{1,4}$/ 新增 13 個測試:computeHash3 ×3 / slugify ×7 / oldUrlFromSlug ×3 測試套件 138 → 151,全部通過 ✅ 遷移執行 dry-run 報告:221 篇待遷移,0 碰撞 執行:node scripts/dist/migrate-slug-scheme.js --apply --verbose 221 篇 .md + 220 個 .svg 重命名(全部用 git mv 保留歷史) 441 個文件改動,git 全部識別為 R(rename),內容相似度 54%-100% front matter 注入 aliases:每篇文章新加 aliases: ["/posts/{oldSlug}/"] Hugo 構建驗證: Pages: 264 → 265 Aliases: 15 → 224(舊 URL 全部生成了 301 等價頁面) 抽樣 20260817-文章的變化-jtc/index.html 包含: 1<link rel=canonical href=https://sdttttt.online/posts/20260817-文章的變化-jtc/> 2<meta http-equiv=refresh content="0; url=..."> 本地測試:151/151 通過 ✅ Git 提交(多 commit 策略,經 ask_user_question 確認) 5a417ea chore(scripts): 新增 YYYYMMDD-slug-hash 命名支持 + 一次性遷移腳本 5a7ad18 chore(posts): 遷移 221 篇文章到 YYYYMMDD-slug-hash 命名格式 第一次推送與衝突解決 git push origin master 被遠程拒絕:CI 的 chore: auto-fix content(4ace5ca)剛把 20260817[05hog4] 改名為 20260817[03wwo2](因 body 改了導致 SHA-256 變了) git pull --rebase 出現 rename/rename 衝突:CI → 03wwo2,我 → 20260817-文章的變化-jtc 解決策略:保留我的遷移結果(jtc),丟棄 CI 中間產物(03wwo2) git rm content/posts/20260817[03wwo2].md + 同名 .svg git add 我的遷移結果 git rebase --continue 失誤 1(誠實交代):rebase 後 20260817-文章的變化-jtc.md 文件裡殘留衝突標記 第一次嘗試修復時直接 write 文件,差點覆蓋掉用戶手動潤色的版本(末尾換行、空行) 通過 git show 4ace5ca: 提取用戶的精確版本,再疊加新 frontmatter 恢復 ✅ 用 git commit --fixup=9c99956 + rebase -i --autosquash 把修復折進原 commit,不增加冗餘 commit 重新編號後的兩個 commit:613cd99(腳本) + 2445eae(遷移) 推送成功 ✅ CI 失敗與修復 推送後 CI deploy 失敗: 1ERROR error building site: "/content/posts/20200311-Github-Actions-3fw.md:2:1": 2EOF looking for end YAML front matter delimiter 根因:scripts/gen-covers.ts:injectCoverField line 266 字符串模板 ---\n${newFm}--- 中,閉合符 --- 前缺 \n 當文件 frontmatter 末尾為 aliases: [...]\n(我遷移後所有文章都是這種結構),走 if 分支(fm.replace)重寫 cover 塊後 newFm 末尾是 \n(來自 + '\n'),模板拼接產生 ---\n...\n--- 看似正常 但當文件沒有 trailing newline 時,regex [\s\S]*?\n--- 不匹配(因為根本沒有第二個 ---),replace 不替換 → 文件保持原樣 → 但原文件 frontmatter 沒問題… 矛盾! 真正重現:本地用 v0.161.1 + 手動寫一個無 trailing newline 的測試文件 + 跑 injectCoverField 老邏輯 → 輸出文件 frontmatter aliases: [...]---(無 \n 分隔) Hugo 解析:嚴格模式下視 --- 不在行首 → EOF 找不到結束符 → 報錯 修復:scripts/gen-covers.ts 1let newFm = fm.replace(/^cover:\s*\n((?: .+\n?)+)/m, newCover + "\n"); 2// 確保 newFm 以換行結尾,避免與閉合 --- 之間缺少分隔符 3if (!newFm.endsWith("\n")) newFm += "\n"; 4const newRaw = raw.replace(/^---\n[\s\S]*?\n---/, `---\n${newFm}---`); 移除 else 分支多餘的 + '\n'(避免雙換行) 本地驗證: 復現腳本驗證 buggy 輸出:aliases: ["/posts/2020031100oh3i/"]---(無 \n) 復現腳本驗證 fixed 輸出:aliases: ["/posts/2020031100oh3i/"]\n---(有 \n) 跑 hugo --minify 在 buggy 文件上 → 與 CI 完全一致的 EOF 錯誤 → 確認根因 跑 hugo --minify 在 fixed 文件上 → 通過 ✅ 測試套件 151/151 通過 ✅ 誠實交代 - 失誤 2:我誤以為本地 v0.161 build OK = fix 沒問題 實際上我沒有把 bug 真正跑出來 —— 老代碼生成的輸出與原文件字節序列相同,所以 git diff 顯示 0 改動 真正的 bug 只在沒有 trailing newline 的輸入上才會暴露 CI 上的 v0.165 比本地 v0.161 嚴格,所以 CI 才報錯 教訓:純函數層面 fix 一定要構造能觸發 bug 的輸入 + 獨立驗證,不能依賴"diff 為空 = OK" 推送修復與最終狀態 32e7cd4 fix(gen-covers): 修復 injectCoverField 丟失 frontmatter 末尾換行的 bug CI 重新跑 → 成功 ✅(產生 27fa25b chore: auto-fix content,是部署成功後的文件名微調) 新文章線上 URL:https://sdttttt.online/posts/20260817-文章的變化-1e69/(後綴 hash 因 prettier 規範化略變,deploy.yml 自動處理) 遇到的問題 rename/rename 衝突:本地遷移和 CI auto-fix 在同一文件上往不同方向 rename。教訓:涉及大量 rename 的操作前應先 pull 同步 CI 狀態 ⚠️ rebase 後衝突標記殘留:git 有時不會自動清理 file content 中的衝突標記,只清理 status。教訓:rebase 後必須 hugo --minify 驗證 build,不能只看 git status 乾淨 ⚠️ bug 漏檢:本地 v0.161 與 CI v0.165 行為不一致(後者更嚴格),導致 bug 在本地測不出來。教訓:涉及 frontmatter / 嚴格解析的代碼應該用與 CI 同版本的工具驗證 ⚠️ 不區分大小寫的本地 + 區分大小寫的遠程:APFS 默認 case-insensitive,導致本地文件名 Github-Actions 在 Linux CI 上行為可能不同。本次沒踩坑,但值得警惕 ⚠️ 下次建議 在 CI 流程開始前加一步 git fetch + check clean 的 sanity check,避免 race 給 gen-covers.ts 加專門測試:用 writeFile 寫出無 trailing newline 的輸入,驗證輸出 frontmatter 閉合 在 deploy workflow 加 step:hugo --minify 失敗時打印前 3 個報錯的 .md 文件的 head/tail,便於排查 考慮給 rename-posts.js 加 dry-run-only 模式(默認 dry-run,避免誤操作) 新 hash 計算結果應在文件 gitattributes 或 .gitignore 里加 ignore,避免 auto-fix commit 噪聲(目前 27fa25b 這種 commit 頻率會越來越高) 文件變更清單 新增:scripts/migrate-slug-scheme.ts 修改:scripts/rename-posts.ts(computeHash3 + slugify + oldUrlFromSlug + RenamePlan 字段) 修改:scripts/gen-covers.ts(injectCoverField 末尾換行兜底) 修改:scripts/__tests__/rename-posts.test.ts(+13 測試) 修改:scripts/__tests__/rename-posts-execute.test.ts(RenamePlan 字段適配) 重命名:221 個 content/posts/YYYYMMDD[hash].md → content/posts/YYYYMMDD-{slug}-{hash3}.md 重命名:220 個 static/images/covers/YYYYMMDD[hash].svg → 同名格式 修改:221 個 .md 的 front matter(新增 aliases: 字段)

2026年08月17日 · 7 分鐘 · 3118 字

2026-08-07

維護記錄 完成的工作 創建新文章 content/posts/20260807[0534gw].md(標題「自述 - 小學時期」),參考現有草稿 frontmatter 格式,並設置為 draft: true(不展示狀態)✅ 用 gen-covers --files --force 為文章生成封面 static/images/covers/20260807[0534gw].svg(gold / patternConcentric)✅ 運行 validate-posts.js 校驗通過,文章與封面一致 ✅ 遇到的問題 無 下次建議 無

2026年08月07日 · 1 分鐘 · 192 字

2026-08-05

維護記錄 完成的工作 創建帶新 tag 書評 的文章模板:content/posts/20260805[0buk4e].md,front matter 含 tags: ["書評"]、draft: false、author: sdttttt,正文留空待用戶填寫。✅ 遇到的問題 無。✅ 下次建議 書評 是除 2026-08-01 精簡後的 7 個核心 tag 之外的新增類別,寫作時如出現多本/多主題書評,可考慮是否再細分(例如 技術書評 / 小說書評)以保持 tag 粒度與既有體系一致。 若後續 書評 文章數量持續增長,可在 content/posts/ 下補一個 _index.md 的 description 或在主頁 info 中提示,方便讀者篩選。

2026年08月05日 · 1 分鐘 · 243 字

2026-08-01

維護記錄 完成的工作 精簡博客文章 tags 體系:採用方案 A(激進精簡),將 content/posts/ 下 218 篇文章的 13 個 tag 收斂為 7 個。✅ 合併到 開發:工具、分佈式、建站、Algorithm(子主題歸併) 新增 雜談:金錢、新聞、文字(單例容納) 清理重複條目:3 篇文章的 tags 數組中存在同一 tag 多次出現的情況,強制去重 批量執行腳本:/tmp/consolidate-tags.mjs(Node v24,原地編輯 frontmatter 的 tags 行,其餘內容保持不變) 改動文件數:14 篇(佔 218 篇的 6.4%) 最終分佈:日誌 95 / 開發 49 / 思考 40 / 軟路由 14 / 學習 10 / 安全 6 / 雜談 3 遇到的問題 我的初步 “+9” 淨變化預測在數學上出現 ±1 偏差,實際 開發 為 +4 而非 +9,原因是 20260312[0443ef].md 同時擁有 建站 與 工具,dedup 後只貢獻 1 個 開發 出現次數;同樣原本預測裡的邊界情況需用真實全局計數複核。⚠️ - 不影響最終結果,僅是粗算與精算的偏差。 下次建議 新增文章時建議優先複用現有 7 個 tag,僅在確有跨類目需求時再討論是否擴展。 在 scripts/ 下考慮沉澱 consolidate-tags.mjs 為可重入工具,便於後續調整 tag 體系時一鍵重跑 + 校驗;當前實現還停留在 /tmp/ 裡,無版本控制。 完成的工作 (續) 修復 layouts/partials/custom_footer.html 的渲染範圍:之前 1 行 stub 把 layouts/partials/footer.html 轉交給 custom_footer.html,而後者只塞了 Cloudflare Analytics,等於屏蔽了 PaperMod 的全部 footer 功能,包括回頂按鈕、代碼複製按鈕、主題切換 JS、菜單滾動位置記憶、版權/Powered by 致謝等。✅ 恢復 PaperMod 原版 _partials/footer.html 的全部內容:版權/年份、Powered by Hugo & PaperMod、#top-link 錨點和 SVG、滾動監聽 JS、平滑滾動 JS、#theme-toggle JS、copy-code 按鈕 JS;同時保留 PaperMod 的 {{- partial "extend_footer.html" . }} 鉤子。✅ 保留 Cloudflare Web Analytics:在新版的 custom_footer.html 末尾保留原有的 {{- with site.Params.cloudflareAnalytics.token }} 注入邏輯,並 hugo --minify 構建後用 grep 校驗 id=top-link / copy-code / Powered by / class=footer / menu-scroll / cf-beacon 在生成的 public/posts/.../index.html 中重新出現。✅ 遇到的問題 (續) Hugo minifier 會把 <footer class="footer"> 壓縮成 <footer class=footer>,第一次 grep "class=\"footer\"" 給出 0 命中導致誤判;改為匹配 class=footer 即可。無功能影響。⚠️ 下次建議 (續) 當前 custom_footer.html 用 --ultra-compact 等價於"複製粘貼 PaperMod 原內容",會帶來一個問題:PaperMod 子模塊後續升級 footer 時此處不會自動同步。如果想跟進官方 footer 改進,可以改用 layouts/partials/footer.html 裡 {{ block "footer" . }}{{ end }} 或類似模式避免硬編碼;短期內(PaperMod 不會有大改)維持現狀即可。

2026年08月01日 · 2 分鐘 · 948 字

2026-07-30

維護記錄 完成的工作 將 scripts/rename-posts.ts 接入 .github/workflows/deploy.yml:在 Install Bun dependencies 之後、Generate covers and inject front matter 之前新增 Rename posts 步驟,使每次 master 推送自動將文章重命名為 YYYYMMDD[xxxxxx].md,並同步處理 cover SVG 與 frontmatter 引用。✅ package.json 新增 typescript@7.0.2 與 @types/bun 開發依賴,用於 CI 中編譯腳本。✅ 新增 tsconfig.scripts.json:將 scripts/**/*.ts 編譯輸出到 scripts/dist/,noEmitOnError: false 保證即使存在類型錯誤也會產出 JS。✅ .gitignore 增加 scripts/dist/,避免提交 CI 產物。✅ 更新 .github/workflows/deploy.yml:安裝依賴後先執行 bunx tsc -p tsconfig.scripts.json,隨後所有 bun scripts/*.ts 改為 bun scripts/dist/*.js。✅ 修復 scripts/format-markdown.ts 中 execSync 的 shell: true 在 TypeScript 7 / @types/node 下產生的類型錯誤,改為根據平臺選擇 cmd.exe 或 /bin/sh。✅ 修復 scripts/__tests__/rename-posts.test.ts 的跨文件 mock.module 汙染問題:在 beforeEach 中恢復真實 node:fs/promises 與 node:fs 模塊,避免其它測試的 mock 影響真實 fs 集成測試。✅ 遷移到 Node v24: package.json 刪除 bun-types、@types/bun,新增 @types/node@^24;移除 bun.lock,由 npm install 生成 package-lock.json。 tsconfig.scripts.json 切換到 module/moduleResolution: NodeNext,使編譯產物的相對導入帶上 .js 後綴。 所有腳本的 shebang 和使用說明改為 node scripts/dist/<name>.js;scripts/rename-posts.ts 的 Bun.spawn 替換為 node:child_process 的 spawn。 所有 8 個測試文件改用 node:test + 本地 expect 助手(scripts/__tests__/expect.ts),並把原本 mock node:fs/promises 的用例改為真實臨時目錄集成測試(inTempDir 助手),避免了 Node 實驗性 --experimental-test-module-mocks 的緩存痛點。 5 個 GitHub Actions workflow(deploy.yml、test-scripts.yml、check-dead-links.yml、sync-covers.yml、validate-posts.yml)移除 oven-sh/setup-bun,改為 actions/setup-node@v4 + npm install + npx tsc + node scripts/dist/*.js。✅ 遇到的問題 tsc 首次編譯報錯 Cannot find type definition file for 'bun',原因是僅安裝 bun-types 時 types: ["bun"] 無法解析;補充安裝 @types/bun 後解決。⚠️ 編譯過程中 scripts/format-markdown.ts 的 shell: true 觸發類型錯誤,已按平臺顯式指定 shell 路徑。⚠️ 全量 bun test 因 mock.module 在 bun:test 中跨文件持久而偶發/必發失敗;已通過恢復真實模塊解決。⚠️ Node 原生 ESM 不支持擴展名省略,源 TS 文件全部相對導入加上 .js 後綴。⚠️ Node 的 mock.module 只能影響後續 import(),而 ESM 模塊緩存對同一次 import 複用舊導出;改用真實臨時目錄集成測試以繞過實驗性 API。⚠️ node --test scripts/dist/__tests__/*.js 在 npm scripts 中依賴 shell 展開 glob,CI (bash) 正常;Windows 上需另行處理。⚠️ 下次建議 觀察首次遷移後 CI 運行日誌(Hugo on GitHub Pages、Test Scripts 等),確認 Node 工具鏈無迴歸。 如需把 npm test 在 Windows 上做成跨平臺,可改用 node --test scripts/dist/__tests__(目錄)或顯式列舉文件。

2026年07月30日 · 3 分鐘 · 1204 字

2026-07-28

維護記錄 完成的工作 將首頁從 profileMode 切換為 PaperMod 的 Regular Mode:移除 params.profileMode 配置,新增 params.homeInfoParams,保留原有站點標題與副標題展示。✅ 新增 params.env = "production",讓 PaperMod 在所有構建場景下都按生產環境處理(影響 robots、圖片優化等)。✅ 新增 scripts/optimize-images.ts 圖片壓縮腳本,使用 sharp 對 PNG/JPEG/WebP/AVIF/GIF/TIFF 進行壓縮、限制最大寬度、生成 WebP 變體;並在 package.json 中加入 sharp 開發依賴。✅ 更新 .github/workflows/deploy.yml:新增 bun install 和 Optimize images 步驟,CI 每次構建時自動為 assets/images 生成寬度不超過 1200px 的 .webp 變體,且不覆蓋原圖。✅ 新增 scripts/rename-posts.ts:將 content/posts/ 下的文章批量重命名為 YYYYMMDD[xxxxxx].md(方括號為字面字符),其中日期取自 frontmatter date 字段,hash 是去除 frontmatter 後的 body 用 SHA-256 取前 3 字節(24 bit)後轉 base36(6 位固定長度)。配套重命名 assets/images/covers/{slug}.svg 並改寫 frontmatter cover.image;用 git mv 保留歷史,git 不可用時降級 fs.rename;支持 --dry-run / --verbose;已是新格式、缺 date、格式無效的文件自動跳過;目標名碰撞時按用戶策略「報錯停止」並列出衝突文件。✅ 新增 scripts/__tests__/rename-posts.test.ts:30 個測試覆蓋 normalizeDate(三種日期格式 + 月日越界 + 補零)/ extractBody / computeHash6(確定性、長度、base36 字符集、對末尾空白敏感、SHA-256 已知向量防止誤改回 djb2)/ rewriteCoverImage / buildReport(7 個集成測試覆蓋有效文章、缺 date、無效 date、已是新格式、忽略 _index.md、自定義封面不重命名、封面物理缺失)/ detectCollisions。全綠(bun test 134/134 通過)。✅ 用 git rm 刪除 5 對重複文章中用戶指定的 5 個,同步刪除對應的 5 個 cover SVG(避免 sync-covers 誤判為孤兒、且這些 SVG 本來就只服務被刪的 .md)。✅ 執行 bun scripts/rename-posts.ts 完成 216 篇文章 + 215 個 cover SVG 的一次性重命名;git 全部以 R (rename) 跟蹤,完整保留歷史。✅ 驗證 bun scripts/validate-posts.ts 全綠 + hugo --minify 乾淨構建(265 頁)。✅ 遇到的問題 用戶最初理解 YYYYMMDD{6位hash}.md 時我誤把方括號當成可選語法,按無方括號實現,後被糾正改為字面方括號 YYYYMMDD[xxxxxx].md(修正 computeHash6 輸出格式 + 測試 + 註釋)。⚠️ 用戶指出 hash 用自寫 djb2 不專業,改用 node:crypto 的 SHA-256(前 3 字節,分佈更均勻、行業標準)。⚠️ dry-run 時腳本在 5 對文件上報告目標名碰撞,懷疑 djb2 分佈問題。實際排查:4 種不同哈希(djb2 24bit / djb2 full 32bit / FNV-1a 24bit / xxhash32 24bit)以及 SHA-256 全部在完全相同的 5 對上碰撞 → 證實這 5 對 body 真的 100% 相同(完整 64 字符 SHA-256 也一致),屬於歷史遺留的真實重複文章,不是哈希質量問題。⚠️ 解決方案:用戶手動選保留哪個,git rm 刪另一個,配套 cover SVG 同步刪除。 第一次 hugo --minify 後看到 public/ 裡仍有 2020-10-29-log-8/ 等舊 URL,懷疑 Hugo 把新文件當舊名渲染。⚠️ 實際是 hugo 沒清空 public/,舊文件殘留;rm -rf public/ resources/ && hugo --minify 後正確:URL 形如 /posts/2020031100oh3i/,Hugo slugify 自動去掉方括號。⚠️ URL 全部變更:舊 /posts/2020-03-11-github-actions/ → 新 /posts/2020031100oh3i/。按用戶決定不添加 alias,所有舊 URL 將 404。⚠️ 下次建議 如需進一步自定義首頁信息卡片樣式,可通過 assets/css/extended/*.css 覆蓋 .home-info 相關樣式。 舊的 /posts/{slug}/ URL 已全部失效。如未來想恢復外部鏈接有效性,可寫一個小腳本掃描 git 歷史為每篇生成 aliases frontmatter。 部署到生產後建議用 curl -I 抽查若干新舊 URL 確認 404/200 符合預期,並提交 Google Search Console 站點地圖更新。

2026年07月28日 · 3 分鐘 · 1452 字

2026-07-27

維護記錄 完成的工作 修改 scripts/gen-covers.ts,移除 SVG 封面中的方形與菱形元素: 從 symbol 列表刪除 □ 與 ◇ 刪除 patternRectangles 與 patternGrid 兩個圖案函數,並從 PATTERN_FNS 中移除 同步更新 scripts/__tests__/gen-covers.test.ts,移除對已刪除圖案的引用 運行 bun test scripts/__tests__/gen-covers.test.ts,29 個測試全部通過 ✅ 合併自動修復流程到 deploy.yml: 改寫 .github/workflows/deploy.yml,把 gen-covers + format-markdown 併入 build job,在 hugo --minify 之前順序執行(gen-covers 先,format 後,一次提交無殘留) 刪除獨立的 .github/workflows/format-markdown.yml 與 .github/workflows/gen-covers.yml scripts/git-commit-push.ts 加 git pull --rebase 兜底,避免併發 push 被拒 移除 deploy build job 的 if: github.actor != 'github-actions[bot]'(該條件在 GITHUB_TOKEN push 場景下從未生效,是死代碼) 新增 permissions: contents: write 與 workflow_dispatch 觸發器 效果:一次 push → 一個 bot commit → 部署的是修復後的內容(封面、格式化結果即時上線) ✅ 遇到的問題 最初計劃新建獨立的 auto-fix.yml workflow,但發現 GITHUB_TOKEN 推送的 commit 不會觸發新 workflow run,導致封面/格式化結果延遲一次 push 才上線 ⚠️ 解決方案:直接合併到 deploy.yml,在構建前完成修復,部署的就是修復後的內容 下次建議 若後續想補充新圖案,可優先加入曲線/有機形態,進一步豐富封面視覺差異 如需進一步降低 bot commit 噪音,可考慮在 git-commit-push.ts 里加 git diff-index --quiet HEAD 檢查,有改動才 commit/push

2026年07月27日 · 2 分鐘 · 570 字