跳到內容
OmniRoute source

Release Checklist (中文 (繁體))

最後更新: 2026-06-28 — v3.8.40 精簡化發行流程,運用 Claude Code Skills 實現自動化。

在發行之間保持佇列/分支為綠色: 請參閱 RELEASE_GREEN.md (/green-prs 系列指令 + npm run check:release-green + /babysit + 夜間排程)。定期執行此流程—— 尤其是在執行本檢查清單之前——可讓發行 PR 一開始就處於綠色狀態。

Terminal window
# 1. 更新版本號 + 產生 CHANGELOG(skill)
/version-bump-cc patch # 或 minor / major
# 2. 在本機執行品質門檻檢查
npm run check # lint + 測試
npm run test:coverage # 完整覆蓋率門檻(60/60/60/60)
# 3. 建置與冒煙測試
npm run build
npm run test:e2e # 選擇性但建議執行
# 4. 產生存放版(skill)
/generate-release-cc
# 5. 部署(skill)
/deploy-vps-both-cc # 或 akamai-cc / local-cc
# 6. 擷取發行佐證(skill)
/capture-release-evidences-cc

npm 可信任發佈(自 v3.8.51 起為預設)— 可依要求暫存,直接發佈作為備援

Section titled “npm 可信任發佈(自 v3.8.51 起為預設)— 可依要求暫存,直接發佈作為備援”

npm-publish.yml 預設透過 **npm 可信任發佈(OIDC)**進行發佈: stage-npm 作業(由 GitHub 託管)會使用 GitHub 的 id-token,為該次執行交換一組短效 npm 憑證——儲存庫密鑰中不需要長效 npm token、不會出現 2FA 提示,並會附加來源證明。 由於可略過 2FA 的 token 正在淘汰,這是 npm 目前認可的繞過方式; 它恢復了專案截至 v3.8.48 為止所使用的全自動流程,同時維持 WS1.3 保證(外洩的 token 無法單獨進行發佈——因為根本沒有 token)。

一次性設定(擁有者): npmjs.com → 套件 omniroute → Settings → Trusted Publisher → GitHub:擁有者 diegosouzapw、儲存庫 OmniRoute、工作流程 npm-publish.yml (環境:無)。在完成這項設定之前,自動步驟會因 ENEEDAUTH 而失敗: 請使用 publish_mode=staged(如下)或 direct 重新分派。

暫存發佈(依要求啟用 — publish_mode=staged)

Section titled “暫存發佈(依要求啟用 — publish_mode=staged)”

npm-publish 工作流程不再直接發佈:它會啟動已封裝的 tarball (check:pack-boot),然後執行 npm stage publish——完全相同的位元組會暫存在 登錄檔中,且在擁有者核准前無法安裝。人工 2FA 閘門已移至 驗證之後,而非之前。

工作流程轉為綠燈後的擁有者操作流程:

  1. npm stage list omniroute——找出 stage id(工作流程摘要中也會顯示)。
  2. 驗證已暫存的位元組(建議):npm stage download <id>,然後將下載的 tarball 安裝至暫用 prefix 並啟動它(npm run check:pack-boot 會在 CI 中自動執行 相同的封裝→安裝→啟動判定)。
  3. npm stage approve <id>——2FA 提示本身就是發佈動作。npm stage reject <id> 則會捨棄它。
  4. 發佈後安全網:發佈後驗證器(v3.8.49 計畫的 WS1.4)會在乾淨的容器中,從 公開登錄檔安裝已發佈版本並啟動它。

緊急備援: 使用 publish_mode=direct 執行 workflow_dispatch,即可恢復舊版的 即時 npm publish(僅在暫存機制本身發生異常時使用;請記錄原因)。

一次性強化(擁有者,npmjs.com): 為 omniroute 將 Trusted Publisher 設定為僅限暫存模式,如此一來,即使長效 token 外洩,也無法從任何位置直接執行 npm publish ——CI 只能暫存;只有擁有者的 2FA 能正式發佈。

損壞成品應變手冊(維持不變): 預設的第一反應應是執行 npm deprecate omniroute@<bad> "<reason> — use <fixed>" (只需幾分鐘、可復原);僅可在 72 小時/無相依套件的期限內執行 npm unpublish, 且絕不可將其作為第一步。Docker:絕不重寫版本標籤——復原方式是將 latest 重新指向上一個正常的 digest。

