用 electron-builder 打包成 Windows exe

摘要:
加上 electron-builder 設定,`npm run dist` 產出 NSIS 安裝檔與免安裝版,並修正打包後才會出現的路徑問題。

根本原因:
原本三處路徑都假設程式是攤在資料夾裡跑的,打包成 asar 後會壞:
1. hook 腳本路徑會落在 app.asar 內,而 Claude Code 是用 `node <路徑>` 執行它,node 讀不到 asar 裡的檔案,hook 會直接失敗。
2. pets 資料夾同樣在 asar 內,使用者無法自己丟寵物進去,選單「開啟寵物資料夾」也開不起來。
3. 開機自動啟動寫入的是 `electron.exe + 專案路徑`,打包後沒有 node_modules,登錄值會指向不存在的檔案。

影響:
沒有可散佈的執行檔;直接打包的話 hook、換寵物、開機啟動三個功能都會壞掉。

修法:
- 新增 lib/paths.js:unpacked() 把 app.asar 換成 app.asar.unpacked,isPackaged() 以 process.defaultApp 判斷是否為打包版。
- build.asarUnpack 把 hook/ 與 pets/ 解到 asar 外,hooks-installer 與 main.js 的 PETS_DIR 都改走 unpacked()。
- autostart 打包後改用 process.execPath,並跳過開發版才需要的 electron.exe 存在檢查。
- NSIS 設為 per-user、可改安裝路徑、建立桌面與開始選單捷徑,解除安裝不刪 ~/.claude-pet。
- 新增 build/icon.ico(16–256,七種尺寸),取自小念 spritesheet 第 0 列第 6 欄的頭肩方形裁切。
- dist/ 加入 .gitignore;README 補上「打包成 exe」一節與安裝檔的使用方式。

驗證:
以 ELECTRON_RUN_AS_NODE 執行打包後的 exe(不開視窗)載入打包內的 lib,確認 isPackaged 為 true、hook 路徑指到 app.asar.unpacked 且檔案存在、autostart 指到 exe 本身、pets 掃得到 xiao-nian、renderer 讀得到 asar 內的 index.html;另確認 exe 版本資訊與七種尺寸圖示皆已嵌入。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-21 11:03:11 +08:00
co-authored by Claude Fable 5
parent a014f9a279
commit 56fd8448ba
9 changed files with 3545 additions and 10 deletions
+37 -2
View File
@@ -21,6 +21,7 @@
- [設定檔](#設定檔)
- [架構與檔案](#架構與檔案)
- [HTTP API](#http-api)
- [打包成 exe](#打包成-exe)
- [疑難排解](#疑難排解)
- [移除](#移除)
@@ -50,6 +51,12 @@
## 快速開始
### 用安裝檔(一般使用)
執行 `dist\Claude Pet-<版本>-setup.exe`(見[打包成 exe](#打包成-exe)),裝在 `%LOCALAPPDATA%\Programs\Claude Pet`,不需要系統管理員權限。裝完從開始選單開啟,再用系統匣選單的 **Claude Code hooks → 安裝** 接上 Claude Code。
### 從原始碼跑(開發)
```powershell
cd E:\Project\Test\AI\Claude\claude-pet
npm install
@@ -200,10 +207,12 @@ Claude Code ──hookstdin JSON)──▶ hook/claude-pet-hook.js ──PO
| `renderer/index.html``style.css` | 版面與氣泡樣式(CSP 僅允許 self / data: |
| `hook/claude-pet-hook.js` | Claude Code hook 端:讀 stdin → 擷取欄位 → POST800 ms 逾時、永遠 exit 0 |
| `lib/hooks-installer.js` | 安全地合併 / 移除 `~/.claude/settings.json` 的 hooks(保留其他設定與其他 hooks,先備份) |
| `lib/autostart.js` | `HKCU\Software\Microsoft\Windows\CurrentVersion\Run\ClaudePet` 登錄值 |
| `lib/autostart.js` | `HKCU\Software\Microsoft\Windows\CurrentVersion\Run\ClaudePet` 登錄值;開發時指向 `electron.exe + 專案路徑`,打包後直接指向那顆 exe |
| `lib/paths.js` | 開發/打包兩種情境的路徑解析(`app.asar``app.asar.unpacked`、是否為打包版) |
| `scripts/*.js` | 上述兩者的 CLI 包裝 |
| `pets/` | 內附寵物 |
| `docs/` | README 用圖 |
| `build/icon.ico` | exe 與安裝檔的圖示,取自小念 spritesheet 第 0 列第 6 欄(中立正面)的頭肩方形裁切 |
設計重點:
@@ -257,6 +266,30 @@ curl http://127.0.0.1:17333/state
也可以送 `{"event":"__test","anim":"waiting"}``idle|running|waiting|review|failed|jumping|waving|clear`)直接指定動畫,與選單「動作測試」相同。
## 打包成 exe
```powershell
npm run dist # 安裝檔 + 免安裝版
npm run pack # 只產免安裝版,快很多,開發時驗證用
```
產物在 `dist\`
| 檔案 | 說明 |
|---|---|
| `Claude Pet-<版本>-setup.exe` | NSIS 安裝檔(約 100 MB)。per-user 安裝、不需要系統管理員權限,預設裝到 `%LOCALAPPDATA%\Programs\Claude Pet`,可自選路徑,會建立桌面與開始選單捷徑 |
| `win-unpacked\Claude Pet.exe` | 免安裝版,整個資料夾複製走就能直接執行 |
第一次建置時 electron-builder 會從 GitHub 抓 NSIS 與相關工具到 `%LOCALAPPDATA%\electron-builder\Cache`,需要網路,之後就會走快取。
**打包後和原始碼跑有三個地方不一樣**(都已經處理好,改程式時要留意):
- **`hook/``pets/` 不放進 asar**`build.asarUnpack`)。前者是因為 Claude Code 用 `node <路徑>` 執行 hook,而 node 讀不到 asar 裡的檔案;後者是因為使用者要能自己丟寵物進去、選單「開啟寵物資料夾」也要打得開。程式裡由 `lib/paths.js``unpacked()``app.asar` 換成 `app.asar.unpacked`
- **開機自動啟動**寫入的指令是那顆 exe 本身(`process.execPath`),不再是 `electron.exe + 專案路徑`。判斷方式是 `lib/paths.js``isPackaged()`
- **hook 指令仍然需要 `node` 在 PATH 裡**。安裝路徑含空白(`Claude Pet`)時會自動加引號。
換圖示就換掉 `build/icon.ico`(要含 256×256)。目前這顆是從 `pets/xiao-nian/spritesheet.webp` 第 0 列第 6 欄(中立正面)取頭肩方形裁切產生的。
## 疑難排解
### Electron 裝完沒有 `electron.exe`
@@ -290,12 +323,14 @@ npm config set allow-scripts=@anthropic-ai/claude-code,electron --location=user
## 移除
先在系統匣選單關掉 **開機自動啟動**、並用 **Claude Code hooks → 移除** 拆掉 hooks,然後結束程式。從原始碼跑的話也可以下指令:
```powershell
npm run hooks:uninstall # 從 ~/.claude/settings.json 移除所有 Claude Pet hook(先備份)
npm run autostart:uninstall # 移除開機啟動登錄值
```
後刪掉專案資料夾與 `%USERPROFILE%\.claude-pet\` 即可。
裝過安裝檔的話,到「設定 → 應用程式 → 已安裝的應用程式」移除 **Claude Pet**(解除安裝不會動到 `%USERPROFILE%\.claude-pet\`)。最後刪掉專案資料夾與 `%USERPROFILE%\.claude-pet\` 即可。
---