Commit Graph

9 Commits

Author SHA1 Message Date
Leo 458ff3fd88 v0.18.14/15:全新使用者連上知識庫後會自己開始+log 不再印不存在的網址
leo 08-06 用共用資料夾實測,兩張圖把最後一個病逼出來:
「第一次直接跑可以,**清空再來一次,就不跑了**」。

## 真兇:restartWatch 第一行就早退
全新使用者的順序是:
  ① 打開程式(**還沒有任何設定**)⇒ startSupervisor 早退,`sup` 是 nil
  ② 連上知識庫、加資料夾 ⇒ restartWatch
  ③ 舊版:`if sup == nil { return }` ⇒ **什麼都沒發生**
  ⇒ 引擎永遠不啟動,畫面叫人「請結束 Arcrun 再重新開啟」
「不算錯」(重開真的會好),但等於要求剛裝好的人自己想到去重開程式。
**每一個第一次用的人都會撞到**;開發機永遠有設定,所以永遠測不到。

修:`sup == nil` 時**現場建立**(設定剛出現,正是該啟動的時機)。
新測試 `TestFirstRunStartsEngineAfterConnect` 從「沒有設定」開始走完整順序;
反向驗證拿掉即紅。

## 順帶把那句沒用的話拿掉
「請結束 Arcrun 再重新開啟」=把系統的無能推給使用者。
改成「正在啟動同步引擎,請稍候…」;還沒連知識庫時說
「按『新增知識庫帳號』就會開始」。

## log 不再說謊(今天第三次同一個主題)
啟動訊息印 `cfg.triggerURL(...)`=用**根層**的 cypher_url/namespace 組的,
而多帳號設定根層是空的 ⇒ 印出 `→ /webhooks/named//rag_ingest/trigger`
(沒網域、雙斜線)**看起來像設定壞了,其實功能正常**。
改印每個帳號真正會用到的網址。

## 實測證據(共用資料夾自動收回來的 log,非截圖轉述)
  19:13:54  設定檔缺必填欄位,已自動補上 manifest=C:\Users\leo21\.arcrun-rag\manifest.json
  19:13:55  collector direct daemon 啟動:監看 …\win_on_mac_test_lib  {"phase":"start"}
⇒ v0.18.13 的自我修復在真機生效,config 已補上 manifest,collector 真的跑起來。
2026-08-06 19:33:36 +08:00
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 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 ee2fc2a803 Windows 三修:不再無限多開/首頁不再謊報「引擎沒在跑」/視窗改螢幕 50%
leo 08-06 封測回報①④+圖三標註。三個都是**只在 Windows 現形**的病。

## ④ 托盤一次開好幾個 icon
leo:「點一次開一個新的,測試者原本給我看顯示到 4 個」。
真兇:main.go 的 options.App 沒設 SingleInstanceLock(Wails v2.13 有這選項)。
每個實例還各自拉一份 collector 子行程。
macOS 由 LaunchServices 天然單實例 ⇒ Mac 上驗不出來。
修:加 SingleInstanceLock,第二次啟動叫醒既有視窗後自己退出。

## ① 根本不運行(首頁恆顯示「同步引擎沒有在跑」)
真兇:collectorAlive() 的憑據是 `pgrep -f <bin>`,**Windows 沒有 pgrep**
⇒ 恆回 false ⇒ app.go:356 一定走「同步引擎沒有在跑」,與實際狀態無關。
修:憑據換成 supervisor 自己的狀態機(親手拉起的子行程、runOnce 以 cmd.Wait 收尾)
    ——比掃行程表更有憑據且跨平台,順帶修掉 pgrep 會匹配到別的實例的偽陽性。
⚠️ 不是發明第三種判斷法:db17f28(08-05)已為「同步中」立下同一條路
   「改讀 sup.Status().State ⇒ 接回既有機制,不發明第三種判斷法」,
   當時只改了 collectorSyncing 那半邊,這裡把漏掉的 collectorAlive 補上。
順帶移除 waitCollectorGone/pkill:翻 supervisor 原始碼確認 Stop() 回來時
子行程已被 cmd.Wait 收屍完畢,補刀多餘;且那兩支指令 Windows 根本沒有。

## 視窗高度擠出畫面
leo 圖三:「視窗尺寸應該是 default 50% 螢幕長寬,高度太高快擠到外面了」。
修:OnStartup 依 ScreenGetAll 算 50% 並置中;保底值 1000x700 → 960x600
    (拿不到螢幕資訊時不瞎猜,沿用保底值)。

## 驗(實測輸出)
· go vet 全綠(darwin + GOOS=windows 各一次)
· mac build OK;GOOS=windows CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc 交叉編譯 OK
· 位元組比對交叉編譯出的 .exe:
    新 CIS trayicon.ico 在 exe 裡 = True
    舊 Wails「W」圖在 exe 裡    = False