Docker Hub latest(每次發佈穩定版 SemVer 時皆為必要): docker-publish 工作流程必須同時標記 X.Y.Z,且當 should-promote-latest.sh 判定其為最高的穩定版 SemVer 時,也必須標記 :latest, 兩者必須具有相同的 digest。作業完成後:Hub 上 latest 的 digest 應等於新的 SemVer digest,且 last_updated 已更新。當發行說明提及僅存在於 git 上的修正時, 不得讓 :latest 繼續指向較舊的建置版本。 Compose 快速入門使用 :latest;GitOps 應繼續固定使用 X.Y.Z。請參閱 Docker 發佈通道及 #10317。

標記為 hotfix 的 PR 會跳過繁重的 CI 矩陣(9 分片 E2E、覆蓋率棘輪、 品質門檻、品質延伸檢查),僅保留快速且高訊號的關卡:建置、 單元測試分片、整合測試、vitest、lint/型別檢查、docs-sync、check:pack-artifact 以及 tarball 啟動冒煙測試(check:pack-boot)。目標:在 ≤15 分鐘內變為綠色,而非 ~33 分鐘。

進入條件——必須全部符合(以 Chromium/VS Code/Node 緊急通道為藍本):

  1. 嚴重性:正式環境已中斷——已發布的成品啟動時崩潰/安全性修正/該版本的所有使用者都受影響。「重要」不等於「已中斷」。
  2. 授權:只有倉儲擁有者可以套用 hotfix 標籤。此標籤即為核准——專案 PR 不得自行使用。
  3. 佐證:PR 主體需連結先前完整通過的繁重執行結果(被跳過的工作本來會重新驗證的套件),以及修正本身從失敗到通過的測試記錄。
  4. 範圍:僅限 cherry-pick——最小修正,不得重構,不得夾帶其他變更。

被跳過的覆蓋率/棘輪檢查範圍將由發行分支上的下一個完整執行重新驗證(持續 release-green)——快速通道是跳過等待,而非跳過驗證。 僅限測試的 diff(所有檔案都在 tests/ 下,且不在 tests/e2e/ 下)會自動跳過 E2E 矩陣,無需任何標籤。

  • 此版本的所有目標 PR 均已合併至 release/vX.Y.0
  • 此版本所有未完成的 Linear/issue 項目均已關閉或移至下一個里程碑
  • release/vX.Y.0 分支上的 CI 全部通過
  • 程式碼中沒有 TODO(release) 標記:grep -r "TODO(release)" src/ open-sse/
  • Docker 基礎映像檔已更新至最新版本(目前為 node:24.15.0-trixie-slim)
  • 執行 /version-bump-cc <patch|minor|major>(Claude Code 技能)
    • 更新 package.json、electron/package.json 中的版本
    • 根據自上一個標籤以來的 git 提交重新產生 CHANGELOG.md
    • 更新 README.md 徽章
  • 手動檢閱 CHANGELOG.md,並視需要整理提交訊息
  • 確保 CHANGELOG.md 中最新的 semver 區段與 package.json 版本一致
  • 保留 ## [Unreleased] 作為變更日誌的第一個區段,以供即將進行的工作使用
  • 更新 docs/openapi.yaml → info.version 必須與 package.json 版本一致
  • npm run lint — 0 個錯誤(警告為既有問題)
  • npm run typecheck:core — 無問題
  • npm run typecheck:noimplicit:core — 無問題(嚴格模式)
  • npm run check:cycles — 無循環相依性
  • npm run check:any-budget:t11 — 未超出預算
  • npm run check:route-validation:t06 — 無問題
  • npm run check:node-runtime — 符合最低支援執行環境要求(>=22.22.2 <23、>=24.0.0 <27,依據 src/shared/utils/nodeRuntimeSupport.ts 中的 SUPPORTED_NODE_RANGE;與 package.json 的 engines 一致)
  • npm run test:unit — 通過
  • npm run test:vitest — 通過(MCP 伺服器、autoCombo、快取)
  • npm run test:coverage — 滿足 60/60/60/60 門檻(陳述式/程式行/函式/分支)
  • npm run test:integration — 通過(若變更涉及 DB/處理常式)
  • npm run test:combo:matrix — 通過(組合策略矩陣:以確定性方式驗證全部 19 種公開路由策略的選擇決策;變更組合路由、策略解析或備援邏輯時執行)
  • RUN_COMBO_LIVE=1 npm run test:combo:live — 選用/手動(設有閘門的真實上游冒煙測試;從 VPS root@192.168.0.15 取得唯讀 DB 快照;呼叫真實提供者,會消耗點數;絕不在 CI 中執行;未啟用閘門時會正常略過)
  • npm run test:combo:live:vps — 選用/手動(第 3 階段 VPS 即時冒煙測試:透過純 Node ESM 對即時 .15 伺服器執行 7 個 HTTP 情境;需要 ssh root@192.168.0.15;僅建立/刪除 __live_test__* 組合;呼叫真實提供者;絕不在 CI 中執行)
  • npm run test:e2e — 通過(UI 變更)
  • npm run test:protocols:e2e — 通過(MCP/A2A 變更)
  • npm run test:ecosystem — 通過

