Commit Graph

8 Commits

Author SHA1 Message Date
Leo 6698f9fbda v0.18.10:讓「同步引擎沒在跑」說出死因(leo Windows 實測①②的診斷前置)
leo 08-06 Windows 回報:「一直在『看守中』和『沒有在跑』中間閃,要我重啟但重啟無效,
我覺得它在跑個迴圈不停重複」+「加一個資料夾明顯沒產生看守資料夾」。
朋友的一般 PC(非 ARM)也一樣,停在等待中 ⇒ **不是 ARM 模擬的問題,是 Windows 通用**。

## 已定位的機制(不是根因,是「為什麼查不出根因」)
閃爍=子行程一啟動就死 → supervisor 退避重拉 → 狀態在 Starting(alive=true)與
Error(false)之間彈跳 ⇒ 畫面跟著閃。而**死因一直被記在 Status().LastError 裡,
從來沒有上過畫面、也沒寫進 app.log** ⇒ 使用者只看到閃爍與「請重新開啟」,
重開當然無效(死因沒變)。這是「安靜地略過」的同一種病換地方發作。

## 這版做的
- 死因上畫面:重試 >= 3 次改顯示「同步引擎一直啟動失敗,已自動重試 N 次|原因:…」,
  且**黏住不閃**(不受重起過程中的 Starting 影響)
- 每次異常結束寫進 app.log(同錯誤 10 次內只記一次,避免洗爆)

## 排除掉的嫌疑(查過,不是)
- PDF 引擎(pdfium/wasm):**延遲初始化**,第一次讀 PDF 才啟動 ⇒ 不會在啟動時炸
- ARM 模擬:leo 朋友的一般 x64 PC 同樣症狀
- 待查嫌疑:Wails 的 Windows 版是 `-H windowsgui`(GUI subsystem,無主控台),
  而 v0.18.8 的 collector.exe 是 `go build` 的 console subsystem——
  v0.18.9 合併成單一 binary 後,子行程換成 GUI subsystem 的自己。**尚未證實。**

## 順帶修好自己的閘(它擋對了我)
指紋閘擋下「v0.18.10 已對應另一份原始碼」——因為第一次打包失敗、版號卻已被戳。
⇒ 加判準:**磁碟上沒有該版號產物=從未出貨,允許重戳**(不用去手改 JSON,
那種爛示範遲早被改成「都放行」)。

## 安裝程式(leo ③)尚未兌現,誠實記錄
`wails build -nsis` 需要 makensis;Homebrew 的 3.12 在這台 macOS **連兩行的最小腳本
都在寫檔階段丟 std::bad_alloc**,zlib/bzip2/lzma 三壓縮器全崩,brew extract 舊版
被 homebrew/core 擋。且帶 -nsis 會讓 wails 整個中止、連 exe 都不產
⇒ build-win.sh 改成**先煙霧測試 makensis**,壞的就只出裸 exe 並大聲警告。
2026-08-06 18:27:08 +08:00
Leo 4d3a6a09a6 v0.18.9:collector 併進同一支執行檔——磁碟上不再攤出第二支 exe
leo 08-06 裁決:「不要兩支,寫成一支檔案」。

## 為什麼
v0.18.7-8 的「單一 exe」其實是**一支包著另一支**:collector.exe 被 go:embed
進 Arcrun.exe,執行時攤到 ~/.arcrun-rag/bin/ 再跑。
那正是防毒軟體眼中的 dropper 特徵 —— 封測者實撞
`Trojan:Win32/Sabsik.FL.A!ml`,檔案當場被隔離、自動刪除。

⚠️ 誠實界定:`!ml` 結尾=**機器學習判定**,Sabsik 是最常見的通用誤判家族,
   主因是「未簽章+下載次數少」,**不是**特別指向 dropper 行為。
   所以本次改動**不保證**解除誤判——真正的解是上架 MS Store(微軟簽章)。
   但「執行時把第二支 PE 寫到磁碟再執行」本來就該拿掉,這是對的方向且順手變小。

## 怎麼做
- `collector/` 39 個檔 `package main` → `package collector`,`main()` → 匯出的 `Run(args) int`
- 新增 `collector/cmd/collector/`(薄殼 CLI,讓單獨跑 collector 這條路仍可用)
- App 直接 import 該套件;`main()` 第一件事就判 `--collector`,是的話走 `collector.Run` 不碰 GUI
- `supervisor` 加 `ArgPrefix`,App 把 `BinPath` 指向 `os.Executable()` 自己
- 刪掉 `bundled_collector_{windows,other}.go`(embed + 攤檔那套)
- 三支打包腳本不再編/複製第二支;版本注入同時打到兩個 package
- build-win.sh 的機械閘改成**直接問它**:`--collector --version` 回得出版本才放行
  (舊閘是比大小,只能證明「有 embed」,證明不了「分派是對的」)