· 未驗:Windows 真機行為(需重打包後由封測者確認)⇒ 狀態 ◐,不是 
2026-08-06 12:20:25 +08:00
Leo 6bf0daa786 修首頁狀態說謊+DMG 補上拖曳版面(leo 08-05 封測回報 ①②)
## ② 首頁狀態是壞的
leo:「拖新的檔案進資料夾,完成本地萃取、上傳,但自始至終 daemon 的首頁都顯示
『有變動就自動開始』『等待中』,都顯示綠燈沒動,實際上已經做完了。」

兩個獨立的真兇:

**A. 「同步中」判斷用錯依據(回歸)**
t191 早就做好機制:collector 開工印 phase:"start"、跑完印 "done",
supervisor 據此維護 StateSyncing。**換 Wails 時 App 沒接這條線**,改看 sync-now 訊號檔:
  ① 訊號檔只有手動按「立刻同步」才產生 ⇒ 拖檔進資料夾(自動觸發)整輪不亮燈
  ② 就算手動按,collector 是**先刪檔再跑**(consumeSyncNowSignal)⇒ 真正在跑時檔早沒了
⇒ 改讀 sup.Status().State == StateSyncing。**接回既有機制,不發明第三種判斷法。**

**B. 做完的證據被下一輪抹掉**
ExtractedOK/ExtractFailed 是**本輪**計數、每輪覆寫整份 status.json
⇒ 有產出那輪寫下 N,十幾秒後空轉的一輪把它蓋成 0
⇒ 「上一輪 N 份」永遠空白、四步時間軸的綠燈只靠「跑過任何一輪」判斷=與實際進度脫鉤。
⇒ 新增 last_activity_{at,ok,failed}:有產出記本輪、空轉沿用上一輪(CarryForwardActivity)。
   首頁改顯示「幾點整理了幾份」,綠燈只在真的整理過東西時才亮。

## ① Mac DMG 少了「看得出要拖」的版面
leo:「要跳出虛擬隨身碟,打開一個 finder 的視窗,**顯示 Arcrun 和 Application 的捷徑**,
用戶把 App 拖進 Application」。
原本 DMG 內容是對的(Arcrun.app+Applications 捷徑),但**沒設版面**
⇒ 預設清單視圖、位置隨機,看不出「要往右拖」。
⇒ build-dmg.sh 改走 UDRW → Finder AppleScript 設大圖示/視窗大小/左右並排 → 轉 UDZO。
   best-effort:無桌面工作階段時只警告不中止(版面是加分,不該讓打包掛掉)。

⚠️ 真正讓 leo 拿到 zip 的原因不在這裡——是**線上 portal 還沒出貨**(見下)。

## 驗(實測輸出)
· collector 全測綠;新增 TestCarryForwardActivity 四子測(含「空轉不該抹掉上次成果」)
· 掛載 dist/Arcrun-v0.18.5.dmg 實查:
    內容剛好兩項(Arcrun.app + Applications→/Applications 捷徑)
    .DS_Store 6148 bytes(版面已存進去)
    Contents/MacOS/ 有 arcrun-app **和 arcrun-collector**
    CFBundleShortVersionString = 0.18.5(不是 1.0.0)/LSUIElement = true/codesign -v 通過
· 三支機械閘 check-cis/check-render/check-tray 全 PASS

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 18:01:17 +08:00
Leo d787bfc47d t195:燈號不再說謊+加診斷 log(leo:「燈號是真的還是假的?」→ 是假的)
## leo 實撞
丟 PDF 進 youlinhsieh-test1 沒反應;按「立刻同步」後畫面顯示
「正在整理知識卡」,但**卡從來沒產出**。

## 燈號為什麼是假的
舊版 describeStatus 只看「sync-now 訊號檔存不存在」就顯示「同步中…」。
那只代表**排隊了**,不代表有人處理:leo 的 collector 在 11:25 跑完最後一輪,
他 11:38 按同步 ⇒ 訊號檔沒人消化 ⇒ 畫面一直說在整理,實際 13 分鐘沒跑過。
**這比沒有燈號更糟——它在說謊。**

修:燈號要有憑有據——
  · collector 沒在跑 → 明說「同步引擎沒有在跑」並告訴他怎麼辦
  · 有排隊 **且** 引擎活著 → 才是「同步中」
  · 其餘 → 看守中

## 順手補上診斷 log(~/.arcrun-rag/app.log)
startSupervisor 以前只 Stat(config) 就靜默 return,出問題完全查不到
(我這次也是繞了很久才確定它有啟動)。現在每個 return 點都留痕。

## 🔴 但真正擋住產卡的是另一個 401(未修,需 leo 裁)
實測鏈路:掃到 PDF  → /portal/daemon/extract  200 → 寫 kbdb  401
  curl -X POST https://arcrun-kbdb.youlin-hsieh-dev.workers.dev/entries(無 token)→ 401
