v0.15.7:改名 Arcrun.app+發 DMG(拖進 Applications)+MSIX 正式身分

leo 08-04:「如果當初 mac 打包就是 dmg 用拖的,現在 oscar 那裡就解決了,
如果當初 msix 就用了,現在另一個人也是更新就可以」——遠慮該在第一版就有。
原則:**用戶好用、白癡化**。

① 改名 Arcrun RAG.app → Arcrun.app(leo:「不要 rag,要 arcrun.app」)
   五處引用一起改(selfupdate.go/build-mac.sh/build-dmg.sh/t184_test.go/README)

② 新增 build-dmg.sh:DMG 內含 Arcrun.app + Applications 捷徑
   =Mac 幾十年的標準做法,開起來就暗示你拖進去 ⇒ **從源頭讓 app 待在對的位置**。
   坑:hdiutil 預設檔案系統會把「Arcrun RAG.app」截成「RAG.app」⇒ 加 -fs HFS+ 解。
   DMG 治源頭、t184 是安全網,兩個都要(已裝在別處的人不會因改發 DMG 就自動變好)。

③ MSIX 用 .env 的正式 Partner Center 身分重打(**不是佔位值**)
   回讀 AppxManifest 逐欄驗證:
     Identity Name        Uncle6.Arcrun
     Publisher            CN=DE038286-31A5-47CF-B83F-FF6B206BF591
     PublisherDisplayName Uncle6
     Version              0.15.7.0
     仍含 PLACEHOLDER      False

實測(t184 端到端,模擬 Oscar 的情境):
  app 放 /tmp/oscar-test/Downloads/(不在 /Applications)→ 跑更新覆蓋
  → 該處 app 變成 v0.15.7 
  → /Applications 沒有被無中生有一個副本 
  路徑推導三種放置位置皆正確(Downloads/Applications/Desktop)

產物 sha256:
  dmg  0eb3f76b60bf6891   mac zip f264dda7391f3006
  win  32fe44450ca77c62   msix    5bf7c911b8f3a817

 誠實標記:MSIX 能否實際安裝**這台 Mac 驗不到**(Add-AppxPackage 只有 Windows)。
   已驗的是包結構合法(unpack 過 blockmap 雜湊)+身分欄位正確。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-04 18:12:53 +08:00
parent 0021c274e8
commit 9fcd82b517
6 changed files with 64 additions and 18 deletions
+7 -7
View File
@@ -255,7 +255,7 @@ func startUpdateWatcher() {
// applyStagedAndRestart 套用已備妥的更新並重啟。
// 只有使用者按下「重新啟動以完成更新」才會走到這裡(不偷偷替換正在跑的自己)。
//
// 做法:解壓到暫存 → 用 ditto 覆蓋 /Applications/Arcrun RAG.app → 重新 open → 結束自己。
// 做法:解壓到暫存 → 用 ditto 覆蓋 /Applications/Arcrun.app → 重新 open → 結束自己。
// 失敗時保留原版不動(寧可停在舊版,也不要弄出開不起來的 .app)。
func applyStagedAndRestart() error {
s := loadStaged()
@@ -277,15 +277,15 @@ func applyStagedAndRestart() error {
if out, err := runCmd("ditto", "-x", "-k", s.ZipPath, work); err != nil {
return fmt.Errorf("解壓失敗:%v %s", err, out)
}
newApp := filepath.Join(work, "Arcrun RAG.app")
newApp := filepath.Join(work, "Arcrun.app")
if _, err := os.Stat(newApp); err != nil {
return fmt.Errorf("更新檔內容不符(找不到 Arcrun RAG.app")
return fmt.Errorf("更新檔內容不符(找不到 Arcrun.app")
}
// 🔴 t184leo 08-04 實撞:Oscar 按更新→顯示「新版 v0.15.6 已就緒」→重啟後**又跳回 v0.15.4**):
//
// 原本寫死 `/Applications/Arcrun RAG.app`。但使用者**不一定把 app 放在 Applications**
// 原本寫死 `/Applications/Arcrun.app`。但使用者**不一定把 app 放在 Applications**
// (Oscar 就是從下載資料夾/桌面直接跑)。這時 `ditto` 會**自動建出**
// `/Applications/Arcrun RAG.app` 並**回傳成功**(實測 exit 0,不是報錯)
// `/Applications/Arcrun.app` 並**回傳成功**(實測 exit 0,不是報錯)
// ⇒ 新版被寫到一個他根本沒在跑的路徑,他重開的還是原地那份舊的
// ⇒ 畫面說「更新完成」、版本卻永遠是舊的=**靜默失敗**,最難查的那種。
//
@@ -310,7 +310,7 @@ func applyStagedAndRestart() error {
// runningAppBundlePath 回傳**現在正在跑的**那個 .app 路徑(t184)。
//
// 路徑長相:<某處>/Arcrun RAG.app/Contents/MacOS/arcrun-tray
// 路徑長相:<某處>/Arcrun.app/Contents/MacOS/arcrun-tray
// ⇒ 從執行檔往上三層就是 .app 本體。
//
// 為什麼不寫死 /Applications:使用者常常就地執行(下載資料夾/桌面/隨身碟),
@@ -324,7 +324,7 @@ func runningAppBundlePath() (string, error) {
if resolved, err := filepath.EvalSymlinks(exe); err == nil {
exe = resolved // 走過 symlink 才是真身
}
// .../Arcrun RAG.app/Contents/MacOS/arcrun-tray → 上三層
// .../Arcrun.app/Contents/MacOS/arcrun-tray → 上三層
app := filepath.Dir(filepath.Dir(filepath.Dir(exe)))
if filepath.Ext(app) != ".app" {
return "", fmt.Errorf("這份 Arcrun RAG 不是從 .app 啟動的(%s)⇒ 請改用下載頁的 .app 版本再更新", exe)