## 驗(真機實跑)
· `.app/Contents/MacOS/` 只有 **一個** 執行檔(原本兩個)
· 跑起來兩個行程是**同一個 exe**:
    …/MacOS/arcrun-app
    …/MacOS/arcrun-app --collector direct --config …
· `~/.arcrun-rag/bin` **不存在**(沒有任何東西被攤出來)
· 端到端:丟檔進看守資料夾 → collector.log `"status":"ingested","http_status":200`
· `lsappinfo` 仍是 `type="UIElement"`、`Version="0.18.9"`
· collector 39 檔測試全過;app 測試過;go vet 全綠;mac + windows 交叉編譯皆過
· 單檔 26MB → 22MB(不再夾帶第二份完整程式)
2026-08-06 16:00:47 +08:00
Leo b783b870e6 版本號改由 changelog 決定:從頭到尾沒有人打過數字,且與更新內容天生綁定
## 為什麼推翻自己幾小時前的做法
上一版用「動過 collector/ 的 commit 數」當 patch。確實不用手打,但
**每個 commit 都變成一版**(一天 5 個 commit 就跳 5 版),
每跳一版還要補一段 changelog ⇒ 把機械化變成新的手工活。leo 要的不是這個。

## 現在的機制(daemon-version.py)
單一真相源=docs-site/.../help/changelog.md:
  · 要出新版 ⇒ 最上面加一段 `## 下一版(未發佈)`,底下寫白話更新內容
  · 打包時腳本把它**戳成正式版號**(上一版 patch+1)並補今天日期
  · 沒有「未發佈」段 ⇒ 版本=最上面那一版(重打同一版,冪等不虛增)
⇒ 版本號沒有人打過;且不可能「升了版卻沒人知道改什麼」,
  也不可能「寫了內容卻忘了升版」——兩者出自同一段文字。
換線(0.18→0.19)只改 DAEMON_LINE,下一版自動從 0.19.0 起。
刪掉 daemon-version.sh 與 DAEMON_PATCH_BASE(一版的殘留)。

## 驗(實測輸出)
· `## 下一版(未發佈)` --stamp→ `## v0.18.7(2026-08-06)`(腳本自己改的)
· 沒有未發佈段時重跑 → 仍回 v0.18.7(冪等,不虛增)
· ./build-win.sh 全程通 → dist/Arcrun-win-v0.18.7.exe(27,445,248 bytes)
    strings 抽內嵌版本 = v0.18.7
· ./build-dmg.sh 全程通 → dist/Arcrun-v0.18.7.dmg(10M)
    掛載後 strings 抽 App 內嵌版本 = v0.18.7
    Info.plist CFBundleShortVersionString = 0.18.7(以前永遠是 1.0.0)
⇒ **兩條打包線第一次在同一個版本號上對齊**——這正是 08-06 那個病
  (只重打 Mac DMG、Windows 沒動、manifest 卻宣告新版)的根治。
· 未驗:Windows/Mac 真機行為;未出貨 ⇒ ◐
2026-08-06 13:16:14 +08:00
Leo be817b3c16 更新內容機械化+manifest 補上「宣告版本==產物版本」的閘+前端顯示同步器版本
回應 leo 08-06 兩問與兩項新需求。

## ①「更新內容還要寫在 docs 裡,機械化要怎麼做」
答:改的是「寫在哪」,不是「誰來寫」。
- 單一真相源=docs-site/.../help/changelog.md(本來就存在,用戶語言那份)
- 新增 changelog-section.sh:抽出某版段落(供 manifest.notes 投影用)
  + --check 模式當閘
- build-win.sh/build-mac.sh 接上閘:**changelog 找不到這版段落 ⇒ 中止打包**
  ⇒「忘了寫更新內容」變成不可能,而不是靠誰記得
- 已寫 v0.18.8 的用戶語言版本說明(本次五修)

