老實說,一開始我覺得範例專案原本的架構就夠用了:runner、manifest、正文、被拍的 Demo App 全部放在同一個 repo,指令也都是 npm run manual 這種只在範例專案裡才有意義的寫法,反正能跑就好。
但從 i18n 名稱比對、多語同步,一路做到影片與 App 內導覽,中間改了不少東西,很多「只有 Demo App 才成立」的假設也跟著越積越多。後來再想了想,既然最終目標是讓別的產品也能用這條產線,最自然的形式就是包成一個 npm package,讓別人 npm install 就能用。要做到這件事,原本的架構就得調整。
所以最後這組番外篇來處理發布。今天先把工具從專案裡抽出來,變成一個 CLI:auto-manual-gen;接下來兩天,再把「怎麼用它」的知識打包成 Claude Code plugin。
這篇同時也是一份使用說明。如果你是直接跳到這一篇,搭配範例專案應該就能知道這條產線能做什麼、該怎麼用,細節則可以回頭翻對應的那一天。
要包成套件,原本的架構有幾個地方過不去:
| 問題 | 重構後 |
|---|---|
所有路徑都以 runner 這支檔案為基準,一旦被裝進 node_modules/,就會在錯的資料夾裡找 manifest |
使用者的檔案從目前目錄往上找 manual.yaml;工具自己附帶的檔案 (腳本、樣式、schema) 則以套件位置為基準 |
跟產品有關的東西散在程式碼與 config.json 裡,有些甚至寫死成 Demo App 的檔名 |
全部集中到 manual.yaml,套件的程式碼裡不再出現任何 Demo App 的檔名 |
| 怎麼啟動 App 是寫死的 | 沿用 Day 07 的 AppDriver,內建 Electron 與 Web,其他情況讓使用者自己寫 driver |
失敗一律 process.exit(1),CI 與 agent 分不出是誰的問題 |
exit code 分成內容、用法、環境三種,每個指令都支援 --json |
| Word 轉 PDF、TTS 只能在 Windows 上跑,發布後就會變成「在 macOS 上壞掉」的 issue | 當成選用能力,缺了只在用到時失敗,由 doctor 回報 |
重構後的範例專案還是同一個 repo,但裡面分成了兩部分:
auto-manual-gen/
├── packages/auto-manual-gen/ # 產線本體,就是發布到 npm 的那個套件
├── manual.yaml # ← 以下是「一個使用 auto-manual-gen 的手冊專案」
├── manifest/ docs/ agent/ templates/
└── apps/demo-stream-app/ # 被拍的 Demo App
範例專案透過 npm workspace 依賴 auto-manual-gen,用法跟別人 npm install -D auto-manual-gen 完全一樣,原本的 npm run manual 也還在,只是現在轉給的是 auto-manual-gen run。
要特別說明的是,Demo App 依然留在 repo 裡,沒有拆出去。這純粹是為了 demo 方便:clone 下來就有東西可以拍,不用另外準備一個 App。實際用在自己的產品上時,結構會剛好反過來,下一節會看到。
假設你手上已經有一個產品 (Web 或 Electron),想幫它做一本手冊,該怎麼做?
讓我們先看一下整體是怎麼運作的,安裝的部分先跳過,後面再說明。
這條產線裡有三個角色,各自負責不同的事:
整個流程如下:

