diff --git a/cmd/arcrun-app/.version-source.json b/cmd/arcrun-app/.version-source.json index 6b7a68a..bdac60c 100644 --- a/cmd/arcrun-app/.version-source.json +++ b/cmd/arcrun-app/.version-source.json @@ -1,5 +1,6 @@ { "v0.18.9": "8be9260eb542f527", "v0.18.10": "a440f044a849b7f2", - "v0.18.11": "1538689e181444f6" + "v0.18.11": "1538689e181444f6", + "v0.18.12": "ce37982f05d8cb5b" } diff --git a/cmd/arcrun-app/app.go b/cmd/arcrun-app/app.go index 5a17655..1ac0d9c 100644 --- a/cmd/arcrun-app/app.go +++ b/cmd/arcrun-app/app.go @@ -21,7 +21,9 @@ import ( "encoding/json" "fmt" "os" + "os/exec" "path/filepath" + runtime2 "runtime" "sort" "strings" "time" @@ -196,6 +198,10 @@ type UIState struct { ExtractedOK int `json:"extractedOK"` // 首頁「已整理幾份」 Steps []Step `json:"steps"` // 首頁狀態時間軸(leo #6) Skipped *UISkipped `json:"skipped"` // 讀不了的檔(沒有就是 null,前端不畫) + // EngineTrouble=同步引擎有問題(沒在跑/一直啟動失敗)⇒ 前端才長出「回報問題」卡。 + // 沒事時不顯示,避免把「哪裡看 log」變成常駐噪音。 + EngineTrouble bool `json:"engineTrouble"` + LogFolder string `json:"logFolder"` } // UISkipped=首頁那張「這些檔案現在還處理不了」的卡。 @@ -343,6 +349,10 @@ func (a *App) GetState() UIState { st.Syncing, st.StatusBig, st.StatusSub = describeStatus(sync) st.Steps = buildSteps(sync, st.Syncing) st.Skipped = buildSkipped(sync) + // 引擎有問題才把「回報問題」卡叫出來(含記錄檔路徑)。 + // 沒事時不顯示——否則「哪裡看 log」會變成常駐噪音,真出事時反而沒人看。 + st.EngineTrouble = !collectorAlive() + st.LogFolder = appDir() return st } @@ -543,6 +553,36 @@ func (a *App) SetAI(useGemini bool, key string) error { // OpenURL 用系統瀏覽器開網址(下載頁/說明文件)。 func (a *App) OpenURL(u string) { runtime.BrowserOpenURL(a.ctx, u) } +// OpenLogFolder 在檔案總管/Finder 裡打開記錄檔資料夾。 +// +// 🔴 leo 2026-08-06:「不能用一個 debug mode,就是它會把 log 寫在一個檔案?」 +// +// 答:**log 一直都有寫**(`~/.arcrun-rag/` 下的 collector.log 與 app.log, +// collector 的 stderr 也以 `[stderr]` 開頭落在裡面)。 +// 缺的不是「有沒有寫」,是**使用者找不到**——出事時他只看得到畫面上那句話, +// 沒有任何入口把他帶到檔案。這次 Windows 事故就卡在這:真正的死因 +// (config 缺 manifest)一直躺在 collector.log 裡,沒人看得到。 +// ⇒ 不做「debug mode 開關」(多一個要教使用者的東西),而是**永遠寫、一鍵打開**。 +func (a *App) OpenLogFolder() error { + dir := appDir() + if err := os.MkdirAll(dir, 0o755); err != nil { + return err + } + switch runtime2.GOOS { + case "windows": + // explorer 開啟後回傳非 0 是常態(它不等視窗關閉),所以不看 error。 + _ = exec.Command("explorer", dir).Start() + case "darwin": + return exec.Command("open", dir).Start() + default: + return exec.Command("xdg-open", dir).Start() + } + return nil +} + +// LogFolderPath 給畫面顯示用(讓使用者就算按鈕失效也知道去哪找)。 +func (a *App) LogFolderPath() string { return appDir() } + // ── 托盤會呼叫的兩個動作(t194)── // ShowWindow 把主視窗叫出來並帶到前景。 diff --git a/cmd/arcrun-app/frontend/src/main.js b/cmd/arcrun-app/frontend/src/main.js index 05f12ce..36d6da5 100644 --- a/cmd/arcrun-app/frontend/src/main.js +++ b/cmd/arcrun-app/frontend/src/main.js @@ -213,6 +213,7 @@ function renderPage() { function wire() { const on = (id, fn) => { const e = $(id); if (e) e.onclick = fn; }; on('uDocs', () => go.OpenURL('https://rag.arcrun.dev/docs/')); + on('hLogs', () => go.OpenLogFolder()); on('hAcct', showConnect); on('obConnect', showConnect); on('obInstall', () => go.OpenURL('https://install.arcrun.dev/')); on('aiSave', saveAI);