Husky hook 位於 .husky/,並會在執行 git 操作時自動執行。

  • pre-commit: npx lint-staged + node scripts/check/check-docs-sync.mjs + npm run check:any-budget:t11
  • pre-push: 快速且具確定性的閘門 — npm run check:any-budget:t11 && npm run check:tracked-artifacts(於 2026-06-13 啟用)。刻意排除 test:unit(速度較慢;由 CI 的 test-unit 作業涵蓋)。
    • 推送發布分支前,請手動執行 npm run test:unit。

如果 hook 失敗:修正根本問題,不要使用 --no-verify 繞過。

所有納入發布版本的提交都必須遵循 type(scope): subject 格式。

有效類型: feat、fix、refactor、docs、test、chore、perf、style、ci

有效範圍: db、sse、oauth、dashboard、api、cli、docker、ci、mcp、a2a、memory、skills、cloud-agent、guardrails、compression、auto-combo、resilience、providers、executors、translator、domain、authz

破壞性變更:加入 BREAKING CHANGE: 頁尾,或在範圍後加上 !(例如 feat(api)!: drop /v0)。

  • npm run check:docs-sync 通過(由 pre-commit 自動執行)
  • npm run check:docs-all 通過(整合檢查:docs-sync + docs-counts + env-doc-sync + deprecated-versions + doc-links)
  • npm run check:env-doc-sync 以 0 結束 — 程式碼 ↔ .env.example ↔ docs/reference/ENVIRONMENT.md 的環境變數契約維持完整
  • npm run check:doc-links 以 0 結束 — 重構後沒有損壞的內部 markdown 參照
  • 已檢閱 docs/architecture/ARCHITECTURE.md 是否有儲存與執行環境偏差
  • 已檢閱 docs/guides/TROUBLESHOOTING.md 是否有環境變數與操作偏差
  • 如果 .env.example 有變更:已更新 docs/reference/ENVIRONMENT.md
  • 如果新功能具有 UI:docs/guides/USER_GUIDE.md 已提及該功能
  • 如果新功能具有 API:已更新 docs/reference/API_REFERENCE.md + docs/openapi.yaml
  • 如果新功能是模組:存在專用的 docs/<MODULE>.md
  • 如果是破壞性變更:docs/guides/TROUBLESHOOTING.md 包含遷移說明
  • npm run i18n:check 以 0 結束 — 翻譯狀態(.i18n-state.json)與來源文件同步(嚴格模式下沒有發生偏差的來源;最後一刻進行文件微調時,可接受警告模式的提示,但加上標籤前應為 0)
  • npm run i18n:check-ui-coverage 以 0 結束 — 每個 UI 語言地區都達到或超過 80% 的涵蓋率下限
  • npm run i18n:sync-ui:dry 回報全部 42 個語言地區均缺少 0 個鍵
  • 如果英文來源文件有變更,請在加上標籤前執行 npm run i18n:run(需要在 .env 中設定 OMNIROUTE_TRANSLATION_API_KEY)
  • 若翻譯貢獻屬於次要內容,可延後至下一個版本(在 CHANGELOG 中追蹤)
  • 如果 src/lib/db/migrations/ 中有新檔案:
    • 每個遷移皆具等冪性(CREATE TABLE IF NOT EXISTS 等)
    • 遷移包裝於交易中
    • 編號正確(序列中沒有缺號)
  • 在全新安裝環境中測試:刪除 ~/.omniroute/omniroute.db 並執行 npm run dev
  • 在既有安裝環境中測試:備份 DB、執行遷移並驗證綱要
  • 如果遷移會重寫資料表,須正確處理 WAL 檔案(-wal、-shm)
  • src/shared/constants/providers.ts Zod schema 在載入時有效
    • 所有提供者皆具備必要欄位(id、label、kind 等)
    • 已為新的免費提供者提供 freeNote
    • OAuth 提供者已在 src/lib/oauth/constants/oauth.ts 中註冊 oauthConfig
  • 若新增提供者:在 open-sse/executors/ 中新增對應的執行器
  • 若為非 OpenAI 格式:在 open-sse/translator/ 中新增轉譯器
  • 模型已在 open-sse/config/providerRegistry.ts 中註冊
  • tests/unit/ 中的單元測試涵蓋提供者分類與路由

