From 9fcd82b5174920c931f13da0c1d13a1065d4d028 Mon Sep 17 00:00:00 2001 From: richblack Date: Tue, 4 Aug 2026 18:12:53 +0800 Subject: [PATCH] =?UTF-8?q?v0.15.7=EF=BC=9A=E6=94=B9=E5=90=8D=20Arcrun.app?= =?UTF-8?q?=EF=BC=8B=E7=99=BC=20DMG=EF=BC=88=E6=8B=96=E9=80=B2=20Applicati?= =?UTF-8?q?ons=EF=BC=89=EF=BC=8BMSIX=20=E6=AD=A3=E5=BC=8F=E8=BA=AB?= =?UTF-8?q?=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- cmd/arcrun-tray/ArcrunRAG-mac-unsigned.zip | 4 +- cmd/arcrun-tray/README.md | 4 +- cmd/arcrun-tray/build-dmg.sh | 46 ++++++++++++++++++++++ cmd/arcrun-tray/build-mac.sh | 8 ++-- cmd/arcrun-tray/selfupdate.go | 14 +++---- cmd/arcrun-tray/t184_test.go | 6 +-- 6 files changed, 64 insertions(+), 18 deletions(-) create mode 100755 cmd/arcrun-tray/build-dmg.sh diff --git a/cmd/arcrun-tray/ArcrunRAG-mac-unsigned.zip b/cmd/arcrun-tray/ArcrunRAG-mac-unsigned.zip index 37276fc..177ff6d 100644 --- a/cmd/arcrun-tray/ArcrunRAG-mac-unsigned.zip +++ b/cmd/arcrun-tray/ArcrunRAG-mac-unsigned.zip @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c31803a4f56c00bcc154f101ca7b2029d59acb01acb53cf26756e8eb563708e1 -size 16873725 +oid sha256:f264dda7391f3006686d6ee8311960054206fb1ffee8f50e2f5a896159522565 +size 16874862 diff --git a/cmd/arcrun-tray/README.md b/cmd/arcrun-tray/README.md index 52f22a6..0f8dcad 100644 --- a/cmd/arcrun-tray/README.md +++ b/cmd/arcrun-tray/README.md @@ -41,9 +41,9 @@ go run fyne.io/fyne/v2/cmd/fyne@latest package -os darwin -icon icon.png -name " 未簽章的 .app 會被 Gatekeeper 擋(右鍵開可繞,但非產品體驗)。正式版: ```bash -codesign --deep --force --options runtime --sign "Developer ID Application: <你>" "Arcrun RAG.app" +codesign --deep --force --options runtime --sign "Developer ID Application: <你>" "Arcrun.app" xcrun notarytool submit "Arcrun RAG.zip" --apple-id … --team-id … --wait -xcrun stapler staple "Arcrun RAG.app" +xcrun stapler staple "Arcrun.app" ``` ## TCC(macOS,只有真 Mac 驗得到) diff --git a/cmd/arcrun-tray/build-dmg.sh b/cmd/arcrun-tray/build-dmg.sh new file mode 100755 index 0000000..8a388b1 --- /dev/null +++ b/cmd/arcrun-tray/build-dmg.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# build-dmg.sh — 把 Arcrun.app 打成標準 Mac DMG(t184 配套,leo 2026-08-04 核可)。 +# +# 🎯 為什麼要 DMG(不是繼續發 zip): +# zip 解出來就是一個 app,使用者**很容易就地雙擊執行**(下載資料夾、桌面)。 +# Oscar 就是這樣 ⇒ 他的 app 不在 /Applications ⇒ 自更新蓋錯地方(t184 真兇)。 +# DMG 裡放「app + Applications 資料夾捷徑」,開起來就是叫你把 app 拖進去的畫面 +# ⇒ **從源頭讓 app 待在該待的位置**,這是 Mac 的標準慣例,使用者一看就懂。 +# +# ⚠️ DMG 治源頭、t184 是安全網,**兩個都要**: +# 已經裝好舊版在別處的人(如 Oscar),不會因為改發 DMG 就自動變好。 +# +# 用法:VERSION=v0.15.7 bash build-dmg.sh +# 產物:dist-mac/ArcrunRAG-.dmg +set -euo pipefail +cd "$(dirname "$0")" + +APP="Arcrun.app" +[[ -d "$APP" ]] || { echo "❌ 找不到 $APP —— 先跑 build-mac.sh" >&2; exit 1; } + +VERSION="${VERSION:-$(git describe --tags --always --dirty 2>/dev/null || echo dev)}" +OUT_DIR="dist-mac" +DMG="$OUT_DIR/ArcrunRAG-${VERSION}.dmg" +STAGE="$(mktemp -d)/Arcrun RAG" + +echo "🏷 版本:${VERSION}" +mkdir -p "$OUT_DIR" "$STAGE" + +echo "① 放 app 進暫存區" +ditto "$APP" "$STAGE/$APP" + +echo "② 放 Applications 捷徑(使用者拖曳的目標)" +ln -s /Applications "$STAGE/Applications" + +echo "③ 產 DMG" +rm -f "$DMG" +hdiutil create -volname "Arcrun" -srcfolder "$STAGE" -fs HFS+ -ov -format UDZO "$DMG" >/dev/null + +rm -rf "$(dirname "$STAGE")" +SIZE=$(ls -lh "$DMG" | awk '{print $5}') +# 註:`$DMG(` 要寫成 `${DMG}(`——全形括號不是分隔符,bash 會把它吃進變數名。 +echo "✅ 完成:${DMG}(${SIZE})" +echo +echo "🔬 驗法:" +echo " hdiutil attach '$DMG' → 應看到 Arcrun.app 與 Applications 捷徑並排" +echo " 使用者把左邊拖到右邊即完成安裝(Mac 標準流程)" diff --git a/cmd/arcrun-tray/build-mac.sh b/cmd/arcrun-tray/build-mac.sh index 54c9962..00367f4 100755 --- a/cmd/arcrun-tray/build-mac.sh +++ b/cmd/arcrun-tray/build-mac.sh @@ -6,7 +6,7 @@ # # 用法(真機、需 Xcode CLT): # cd collector/cmd/arcrun-tray && bash build-mac.sh -# 產物:Arcrun RAG.app(含同綑 arcrun-collector)。簽章/公證另行(見 README)。 +# 產物:Arcrun.app(含同綑 arcrun-collector)。簽章/公證另行(見 README)。 set -euo pipefail cd "$(dirname "$0")" @@ -24,7 +24,7 @@ echo "① 編 collector(同綑執行檔)" ( cd ../.. && go build -ldflags "-s -w ${LDFLAGS_VER}" -o "cmd/arcrun-tray/arcrun-collector" . ) echo "② fyne package" -go run fyne.io/fyne/v2/cmd/fyne@latest package -os darwin -icon icon.png -name "Arcrun RAG" -appID dev.arcrun.rag.tray +go run fyne.io/fyne/v2/cmd/fyne@latest package -os darwin -icon icon.png -name "Arcrun" -appID dev.arcrun.rag.tray # ②b 用 -s -w 重編托盤覆蓋回 bundle(2026-07-27,t72/t63)。 # 為什麼:`fyne package` 內部自己 go build,吃不到 -ldflags,產出含符號表與 DWARF 的胖執行檔。 @@ -33,9 +33,9 @@ go run fyne.io/fyne/v2/cmd/fyne@latest package -os darwin -icon icon.png -name " # "File size exceeded the configured limit of 20 MB.",只能走 raw;Windows 版 13MB 無此問題)。 # ⇒ 這一步讓 Mac 版也能走 CDN,且**免除拆檔工程**。功能指紋與簽章實測皆不受影響。 echo "②b strip 重編托盤(-s -w;為了掉進 jsDelivr 20MB 線內)+注入版本號" -go build -ldflags "-s -w ${LDFLAGS_VER}" -o "Arcrun RAG.app/Contents/MacOS/arcrun-tray" . +go build -ldflags "-s -w ${LDFLAGS_VER}" -o "Arcrun.app/Contents/MacOS/arcrun-tray" . -APP="Arcrun RAG.app" +APP="Arcrun.app" PLIST="$APP/Contents/Info.plist" echo "③ LSUIElement=true(托盤唯一指示器,隱 Dock icon——leo 07-24 裁決)" diff --git a/cmd/arcrun-tray/selfupdate.go b/cmd/arcrun-tray/selfupdate.go index 19c6eee..c3e387e 100644 --- a/cmd/arcrun-tray/selfupdate.go +++ b/cmd/arcrun-tray/selfupdate.go @@ -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)") } // 🔴 t184(leo 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) diff --git a/cmd/arcrun-tray/t184_test.go b/cmd/arcrun-tray/t184_test.go index aaf1363..7e8bda7 100644 --- a/cmd/arcrun-tray/t184_test.go +++ b/cmd/arcrun-tray/t184_test.go @@ -21,13 +21,13 @@ func TestRunningAppBundlePathNotHardcoded(t *testing.T) { } } -// 模擬真實 .app 結構:/Arcrun RAG.app/Contents/MacOS/arcrun-tray +// 模擬真實 .app 結構:/Arcrun.app/Contents/MacOS/arcrun-tray // 驗證「往上三層」的推導正確——放在哪個目錄都要算得出來。 func TestAppBundleDerivationFromExePath(t *testing.T) { for _, base := range []string{"/Applications", "/Users/oscar/Downloads", "/Volumes/USB"} { - exe := filepath.Join(base, "Arcrun RAG.app", "Contents", "MacOS", "arcrun-tray") + exe := filepath.Join(base, "Arcrun.app", "Contents", "MacOS", "arcrun-tray") app := filepath.Dir(filepath.Dir(filepath.Dir(exe))) - want := filepath.Join(base, "Arcrun RAG.app") + want := filepath.Join(base, "Arcrun.app") if app != want { t.Errorf("從 %s 推導錯:got %q want %q", base, app, want) }