真兇:workflows/rag-ingest-card.local.yaml 打 __KBDB_BASE__/entries
**完全沒帶 Authorization**,但 kbdb 要 Bearer KBDB_INTERNAL_TOKEN。
⚠️ 與今天修的 t189 不同:那是 extract 端點入口(現已 200),這是 workflow 內部寫 kbdb。

修法命中 D36 金鑰鐵律(「只能拿 key,送出時自動拉 value」)
⇒ 應寫 {{credential.kbdb_internal_token}} 由 resolve_credentials 回填,
   而非讓安裝器 sed 把 token 值塞進定義。**已停下等 leo 裁**。

## CP 對帳
「丟檔→產卡」=  斷(卡產不出來)。本次只修好「燈號誠實」與「可診斷」,
**未送達用戶**(daemon 新版尚未出貨、401 未修)。
2026-08-05 11:45:07 +08:00
Leo fcdb1df71d t194 二修:托盤 icon/右鍵選單/重複點擊/正常結束(leo 實測四點)
leo 真機測出四個問題,每個都查到真兇後才動手:

## ① 托盤 icon 變方塊
真兇:我塞 1024x1024 的**彩色 app icon** 當 template icon。
macOS 選單列規格是 **16-22pt、純黑+alpha**(由系統依深淺色自動上色)
⇒ 彩色大圖被縮成一坨方塊是必然。
修:用 CIS 的 chevron-double.svg 渲成 44x44 純黑 template icon。

## ②③ 右鍵沒選單/第一次能開之後就不再跳
真兇(energye/systray 原始碼註解白紙黑字寫著):
「該方法主動調用後 如果托盤菜單已創建則添加進去, **之後鼠標事件失效**」
⇒ 只要用 AddMenuItem 建了選單,SetOnClick/SetOnRClick **全部失效**。
修:SetMenuNil() 移除選單讓滑鼠事件生效,右鍵時自己 ShowMenu()。
另外 ShowWindow 只呼叫 WindowShow 對「已開但被蓋住」無效
⇒ 補 Unminimise + AlwaysOnTop 閃一下搶焦點。

## ④ 只能用強制結束
真兇:Wails 的 loop 不理 SIGTERM,且 collector 是我們自己 Start 的子行程
⇒ 主程式被殺後**子行程變孤兒繼續跑**。
實測(機械驗證,非目視):
  修前 kill -TERM → App 沒退、collector 孤兒還在
  修後 kill -TERM → App 正常退出 、collector 一起收掉 、殘留 0
修:installSignalHandler 收 TERM/INT → stopSupervisor() →
    waitCollectorGone(3s) 確認子行程真的不見(逾時補一刀)→ 才 os.Exit。
    「關了卻還在同步」比沒關更糟。

實跑驗證:App 活著 pid 88466、自己拉起 collector、crash 0、兩支機械閘全過。
2026-08-05 01:41:31 +08:00
Leo 549834f343 t194:托盤收成 Google Drive 式(點 icon 開視窗/右鍵只有結束)+同綑 collector
leo 2026-08-05:「依照 google drive,托盤裡只剩下按右鍵會結束,
其他設定都在這個頁面,點擊托盤的 icon 就立刻展開界面」

## 托盤
Wails v2 沒有內建托盤 ⇒ 用 energye/systray(Wails 相容分支,支援左鍵事件)。
- 左鍵:直接展開主視窗,**不彈選單**
- 右鍵:只有一項「結束 Arcrun」
- 設定全部留在視窗裡,托盤不再是第二套 UI
  (fyne 版把設定塞下拉選單,leo 早說過「不可能統統塞在下拉選單」)
- 關窗=隱藏不結束(daemon 常駐;按 × 就停止同步不符預期)
- Dock 不出現 icon:Wails v2.13 的 mac.ActivationPolicy 還沒開放(原始碼是註解掉的)
  ⇒ 改走 Info.plist 的 LSUIElement,與 fyne 版同一個做法

## 🔴 順手抓到自己的大漏:這個 App 根本沒有啟動 collector
daemon 的**本體**是 `collector direct`(監看/萃卡/上傳),Wails 版我一路沒接
⇒ 照這樣出貨會是「裝了也不會同步」的空殼。
修:新增 supervise.go,**複用既有 supervisor 套件**(重起退避/狀態機/
    t191 的 phase:start/done ⇒「同步中…」),不複製一份(複製=會漂移)。
    go.mod 用 replace 指回 collector 主模組。
    加/刪資料夾、改 AI 設定後都會 restartWatch(),設定立刻生效。

## 打包
新增 build-mac.sh:編 collector → wails build → **同綑進 .app** → ad-hoc 重簽。
沒同綑就等於沒有 daemon。

實測(v0.18.0):collector 同綑 15M /LSUIElement=true /版本注入 /已簽 
兩支機械閘全過。
⚠️ 未驗:托盤左右鍵的實際行為要真機點(我開不了視窗)。
2026-08-05 00:31:52 +08:00