若 electron/ 有變更:

  • npm run electron:smoke:packaged 通過
  • 已針對 :win、:mac、:linux 中至少一個進行建置測試
  • 程式碼簽署憑證尚未過期(若進行簽署)
  • electron/package.json 的版本與根目錄 package.json 相符
  • 若發行至 stable,已更新自動更新通道指標

儲存庫使用三個不同的輸出目錄——切勿混用:

目錄 用途 是否追蹤?
src/ 應用程式原始碼(TypeScript / TSX) 是
.build/ 建置中間產物——next build 輸出(distDir) 否(已由 git 忽略)
dist/ 可發布的 npm 套件組合——由 assembleStandalone 組裝 否(已由 git 忽略)

操作人員注意事項:遠端 VPS 映像目錄仍為 /usr/lib/node_modules/omniroute/app/。 僅儲存庫內的建置輸出已移動(app/ → dist/)。部署技能會透過 rsync 將 dist/ 的內容同步至遠端 app/ 目錄——無須變更 VPS 路徑。

單次建置流程:

npm run build:release
└─ rm -rf .build dist (清理)
└─ next build → .build/next/ (中間產物)
└─ assembleStandalone (將獨立版本 + 靜態檔案 + 公開檔案 + 原生模組複製至 dist/)
└─ writes dist/BUILD_SHA (HEAD 哨兵值)

部署時請勿先執行 npm run build,再另外執行 npm run build:cli——請使用 npm run build:release,它會以單一命令執行全新建置並寫入哨兵值。

  • npm run build:release 成功,且 dist/BUILD_SHA == git rev-parse --short HEAD
  • npm run check:pack-artifact 檢查結果乾淨——沒有 app.__qa_backup、scripts/scratch、package-lock.json 或其他本機殘留項目
  • 建置後 dist/server.js 存在
  • 執行 /generate-release-cc(Claude Code 技能):
    • 建立標籤 vX.Y.Z
    • 推送標籤與分支
    • 建立含變更記錄內容的 GitHub Release
    • 附加 Electron 安裝程式(若已建置)
  • 或手動執行:
    Terminal window
    git tag -a vX.Y.Z -m "Release vX.Y.Z"
    git push origin vX.Y.Z
    gh release create vX.Y.Z --notes-from-tag

部署技能使用輕量 rsync 流程——不使用 npm pack,也不使用 npm i -g:

  • 使用與目標相符的部署技能:
    • /deploy-vps-local-cc——本機 VPS(192.168.0.15)
    • /deploy-vps-akamai-cc——Akamai VPS(69.164.221.35)
    • /deploy-vps-both-cc——兩者
  • 部署前,確認 dist/BUILD_SHA == git rev-parse --short HEAD
  • 建置必須在具有實際 node_modules 的位置執行(主要簽出目錄或已執行 npm ci 的工作樹——不得使用符號連結的工作樹)
  • 對已部署的執行個體進行煙霧測試:
    • 開啟 /dashboard/health → 檢查版本字串是否與發行版本相符
    • 對已知提供者執行一次 /v1/chat/completions 請求
    • 確認 /api/monitoring/health 傳回 CLOSED 斷路器
    • 確認 MCP 傳輸端點有回應(/mcp HTTP、/mcp-sse SSE)
  • 執行 /capture-release-evidences-cc(Claude Code 技能)
    • 擷取新功能的 WebP 螢幕截圖/錄影
    • 附加至發行說明/部落格文章
  • 在 GitHub Discussions/Discord 發布發行公告
  • 為下一個版本建立里程碑
  • 若屬重大事項:置頂討論,或在 news.json 中發布應用程式內橫幅