## ② manifest 的閘:這次的病是從兩條規則中間的縫穿過去的
verifyManifest 對 daemon 只驗 ①version 欄在不在 ②file 指的檔存不存在。
08-06 那次**兩條都過**(宣告 v0.18.5、`-v0.18.4.zip` 檔案真的存在)⇒ 全綠放行。
新增第三條:宣告版本必須等於產物真正的版本
  (a) 檔名要帶宣告的版本(光這條就足以擋下 08-06 那次)
  (b) .exe 再驗一層:版本字串要真的在二進位裡(檔名可改,內嵌版本改不了)

實測(用當時的真實 manifest 值重現):
  · 宣告 v0.18.5 + 檔名 -v0.18.4.zip →  擋下(mac/win 各一條)
  · 檔名改成 v0.18.8 但內容是 v0.18.7 那顆 →  擋下(規則 b)

## ③ 前端顯示同步器版本+下載入口
leo:「連我都沒辦法確認,所以用戶到底是否最新版他自己也不知道」
- /api/latest 新增 daemon 欄(version/notes/downloads),由 daemonOf(env) 讀釘點
  manifest——與 releaseOf 同原則同真相源,不留手抄本。
  下載網址走 raw + 釘點 sha,與 selfupdate.go:158 同源(不自創第二條路)。
- rag.arcrun.dev 步驟 4 補上**真的下載按鈕**(Win/Mac)+同步器版本+
  「這一版改了什麼」連結。以前這裡只有文案提到下載、沒有連結也沒有版本。
  取不到就顯示「(查詢中)」並退回安裝說明頁——沿用 bf06ed7 的原則,不留手抄值。

## 驗
· node --check worker.js(installer/landing)皆 OK
· changelog 閘:v0.18.6 通過;不存在的 v0.18.7 → 退出碼 1 並印出可照抄的範本
· manifest 三條規則實測如上
· 未驗:線上畫面(要出貨後才有 daemon 欄位)⇒ ◐,不是 
2026-08-06 13:12:48 +08:00
Leo a55488040d Windows 交付改單一 exe+版本號不再手打(leo 08-06 回報②與「整串該機械化」)
## ② 兩個檔很迷惑 → 一個檔
leo 圖一標註:「下載還是 ZIP ⇒ 應該是 MSIX 或 EXE;解開還是 2 個檔 ⇒ 應該只有 1 個檔案」。
舊做法 zip 裡放 Arcrun.exe+arcrun-collector.exe 同層,少解一個檔就永遠不會同步,
而畫面不會說是這個原因。
修:collector 用 go:embed 收進 Arcrun.exe,第一次執行攤到 ~/.arcrun-rag/bin/
    (冪等:sha256 相同不重寫;先寫暫存再 rename,避免留半截執行檔)。
    build-win.sh 直接產單一 Arcrun-win-<ver>.exe,不再打 zip。
    加機械閘:產出的 exe 若比 collector 還小 ⇒ 沒 embed 成功 ⇒ 中止(過去只會
    默默得到一顆「裝了也不會同步」的空殼)。
不走 MSIX:未上架的 MSIX 要使用者先開「開發人員模式」,比 zip 更麻煩。

## 版本號機械化(leo:「這一整串都應該是機械化,不應該每次手工做」)
病根實測:本 repo **一個 git tag 都沒有**,而四支 build 腳本寫的是
`git describe --tags` ⇒ 永遠拿不到 v0.18.x ⇒ 只能靠打包時人工敲 VERSION=
⇒ 兩條打包線各敲各的 ⇒ manifest 宣告 0.18.5、產物其實是 0.18.4。

修:新增 daemon-version.sh 當唯一產生器,沿用 release.mjs 已在跑的原則
   (「版本號由內容算出來,不是由人宣告」),不另立新制:
     MINOR ← DAEMON_LINE(人決定,大改版才動)
     PATCH ← 動過 collector/ 的 commit 數 − DAEMON_PATCH_BASE(機器決定)
   ⇒ 沒改 daemon 重跑打包不會虛增;改了才 +1;四支腳本在同一 commit 必得同號。
   ⇒ 不需要 git tag/Actions/輪詢(守 D20 紅線)。
   校準:DAEMON_LINE=0.18、BASE=87 ⇒ 現在的樹算出 v0.18.7(上次出貨過 0.18.6)。
   build-win/mac/dmg/msix 四支全部改用它。

## icon 漂移根治接上打包
build-win.sh 步驟⓪ 每次都跑 gen-icons.py 重產 icon.ico/trayicon.ico。