有幾個地方要特別說明:
data-testid。這條產線的每一步都靠 testid 定位,CLI 沒辦法替你的 App 加上去。不過不需要一開始就全部補齊,第 3 步寫到哪一章,probe 發現缺了哪個,agent 再補哪個就好。因為這是在改產品程式碼,第 4 步一定要經過 review。run 成功不代表拍對了。它只保證流程跑得通,畫面對不對、框有沒有框在對的元件上、有沒有拍到敏感資料,都要人看過。比起逐行讀 manifest,把時間花在截圖與正文上更值得,格式上的錯誤 validate 已經擋掉大部分了。run 會失敗,--json 的錯誤裡已經附上候選的 testid,agent 拿它去修,人只要 review 那個 PR。手冊專案建議直接放在產品 repo 的子目錄 (e.g. manual/)。manifest 依賴的是產品的 testid,UI 跟 manifest 放在一起,才能在同一個 PR 裡一起改、一起在 CI 驗證,不會等到下次有人跑手冊才發現壞掉:
my-electron-app/
├── package.json # devDependencies 加上 auto-manual-gen、playwright
├── src/ ... # 產品本身,元件上有 data-testid
└── manual/ # 手冊專案,manual.yaml 在哪,根目錄就在哪
├── manual.yaml # 專案共用的設定,進版控
├── config.json # 個人設定,不進版控
├── manifest/ # 操作步驟 (agent 寫、人 review)
├── docs/ # 正文 (agent 寫、人 review)
└── screenshots/ output/ # CLI 產出,不進版控
跟範例專案剛好相反:範例專案是手冊專案在最外層、App 在 apps/ 底下;真實產品則是 App 在最外層,手冊專案縮進子目錄。
CLI 是從目前目錄往上找
manual.yaml,所以指令要在manual/裡執行。可以在產品的package.json包一層"manual": "cd manual && auto-manual-gen",之後在根目錄用npm run manual -- run就好。
manual.yaml:跟產品有關的都在這裡manual.yaml 原本就存在 (Day 14 的 profile 與 bootstrap),現在它多了一個身分:它在哪裡,手冊專案的根目錄就在哪裡。以上面的結構為例,大概會長這樣:
# yaml-language-server: $schema=../node_modules/auto-manual-gen/schema/v1/manual.json
profile: my-electron-app
title: { zh-Hant: MyApp 使用手冊, en: MyApp User Manual }
version: 'v1.0.0'
locales: [zh-Hant, en]
bootstrap:
viewport: { width: 1600, height: 900, deviceScaleFactor: 2 }
localeKey: locale # App 從哪個 localStorage key 讀語言
ready: app-root # 這個 testid 出現才算開機完成
clock: '2025-09-01T09:00:00'
disableAnimations: true
app:
mode: electron
electron: { projectDir: .., build: npm run build }
text:
messages: ../src/renderer/locales/{locale}.json
tour:
output: ../src/renderer/help/tours.json
所有路徑都以 manual.yaml 所在的目錄為基準。config.json 則是一人一份,只能覆寫 app,例如自己機器上的 dev server 剛好開在別的 port。
如果 App 的啟動方式比較特別 (e.g. 要先登入 SSO、要先用 docker compose 把後端跑起來),可以改用 mode: custom,指向自己寫的 driver:
app:
mode: custom
custom: { driver: ./driver.mjs }
driver 模組只要 default export 一個回傳 AppDriver 的函式就好,套件也有匯出內建的 WebDriver、ElectronDriver,可以包一層再用。
開頭那行 yaml-language-server 指向套件裡附帶的 schema (路徑相對於這個檔案,manual/ 往上一層才是 node_modules/),有裝 YAML 擴充套件的 VS Code 就會即時補全、把錯的欄位標紅;manifest 也一樣,換成 schema/v1/manifest.json 就好。validate 用的是同一份 schema,不會有「編輯器說對、validate 說錯」的情況。
用到的就是這個系列一路做過來的那些事,只是現在每一件都是一個指令:
| 指令 | 做什麼 | 詳見 |
|---|---|---|
probe |
列出畫面上可見且有 data-testid 的元件,寫 manifest 前先探勘 |
Day 16–17 |
validate |
不開瀏覽器,驗證 manifest 與正文 (引用、保護區、名稱出處) | Day 16、19 |
run |
依 manifest 驅動 App、截圖、畫框標號;一章一次開機,可以只重跑一章 | Day 08–15 |
build |
合併正文與截圖,產出 Word / HTML / PDF | Day 20–21 |
sync |
主語言改了哪幾段、譯文要重翻哪幾段 | Day 22–23 |
video |
同一份 manifest 錄成附字幕、旁白的教學影片 | Day 24–25 |
tour |
同一份 manifest 轉成 App 內導覽 | Day 26 |
init / doctor |
建立骨架 / 檢查環境 | 下一節 |
每個欄位、每個動詞的說明都整理在套件的 README,那份文件明天也會直接變成 agent 的上下文。
agent 光靠 README 與
--help就能呼叫這些指令;但要寫出好的手冊,還需要工作流程、寫作規範與產品知識,這些 README 裡沒有。怎麼把它們打包給 agent,是明天 plugin 的主題。
第一次導入時,先在產品 repo 裡建立 manual/,接著在 App 跑起來的狀態下:
npm install -D auto-manual-gen playwright
npx playwright install chromium
npx auto-manual-gen init --url http://localhost:5173
npx auto-manual-gen run
這裡假設套件已經在 registry 上;如果同事給你的是打包好的
.tgz,把auto-manual-gen換成檔案路徑就好,最後一節會說明。
init 會在目前的目錄產生一份最小可跑的骨架:manual.yaml、config.example.json、一章只截首頁一張圖的 manifest/10-overview.yaml 與對應的正文,並把 screenshots/、output/、*.webm、*.mp4 補進 .gitignore。接著跑 run,就能拿到 screenshots/zh-Hant/overview-01.png。
如果要拍的是 Electron,改用 --mode electron,並用 --app-dir 指向 App 的目錄 (有 package.json 與 main 的那一層):
npx auto-manual-gen init --mode electron --app-dir ..
產生的 manual.yaml 會是 projectDir: ..,並預設在開機前先跑一次 npm run build,手冊要拍的是打包後的樣子。
如果跑不起來,或是換到同事的電腦上,可以先跑一次 npx auto-manual-gen doctor。它會列出 Node、Playwright、Chromium 這些必要的東西有沒有裝好,以及 pandoc、ffmpeg 這類選用工具缺了哪些、會影響哪個指令。
注意
init不會產生UI-MAP.md、QUIRKS.md。那些是產品本身的知識,沒辦法事先寫好,也就是流程第 2 步要人補上的部分,明天會再提到。
前面的安裝指令,都假設 npm install auto-manual-gen 裝得到東西。但這條產線不一定要上架到公開的 npm,更常見的情況是:在公司裡做好了,想 甩鍋 交接給別人,或是讓別人也可以自己使用。
在套件的目錄裡先編譯,再打包:
cd packages/auto-manual-gen
npm run build
npm pack
npm pack 會產出一個 auto-manual-gen-0.1.0.tgz,這就是 npm publish 實際上傳的那個檔案。不管最後要不要上架,打包出來的東西都是同一份。
方法一:直接給 .tgz。最簡單,不需要任何基礎設施。建議把檔案放進產品 repo (e.g. vendor/),再從路徑安裝:
npm install -D ./vendor/auto-manual-gen-0.1.0.tgz playwright
package.json 會記成 "auto-manual-gen": "file:vendor/auto-manual-gen-0.1.0.tgz"。檔案跟著 repo 走,其他同事 clone 下來 npm install 就有了;如果把 .tgz 放在自己電腦或共用槽上,別人的 npm install 就會因為找不到檔案而失敗。
缺點是更新要靠人:出了新版,就得換掉 .tgz、改路徑,再請大家重新安裝。
方法二:發布到公司內部的 npm registry。如果有兩個以上的產品在用,或是會持續更新,就值得放上 registry。Verdaccio、Azure Artifacts 都能當內部 registry (GitHub Packages、GitLab 也可以,但套件名稱要改成有 scope 的 @your-org/auto-manual-gen,.npmrc 也要改成只把這個 scope 指過去)。發布的人:
npm login --registry https://npm.example.internal/
npm publish --registry https://npm.example.internal/
使用的產品 repo 加一個 .npmrc,指向公司的 registry (內部 registry 通常會代理公開的 npm,其他套件照樣裝得到):
registry=https://npm.example.internal/
之後就跟前面一樣,npm install -D auto-manual-gen playwright 就好,更新也只要 npm update auto-manual-gen。不過要注意,npm update 只會在 package.json 記錄的版本範圍內升級:現在的版本是 0.1.0,記下來的範圍是 ^0.1.0,只涵蓋 0.1.x。出了 0.2.0,就要明確指定 npm install -D auto-manual-gen@0.2.0。
至於要不要上架到公開的 npm,我的建議是在公司內部就好XD
不管是哪一種,只要有人依賴這個套件,就要清楚哪些東西改了會讓別人壞掉:CLI 的指令與參數、
manual.yaml與 manifest 的 schema。這些有不相容的變更,就升主版號;還在0.x的時候,慣例是改升 minor (0.1→0.2),這也是為什麼npm update不會自動跨過去。
今天把產線從範例專案裡抽了出來,變成 auto-manual-gen 這個 CLI:
manual.yaml,它在哪裡,手冊專案的根目錄就在哪裡。manual/ 子目錄;CLI 負責做,agent 負責寫,人負責決定與確認。npm pack 打包後,可以直接給同事 .tgz,或發布到公司內部的 registry。CLI 準備好了,人跟 CI 都能用。明天處理最後一種使用者:AI agent,把「怎麼用這套工具」打包成 Claude Code plugin。