Radar 公告刻意以 active: false 提交。只有在以下每個項目皆有證據後, 才另行進行啟用變更:

  • 所有堆疊式 Radar PR 均已合併,且發行端點的 CI 狀態為綠色
  • 在 RADAR_ENABLED 預設仍關閉的情況下,部署 OSS Radar 路由並進行煙霧測試
  • 在指定的 Radar 主機上,對 GET /planos、/termos、/privacidade 及 /reembolso 進行煙霧測試
  • 在私有服務中記錄操作人員的身分/聯絡方式/地址,以及經擁有者核准的法律審查
  • 僅在測試模式下測試 Stripe Checkout 與已簽署的 webhook
  • 使用已核准的寄件者/網域測試一次加密的交易型電子郵件傳送
  • 驗證備份還原,並執行一次有人監督且設有預算上限的研究作業
  • 在接受捐款證明前,核准 BRL/PIX 審查政策
  • 僅在上述關卡皆通過後啟用公開 Checkout,接著啟用新的 news.json ID
  • 確認首頁橫幅使用本地化文案,且在較舊的 ID 被關閉後,新 ID 會重新出現

在發布任何包含內嵌服務變更的版本前,請確認:

全新資料庫啟動(可發現遷移衝突——於 v3.8.4 hotfix 後新增)

Section titled “全新資料庫啟動(可發現遷移衝突——於 v3.8.4 hotfix 後新增)”
  • DATA_DIR=$(mktemp -d) npm start & — 等待 10 秒啟動
  • curl -s http://127.0.0.1:20128/api/services/9router/status | jq '.tool' 回傳 "9router"(不是 404,不是 500)。確認遷移 071_services.sql 已套用且已寫入種子資料列。
  • sqlite3 $DATA_DIR/storage.sqlite "PRAGMA table_info(version_manager);" | grep -E "provider_expose|logs_buffer_path|last_sync_at" 回傳 3 列。
  • sqlite3 $DATA_DIR/storage.sqlite "PRAGMA table_info(webhooks);" | grep -E "kind|metadata_encrypted" 回傳 2 列(驗證 070_webhooks_kind_metadata.sql 已套用)。
  • node --import tsx/esm --test tests/unit/db/no-migration-collisions.test.ts 通過——防止未來的衝突。
  • POST /api/services/9router/install 在 2 分鐘內回傳 200 並包含 installedVersion
  • POST /api/services/9router/start 在 30 秒內回傳 200 且 state: "running"
  • GET /api/services/9router/status 回報 health: "healthy"
  • POST /v1/chat/completions 搭配 "model": "9router/auto/..." 回傳 200(端到端透過 9Router 路由)
  • GET /dashboard/providers/services/9router/embed/dashboard 在代理程式內渲染 9Router 原生 UI(非直接 127.0.0.1:port iframe)
  • POST /api/services/9router/rotate-key 回傳 { keyRotated: true } 且服務正常重啟
  • POST /api/services/9router/stop 回傳 200 且 state: "stopped"
  • GET /api/services/9router/logs?tail=50 回傳 SSE 串流,包含 snapshot 事件與最近的行
  • 在 PATH 中沒有 npm 的環境中安裝,回傳 500 並顯示友善(非堆疊追蹤)的錯誤訊息
  • POST /api/services/cliproxy/install 在 2 分鐘內回傳 200
  • POST /api/services/cliproxy/start 在 30 秒內回傳 200 且 state: "running"
  • GET /api/services/cliproxy/status 回報 health: "healthy"
  • POST /api/services/cliproxy/stop 回傳 200 且 state: "stopped"
  • GET /api/services/cliproxy/logs?tail=50 回傳 SSE 串流
  • curl -H "X-Forwarded-For: 1.2.3.4" http://localhost:20128/api/services/9router/start 回傳 403 LOCAL_ONLY
  • curl -H "X-Forwarded-For: 1.2.3.4" http://localhost:20128/api/services/cliproxy/start 回傳 403 LOCAL_ONLY
  • /api/services/* 的錯誤回應不包含 err.stack 或絕對路徑

在發布任何 v3.8.x 版本前,請確認以下額外項目:

  • omniroute --tray 在 macOS 上啟動(systray2 已安裝到 ~/.omniroute/runtime/)
  • omniroute --tray 在 Linux 上啟動(需要 DISPLAY;若未設定則優雅報錯)
  • omniroute --tray 在 Windows 上啟動(PowerShell NotifyIcon,無需額外二進位檔)
  • omniroute config tray enable 建立開機自啟項目;disable 則移除
  • npm install -g omniroute@<此版本> 執行 postinstall 而不會致命退出
  • 更新路徑保留選擇性依賴:omniroute update --apply 和自動更新器 執行 npm install -g … --include=optional,因此 optionalDependencies(better-sqlite3、 keytar、tls-client,以及 llmlingua SLM 堆疊:@atjsh/llmlingua-2@2.0.5、 js-tiktoken)在更新後仍會保留。Ultra modelPath SLM 層還需要 tinybert 模型,會在首次使用時自動下載到 ${DATA_DIR}/models/llmlingua。Postinstall (scripts/build/colocateOptionals.mjs)接著將 SLM 選擇性閉包複製到 dist/node_modules,使工作者解析到單一 @huggingface/transformers ^4.2.0 實例——獨立追蹤僅捆綁 transformers,而非動態匯入的 選擇性套件,因此若無此步驟,工作者會載入 llmlingua-2 並使用根目錄的 transformers, 導致 SLM 層靜默地失敗但仍保持運作。
  • omniroute status 在無 .env 的情況下正常運作(僅限 CLI 權杖路徑,迴環介面)
  • curl http://localhost:20128/api/shutdown 回傳 401(始終受保護的路由)
  • curl -H "host: evil.com" http://localhost:20128/api/mcp/sse 回傳 401(迴環保護)
  • SQLite 執行時期在首次執行時解析為 bundled(捆綁的二進位檔對平台有效)
  • 當 node_modules/better-sqlite3 被刪除時,SQLite 執行時期備援至 runtime
  • Smart MCP 過濾器壓縮真實的 playwright-mcp browser_snapshot 輸出(≥50% 縮減)
  • 所有 10 個 skills/omniroute*/SKILL.md 檔案均可透過原始 GitHub URL 公開獲取
  • 入門精靈在新安裝時顯示「運作方式」分層導覽步驟
  • 首頁儀表板的分層覆蓋率小工具顯示已設定/啟用中的計數