## 驗(實測輸出,非推測)
· ./build-win.sh 全程跑通,產出 dist/Arcrun-win-v0.18.7.exe(27,445,248 bytes)
· strings 抽內嵌版本 = v0.18.7、buildTime = 20260806-1233(機器算的,沒人敲)
· 位元組比對該 exe:
    CIS trayicon 在裡面        = True
    Wails「W」圖還在           = False
    collector 有 embed 進去    = True(16,104,960 bytes)
· go vet 全綠(darwin + windows);mac build OK
· 未驗:Windows 真機行為(需封測者實跑)⇒ 狀態 ◐,不是 
· 未做:CHANGELOG 閘、manifest「宣告版本 == 產物版本」驗證閘、前端顯示版本與下載入口
2026-08-06 12:35:54 +08:00
Leo 9cd0adab22 G-6.2:讀不了的檔案不再安靜消失——首頁當場說出來
服務 J-1 / S6「我丟進去的檔案,查得到」的考題 G-6.2:
「要嘛查得到,要嘛**當場被告知這種檔案還不支援**,不准安靜地略過。」
本次只做後半句(轉檔本體另有人閘,等 leo 裁「那段 Go 住哪裡」)。

## 真實現況比記載更糟
t16 寫的「PDF 被靜默略過」已不成立(t73 的轉檔層把 pdf/docx/xlsx/csv/pptx
都接上了,實測 2 頁中文 PDF 完整抽出)。**真正還在沉默的是別的東西**:
副檔名不在 allowedExt 的檔案在 scan.go 直接 `return nil`——
不進事件、不進 manifest、不進 status、不進畫面。
使用者丟一份 .doc 進去,從頭到尾一個字都沒有。

實測基線(真檔):丟 .pdf/.md/.doc/.key/.jpg 進資料夾,
`collector scan` 只吐出 pdf 與 md 兩個事件,另外三個檔沒留下任何痕跡。

## 改了什麼
- scan.go:白名單閘不再是死巷。像文件的(.doc/.xls/.ppt/.pages/.key/
  .numbers/.odt/.ods/.odp/.rtf/.epub/.wpd/.msg/.eml)逐檔留名;
  其餘(圖片/影音/程式碼)只計總數——**避免 Obsidian 附件庫炸出幾百行噪音**。
- 兩個新欄位標 `json:"-"`:collector-trigger schema 是
  additionalProperties:false,且 BuildSendablePayload 是淺拷貝
  ⇒ 有 tag 就會漏到雲端被擋。這是給本機使用者看的,不上 wire。
- direct.go → status.json → App 首頁一張卡:講檔名與格式(「舊版報告.doc
  (舊版 Word)」),並告訴他不用重丟、也給替代路(另存成 PDF/.docx)。
- 刻意不進 manifest、不走 CarryForwardActivity:每輪由檔案系統重算,
  不製造 t195 那種「跨輪欄位漏 carry 就靜默歸零」的債。

## 順手修掉一個會讓驗收失效的回歸
同綑的 arcrun-collector 一路自稱 `dev`:退役 fyne 版
(arcrun-tray/build-mac.sh:24,t150/t72)本來就有版本注入,
t194 換 Wails 時沒帶過來,Mac 與 Windows 兩邊都掉。
**幹活的是 collector**——它不報版本,就沒人能判斷修復有沒有到使用者手上。

## 實測
- go test ./... 135 過 0 敗(新增 10 條:scan 5+首頁文案 5)
- check-cis / check-render / check-tray 三閘全過;淺色深色都抓過畫面
- 從 **DMG 裡那支** collector 實跑:Info.plist 0.18.6、
  collector 回報 v0.18.6 (build 20260806-0101)、
  status.json 吐出 skipped_docs=[簡報.key, 舊版報告.doc]、other=1

⚠️ 未出貨:推 bundles repo 在 GitHub,要 leo 開 D20 閘。
DMG 已備妥 dist/Arcrun-v0.18.6.dmg。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 01:04:25 +08:00
Leo 133bfdbc84 修 Info.plist 版本永遠是 1.0.0+skill 補「用戶視角驗收」
leo 開 DMG 檢查時抓到:CFBundleShortVersionString = **1.0.0**(Wails 預設),
不是 v0.18.4 ⇒ 使用者在 Finder/「關於」看到的版本永遠不變
⇒ 無從判斷自己是不是新版(同「版本號是唯一驗收介面」的病)。

