Files
claude-pet/lib/paths.js
T
JianMiauandClaude Fable 5 e591475d4c 加上免安裝版,寵物來源改成執行目錄的 pets
摘要:
新增 portable 單檔與 zip 資料夾兩種免安裝產物;寵物一律從執行目錄的 pets/ 掃,設定檔不再累積程式自己算出來的路徑。

根本原因:
1. 只有 NSIS 安裝檔,沒有點兩下就能跑的版本。
2. 內附寵物被 asarUnpack 埋在 resources/app.asar.unpacked/pets,使用者要新增寵物得先鑽進 resources 資料夾。
3. loadConfig 會把算出來的來源路徑寫回 config.json,程式一搬家或在安裝版與 portable 之間切換,petSources 就越積越多失效的絕對路徑(實際已累積出 dist/win-unpacked/resources/app.asar.unpacked/pets 這種殘留)。
4. CODEX_PETS_DIR 用到 HOME,但 const HOME 宣告在它下面,會在啟動時就 TDZ ReferenceError。

影響:
沒有免安裝選項;新增寵物的路徑不直覺;設定檔會長出一堆死路徑;且上一版打包後的程式其實一啟動就會崩潰。

修法:
- win target 加上 portable 與 zip;portable 設 unpackDirName=ClaudePet、requestExecutionLevel=user。
- pets/ 改用 extraFiles 放到 exe 旁邊(不再進 asar),APP_ROOT 打包後取 process.execPath 的目錄。
- portable 的 NSIS 外殼每次啟動都重解壓、結束就刪整個目錄,因此:hook 腳本另外複製到 ~/.claude-pet/hook/ 並註冊該穩定路徑(否則寵物沒開時 Claude Code 每次觸發 hook 都找不到檔案);使用者寵物放那顆 exe 旁邊;開機自動啟動改用 PORTABLE_EXECUTABLE_FILE。
- petSources 語意改為「只存使用者自己加的額外路徑」;執行目錄的 pets 與 ~/.codex/pets 為隱含來源,由 petSearchDirs() 組出實際掃描清單,載入時剔除隱含項與不存在的路徑。同 id 以使用者自己放的優先。
- 把 HOME/CONFIG_DIR 移到常數區最前面,修掉 TDZ。
- 內附第二隻寵物 xiao-nian-realistic。

驗證:
以 ELECTRON_RUN_AS_NODE 執行打包後的 exe(不開視窗):
- 一般模式與模擬 portable 模式下的 pets 路徑、hook 路徑、autostart 指令皆正確。
- 用假的 USERPROFILE 實跑 install/uninstall:hook 腳本確實複製、指令含空白路徑會加引號、其他人的 Stop/PreToolUse hook 與 model 設定在安裝與移除後都完整保留、備份有產生。
- 帶殘留路徑的設定檔會被正確清理,掃描順序為「使用者 pets → 內附 pets → ~/.codex/pets → 額外路徑」。
- 從 app.asar 讀回 main.js 確認出貨的程式碼順序正確。
- 以純 node 載入 main.js,確認常數區與 loadConfig 不再有 TDZ。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 14:11:20 +08:00

36 lines
1.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use strict";
// 開發時直接跑資料夾;打包後程式碼會在 resources/app.asar 裡面。
// 有些東西不能待在 asar 內:
// - hook/claude-pet-hook.jsClaude Code 會用 `node <路徑>` 執行它,node 讀不到 asar 內的檔案
// - pets/:使用者要能自己丟寵物進去,選單也要能開這個資料夾
// 這兩個在 build 設定裡以 asarUnpack 解開到 resources/app.asar.unpacked,路徑要跟著換過去。
const path = require("node:path");
const PACKED = `${path.sep}app.asar${path.sep}`;
const UNPACKED = `${path.sep}app.asar.unpacked${path.sep}`;
function unpacked(p) {
return p.includes(PACKED) ? p.replace(PACKED, UNPACKED) : p;
}
// 在 Electron 裡跑,而且不是 `electron .` 的開發模式(開發模式 process.defaultApp 為 true
function isPackaged() {
return Boolean(process.versions.electron) && !process.defaultApp;
}
// portable 單檔版:NSIS 外殼每次啟動都把整包解到 %TEMP%,程式結束後又整個刪掉,
// 所以「程式本身的位置」是暫時的,只有這兩個環境變數指得到那顆 exe 真正待的地方。
function portableExe() {
return process.env.PORTABLE_EXECUTABLE_FILE || null;
}
function portableDir() {
return process.env.PORTABLE_EXECUTABLE_DIR || null;
}
function isPortable() {
return Boolean(portableExe());
}
module.exports = { unpacked, isPackaged, portableExe, portableDir, isPortable };