若發行版本有重大問題:

  1. gh release edit vX.Y.Z --prerelease(標記為非最新)
  2. git tag -d vX.Y.Z && git push --delete origin vX.Y.Z(僅在使用者尚未採用時)
  3. 或者:在 release/vX.Y.0 上進行 hotfix → 修補版本 vX.Y.(Z+1)
  4. 立即在 GitHub Discussions 和 Discord 中溝通
  • 絕不直接提交到 main
  • 絕不對 main 或 release/* 分支使用 git push --force
  • 絕不跳過 Husky hooks(--no-verify)
  • 絕不提交機密、憑證或 .env 檔案
  • 覆蓋率必須維持 ≥60/60/60/60(statements/lines/functions/branches)
  • 在變更 src/、open-sse/、electron/ 或 bin/ 中的正式程式碼時,務必包含或更新測試

在開啟 PR 前在本機執行文件同步檢查:

Terminal window
npm run check:docs-sync

CI 也會在 .github/workflows/ci.yml(lint 工作)中執行此檢查。


OmniRoute 原始碼 (a58000c7685f)

HagiCode

HagiCode 是智慧代理程式開發工作台,結合結構化工作流程、多代理程式執行與 Hero Dungeon 介面,將想法化為交付成果。

以更聰明、更快速且更有趣的智慧代理程式工作流程,打造實用的軟體。

HagiCode 淺色主題介面畫面
  • Smart結構化流程將意圖轉化為從構想到交付的可執行步驟。
  • Efficient多代理程式工作流程讓研究、實作與審查並行進行。
  • FunHero Dungeon 讓長時間的程式協作更直覺、更有參與感。
造訪 HagiCode