真因:wails.json 沒有 info.productVersion,而 wails build **沒有 CLI 旗標**可指定。
修:build-mac.sh/build-win.sh 建置前把版本寫進 wails.json 的 info,
建完用 trap 還原(不污染版控)。
驗:重打後 Info.plist = 0.18.4 、wails.json 無殘留 

DMG 用戶視角實測(掛載後看):
  剛好兩項 Arcrun.app + Applications 捷徑 (拖進去的標準畫面)
  MacOS/ 內含 arcrun-app + arcrun-collector (沒同綑=裝了不會同步)
  LSUIElement=true (不佔 Dock)|codesign -v 通過 

skill 補兩段:
· 3.5「把 DMG/zip 真的打開,用使用者第一次看到的樣子檢查」(含五項判準與漏掉的後果)
· 開頭「這支 skill 自己的失效模式」——leo:「你寫完一個 skill 然後每個我要提醒你,
  表示這個 skill 無效」。根因是憑印象列步驟沒走過使用者的路;
  訂三條鐵律(每條要有可貼的實測輸出/使用者看得到的東西一律真的打開/
  被 leo 問出來的缺口當場補進 skill)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 16:52:34 +08:00
Leo d80e9e1357 t196:Windows 版重編(Wails)+MSIX 打包——在 Mac 上交叉編譯,不需 Windows 機器
leo 08-05:「Windows 版一定要重編,因為我只有 Mac,我需要人家測試,
要做到最完善不要給人家找麻煩,然後當測試者給我截圖安裝成功就要提交 ms store」

## 缺口
Windows 打包腳本全在**舊的 arcrun-tray(fyne 版)**,
新的 arcrun-app(Wails,t193/t194 整批 UI 重做)**完全沒有 Windows 產線**
⇒ Windows 封測者只能拿到 v0.15.7 的舊 fyne 版。

## 新增
· tray_windows.go — Windows 系統匣(energye/systray)
  行為與 macOS 版逐項對齊:左鍵開視窗/右鍵只有「結束 Arcrun」/關窗不結束。
  ⚠️ 為什麼 Windows 能用 systray 而 macOS 不能(wiki 有全文):
     macOS 上它在 Wails 之下根本不建托盤(setInternalLoop 只在 systray.Run() 呼叫),
     改用 systray.Run() 又搶 macOS 主 loop ⇒ macOS 最後走原生 NSStatusItem。
     **Windows 走 Win32 訊息迴圈,沒有主執行緒限制**,所以這裡用 systray 是對的,
     不是抄 macOS 失敗的做法。
  trayApp 與 ICO 都在本檔自帶(tray_darwin.go 有 //go:build darwin,Windows 看不到)。
· build-win.sh  — 交叉編譯 zip(CGO_ENABLED=1 + mingw-w64,Wails Windows 要 WebView2 綁定)
  **同綑 collector.exe**:daemon 本體是 collector direct,沒同綑=裝了不會同步
  (t194 在 Mac 版就漏過一次)。supervise.go 的 collectorBinPath() 已處理 .exe 副檔名。
· build-msix.sh — MS Store 用的 msix(沿用 makemsix,Mac 上就打得出來)
  與舊 fyne 版差別:**Wails 是兩個 exe**,兩個都要進 msix root。
  Identity 三值走環境變數(要與 Partner Center 完全一致),預設佔位並印警告。

## 驗
· Windows zip:兩個檔都是正牌 PE(MZ 標頭)/Arcrun.exe 11.4MB+collector.exe 16.1MB
· 退避修復確實編進 Windows 版(不剝符號重編一份,grep 到 MarkFailed/ShouldRetry/
  retrySkipReason 各 2 處;出貨版用 -s -w 剝符號故查不到,屬預期)
· MSIX:16 檔、含 AppxBlockMap;zip 回讀兩個 exe 的 sha256 與原檔**逐一相符**;
  manifest Executable="Arcrun.exe"、Version=0.18.4.0
· **macOS 版不受影響**:編譯通過、三支機械閘全過

## 兩個踩到的坑(已修)
· zip 用相對路徑在 cd 後失效(zip I/O error,fallback 湊巧成功但不可靠)⇒ 改絕對路徑
· 全形括號緊接變數會被當成變數名(腳本自己的註解就警告過)⇒ 改 ${VAR}

## 殘項
· Identity 仍是 PLACEHOLDER ⇒ **這顆 msix 還不能送 Store**,等 leo 給 Partner Center 三值
· 未在真 Windows 上跑過(誠實界定:只證明編得出來,不證明跑起來對)
2026-08-05 15:50:57 +08:00