33 Commits

Author SHA1 Message Date
f13848cf0b fix(local-tool): workspace 推論面板跑版 — 右側面板固定寬度
右側 InferencePanel 沒設寬度也沒 shrink-0,被左側 CameraInferenceView
擠壓到只剩幾十 px,文字垂直排列。

修法:
- InferencePanel 外層加 w-80 shrink-0(固定 320px 不縮小)
- CameraInferenceView 外層加 min-w-0(允許 flex item 收縮到 0)
- gap-6 改 gap-4(省一點空間)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 23:36:20 +08:00
00192d3d1e fix(local-tool): yt-dlp / ffmpeg 找不到 — VISIONA_BUNDLE_BIN_DIR 加到 PATH
根因:Go 1.19+ Windows 的 exec.LookPath 不再搜尋 current directory,
而 exec.Command("yt-dlp") / exec.Command("ffmpeg") 只走 LookPath。
Wails app 有設 VISIONA_BUNDLE_BIN_DIR 環境變數指向 {app}\bin\,
但 server 的 deps/checker.go 只在 startup 檢查時用它,沒把它加到 PATH。

修法:server main.go 啟動時把 VISIONA_BUNDLE_BIN_DIR prepend 到 PATH。
這一次解決三個問題:
- yt-dlp: cannot run executable found relative to current directory
- ffmpeg 攝影機列舉找不到 ffmpeg binary
- ffmpeg camera capture 也找不到

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 23:32:02 +08:00
96dee565b3 fix(local-tool): 補上 Kneron KL520/KL720 韌體檔案
根因:KL520 在 USB Boot 模式下(fw=KDP2 Loader)需要先載入韌體到 RAM
才能接受模型載入。kneron_bridge.py connect 流程會自動呼叫
kp.core.load_firmware_from_file(),但前提是找到韌體檔案:
  scripts/firmware/KL520/fw_scpu.bin + fw_ncpu.bin
  scripts/firmware/KL720/fw_scpu.bin + fw_ncpu.bin

這些檔案在 M1 從 edge-ai-platform 搬程式碼時漏了,補入。
Makefile 的 payload-windows/linux/macos 的 cp -R server/scripts/
會自動帶入 firmware/ 子目錄。

KL520: scpu 51KB + ncpu 39KB
KL720: scpu 128KB + ncpu 2.0MB

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 23:11:47 +08:00
aa324cef42 fix(local-tool): flash 模型檔案找不到 — 相對路徑未解析
根因:models.json 的 filePath 是相對路徑("data/nef/kl520/xxx.nef"),
但 server working directory 是 {app}\bin\(app.go 設 cmd.Dir = binary 目錄),
所以 server 在 {app}\bin\data\nef\ 找 .nef 檔,找不到。

實際位置:{app}\data\nef\(installer 裝的位置),對應 server 的 --data-dir
由 Wails app 傳入的 %APPDATA%\visiona-local(或 fallback 到 <exe>/../data)。

修法:
- flash.NewService 新增 dataDir 參數
- StartFlash 中把相對 filePath 用 dataDir 拼接成絕對路徑:
  "data/nef/..." → 去掉 "data/" 前綴 → dataDir + "/nef/..."
- main.go 傳 dataDir 給 flash.NewService

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 22:03:28 +08:00
c24a04cdb2 fix(local-tool): Review minor m1/m2/m4 修復
m1(i18n 混用不一致):
- flash-dialog.tsx 所有英文字串改繁中(載入模型 / 選擇模型 / 硬體不相容 / 開始載入 / 關閉 / 完成)
- flash-progress.tsx 同理(模型載入失敗 / 重試 / 正在準備載入 / 模型載入完成)

m2(Dialog 關閉防護不完整):
- 改用 isInProgress 判斷(isFlashing || progress 未到 100%)+ 沒 error
  而非只看 isFlashing,涵蓋「API 回應了但 WS 進度還在跑」的情況

m4(WS 3 秒 timeout 應 reject):
- connectAndWait timeout 改 reject + Error message
- flash-dialog handleFlash 加 try/catch 捕捉 WS 連線失敗
  → 呼叫 setError 讓 UI 顯示錯誤而非靜默卡住

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 20:21:18 +08:00
3c6971febd fix(local-tool): Review M1-M4 + m5 修復 — flash 生命週期 + store 隔離
Review 問題修復:

M1(寫已關閉 channel panic):
- flash service goroutine 改成先等 driver.Flash() 返回,再寫 error 訊息,最後 close
- driver.Flash 返回後保證不再寫 progressCh,消除 race condition

M2(FlashTask 永不清除 memory leak):
- service.go 新增 CleanupTask(taskID) 公開方法
- device_handler.go 的 goroutine 在 `for range progressCh` 結束後呼叫 CleanupTask

M3(同裝置重複 flash taskID 衝突):
- ProgressTracker.Create 改成:舊 task 未完成時返回 nil
- StartFlash 檢查 nil → 回傳 "flash already in progress" 錯誤

M4(前端 flash store 全域不區分 deviceId):
- flash-store.ts 新增 activeDeviceId 欄位
- updateProgress 改接 (deviceId, progress),比對 activeDeviceId 防止混裝
- use-flash-progress.ts 的 WebSocket callback 傳入 deviceId

m5(flash_ws.go 雙重 conn.Close):
- read pump goroutine 移除 defer conn.Close(),由外層 defer 統一關閉

額外修復(S4):
- modelPath 為空時直接回 error 而非傳無效路徑給 driver

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 20:16:24 +08:00
44711753ae feat(local-tool): 推論功能完整搬入 — flash 模組 + workspace 推論介面
## 後端(Phase 1)
新增 flash 模組(從 edge-ai-platform 搬入):
- server/internal/flash/service.go:StartFlash + 模型相容性檢查 + 晶片 NEF 解析
- server/internal/flash/progress.go:Flash 進度追蹤器
- server/internal/api/ws/flash_ws.go:WebSocket 推送 flash 進度
- device_handler.go:新增 FlashDevice method + flashSvc 欄位
- router.go:新增 POST /api/devices/:id/flash + WS /ws/devices/:id/flash-progress
- main.go:初始化 flash.NewService 並傳入 router

推論/攝影機/MJPEG/inference WebSocket 之前 M1 已搬好,不需改動。
Python bridge (kneron_bridge.py) 與 edge-ai-platform 完全相同,不需改動。

## 前端 store + hooks(Phase 2)
- stores/flash-store.ts(新):Zustand store — startFlash / updateProgress / retryFlash / reset
- hooks/use-flash-progress.ts(新):WebSocket hook 接收 flash 進度

inference-store / camera-store / inference types / use-inference-stream / use-websocket
之前 M1 已搬好,不需改動。

## 前端 UI 元件(Phase 3)
- components/devices/flash-dialog.tsx(新):模型載入對話框 + 硬體相容性檢查
- components/devices/flash-progress.tsx(新):Flash 進度條 + 錯誤重試

camera-inference-view / camera-feed / camera-overlay / source-selector /
inference-panel / performance-metrics / classification-result / confidence-slider /
video-progress / batch-image-thumbnails 之前 M1 已搬好。

## 前端頁面整合(Phase 4)
- workspace/page.tsx:繁中硬編碼、顯示已載入模型名稱
- workspace/[deviceId]/workspace-client.tsx:加入 FlashDialog 按鈕 + 繁中硬編碼
- devices/[id]/device-detail-client.tsx:加入 FlashDialog + 「進入工作區」按鈕(模型已載入才顯示)
- device-card.tsx:已連線 + 模型已載入時顯示「工作區」快捷按鈕

## 使用者操作流程
裝置列表 → 連線 → 管理 → 載入模型 → 進入工作區 → 選攝影機/圖片/影片 → 開始推論 → 看 bounding box / FPS / latency
或:裝置列表 → 工作區(已有模型)→ 直接推論

## 不搬的東西
- cluster/* 全部不搬(已砍 cluster 功能)
- relay / tunnel 相關不搬

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 20:07:09 +08:00
819885c85d fix(local-tool): SPA fallback 改用 Next.js dynamic route shell HTML
根因:點模型卡片 → /models/yolov5-face-detection → server SPA fallback
固定回傳根路徑 /index.html(儀表板) → Next.js CSR router 初始化時
pathname 對不上 → 使用者被跳回儀表板。

修法:spaFallback handler 改成三層 fallback:
1. 精確檔案(/models/index.html 等)
2. Next.js dynamic route shell(把最後一段替換為 _ → /models/_/index.html)
   這是 generateStaticParams 產的 placeholder 頁面,Next.js CSR 會從 URL
   讀真正的 param 值
3. 根目錄 /index.html(最終 fallback)

這修好了:
- 模型詳情頁 /models/:id 不再跳回儀表板
- 裝置詳情頁 /devices/:id 同理
- 工作區裝置頁 /workspace/:deviceId 同理
- Sidebar active 狀態也會正確(因為 pathname 匹配了)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 19:44:25 +08:00
ebe86663b1 fix(local-tool): i18n type error — 用 devices.status.connecting/disconnecting
devices.connecting / devices.disconnecting 不在 TranslationDict type 裡,
改用已存在的 devices.status.connecting + 新增 devices.status.disconnecting。
刪掉上一個 commit 多加的頂層 devices.connecting / disconnecting key。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 19:11:36 +08:00
ae5dfe1739 fix(local-tool): 連線 loading + 資料目錄平台路徑 + 卡片排版
A. 連線 / 斷線按鈕加 loading state:
- device-store.ts 新增 connectingId / disconnectingId state
- connectDevice / disconnectDevice 用 try/finally 包裹確保 reset
- device-card.tsx 按鈕加 Loader2 spinner + disabled
  當任一裝置正在連線/斷線時所有按鈕都 disabled,防止連按
- i18n 新增 connecting / disconnecting 字串

C. 設定 > 一般 > 資料目錄顯示平台正確路徑:
- 用 navigator.userAgent 偵測平台
  - Windows: %APPDATA%\visiona-local
  - Linux: ~/.local/share/visiona-local
  - macOS: ~/Library/Application Support/visiona-local
- 修正 Python 版本顯示 3.11 → 3.12

D. 裝置卡片排版修正:
- 名稱和狀態 badge 之間加 gap-3
- 名稱區域 min-w-0 + truncate 防止 badge 被擠到換行
- 連線中時 badge 顯示 connecting 狀態

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 18:57:06 +08:00
9b0d946acd feat(local-tool): splash 顯示實時啟動進度 + 拉長 timeout + 修正執行模式顯示
Splash 進度:
- app.go 新增 bootstrapStatus field + GetBootstrapStatus() binding
- 各 startup step 呼叫 setBootstrapStatus 更新文字:
  "正在初始化 Python 環境..."
  "正在解壓 Python runtime (~10 秒)..."
  "正在建立 Python 虛擬環境 (~5 秒)..."
  "正在安裝 N 個 Python 套件 (numpy / opencv / KneronPLUS ...) (~30-60 秒)..."
  "正在安裝 Kneron USB 驅動程式 (請在 UAC 視窗點「是」)..."
  "正在準備應用程式資料..."
  "正在啟動伺服器..."
  "等待伺服器就緒..."
  "載入主介面..."
- visiona-local/frontend/app.js 每 400ms 呼叫 GetBootstrapStatus 更新畫面
- wailsjs/go/main/App.js 手動補上新 binding export(避免等 wails generate)

Timeout:
- splash MAX_WAIT_MS 60s → 240s(涵蓋 UAC 被拖延 + 慢速硬碟)
- healthCheckTimeout 15s → 30s(server 首次啟動內部解析 + embed fs 載入)

設定 > 硬體 > 執行模式:
- 顯示預設值從 mock 改為 real(跟 app.go 實際預設對齊 - Q8 決策)
- 下拉選單寬度 240 → 420px 避免文字被截斷
- i18n 說明文字改為「預設為真實硬體模式,強制 Mock 請設 VISIONA_MOCK=1」
- 仍標 disabled — 未來 M8+ 會連 backend GET /api/system/config

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 08:42:59 +08:00
3355a096b8 feat(local-tool): 首次啟動自動安裝 Kneron WinUSB driver
行為改變:Wails app 首次啟動會在 venv 就緒後、spawn server 前自動呼叫
libwdi 安裝 Kneron WinUSB driver。使用者不再需要手動點「安裝 USB Driver」
按鈕(按鈕保留供失敗後重試用)。

實作:
- startServer() step 1.5 新增 ensureDriverInstalled() 呼叫
- 用 <dataDir>/.driver-installed 記號檔避免每次啟動都彈 UAC
- 失敗不擋 server 啟動,只寫 log,使用者可稍後手動重試
- 新增 app-level log helper appLog() 寫到 <dataDir>/logs/wails.log
  (Wails Windows 以 windowsgui subsystem build,os.Stderr 指向 null device,
   沒有這個檔使用者看不到 startup 期間的 debug 訊息)
- 手動 InstallKneronDriver binding 成功時也寫記號檔

使用者移除 .driver-installed 檔就能強制重裝(例如 Windows 更新把 driver 弄壞時)。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 08:03:37 +08:00
d1ff55005a debug(local-tool): driver install verbose 輸出 + 安裝後自我驗證
- Python script 對每個 PID install 後 capture traceback,不再 swallow
- 裝完立刻 scan_devices() 驗證 SDK 能不能開 handle,印 is_connectable
- 安裝結果完整寫到 server.stderr.log(而不是只回錯誤摘要)
- 判斷 DONE 標記 + 至少一個 OK 才算成功

這讓我們能清楚看到 libwdi 到底是「沒權限 / DLL 載入失敗 / 綁定成功但
裝置 is_connectable 還是 False(代表 driver 層級 OK 但裝置需要重插)」
哪一種情境,而不是只看到籠統的「error 28」。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 07:38:43 +08:00
4902cb5531 feat(local-tool): Kneron WinUSB driver 透過 KneronPLUS SDK libwdi 安裝
根因:
  KP_ERROR_CONNECT_FAILED (error code 28) — Kneron USB 裝置預設沒綁定
  WinUSB driver,SDK 無法開 handle。原 .iss 的 pnputil /add-driver 做法
  需要 .cat 簽章(Windows 10/11 driver signing enforcement),我們沒有。

參考 edge-ai-platform/installer/platform_windows.go 的 installKneronDriverViaSDK:
  KneronPLUS SDK 內建 libwdi wrapper — kp.core.install_driver_for_windows(pid)
  libwdi 會自動用臨時自簽憑證,不需要 .cat 檔,只需要 UAC 提權。

實作:
- server/internal/api/handlers/system_driver_windows.go(新):
  組 Python script → kp.core.install_driver_for_windows 對 KL520/KL720/KL720_LEGACY →
  PowerShell Start-Process -Verb RunAs 提權執行 → 結果寫 temp 檔讀回
- server/internal/api/handlers/system_driver_other.go(新):非 Windows stub
- system_handler.go: NewSystemHandler 新增 pythonBin 參數 + InstallDriver handler
  先判斷 runtime.GOOS==windows 才執行
- router.go: 新增 POST /system/install-driver
- main.go: 解析 pythonBin(VISIONA_PYTHON env var → cfg.PythonBin)傳入

前端:
- frontend/src/app/devices/page.tsx:Windows only 多一個「安裝 USB Driver」按鈕
  (用 navigator.userAgent 判斷平台)
- frontend/src/stores/device-store.ts:connect 失敗訊息偵測 winusb / error 28 /
  KP_ERROR_CONNECT_FAILED 特徵字串,回一條明確的繁中提示引導使用者去點按鈕

Wails app 端:
- visiona-local/app.go: 新增 InstallKneronDriver() binding 作為備用入口(目前前端沒用到,
  因為前端跑在 http://127.0.0.1 不是 wails://,但保留給未來 splash 階段觸發用)
- visiona-local/platform_{windows,darwin,linux}.go: installKneronWinUSBDriver 平台實作
  / 跨平台 stub

.iss:
- 移除 pnputil /add-driver 的 [Run] entry(它是 silent-fail 的 dead code,
  因為沒 .cat 簽章)
- 新增註解說明:driver 安裝改由 app 端呼叫 libwdi 完成

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 05:25:32 +08:00
f8533a6b04 fix(local-tool): sidebar icon + Wails Windows icon.ico + 掃裝置路徑修復
sidebar E icon:
- frontend/src/components/layout/sidebar.tsx 左上角的 "E" 方塊換成 <img> 指向
  /visiona-logo.png,從 frontend/public/visiona-logo.png serve

Wails 桌面/工作列 icon:
- 把 branding/icon.ico 複製到 visiona-local/build/windows/icon.ico
- Wails v2 Windows build 偵測到這個檔案就會直接用它當 exe embedded icon,
  不再從 appicon.png 自動 resize(解析度更好)

掃裝置根因修復:
1. server main.go:新增 resolveBridgeScript() 智慧找 kneron_bridge.py
   - 優先 <exe>/scripts/kneron_bridge.py
   - fallback <exe>/../scripts/... 對應 Windows installer 的 {app}\bin\ + {app}\scripts\ 佈局
   - fallback <exe>/../Resources/scripts/... 對應 macOS app bundle

2. server kneron/detector.go:ResolvePython 重寫
   - 最高優先:VISIONA_PYTHON 環境變數(由 Wails 殼層注入)
   - 加入 visiona-local 新路徑:%APPDATA%\visiona-local\runtime\venv、
     ~/Library/Application Support/visiona-local/runtime/venv、
     ~/.local/share/visiona-local/runtime/venv
   - 保留 edge-ai-platform 舊路徑作為 legacy fallback

3. visiona-local/app.go:spawn server 時 export VISIONA_PYTHON=<pyBin>
   讓 detector 直接用 Wails 殼層已經 resolve 好的 python interpreter,
   不再自己獨立去找造成不一致。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 04:59:23 +08:00
50a3f73acd feat(local-tool): 品牌視覺設計 + 內建模型首次啟動 seed
#8 首次啟動 seed 內建模型:
- app.go 新增 seedUserDataDir() 在 server spawn 之前執行
- 若 user data-dir 缺 models.json,從 locateBundleDataDir() 複製
  models.json + nef/ 預置模型過去
- 新增 locateBundleDataDir() / copyFile() / copyDirRecursive() helper
- user 第一次開 app 會看到 8 個 Kneron 預置 .nef 模型(kl520×5 + kl720×3)

#5 #6 #7 品牌視覺:
- 新增 branding/ 目錄存放設計資產與生成工具
  - logo.svg(向量原始稿)
  - icon-{16,...,1024}.png(10 種尺寸)
  - icon.ico(Windows 多解析度 ICO,PNG-in-ICO 格式)
  - icon.icns(macOS)
  - tools/gen_icon.go + gen_ico.go(純 Go 生成工具,未來調整 logo 用)
  - README.md + 色票表
- 部署:
  - visiona-local/build/appicon.png → Wails build 會嵌入 exe
  - visiona-local/frontend/icon.png → splash 使用
  - frontend/src/app/favicon.ico + icon.png → Next.js App Router favicon
- splash page 升級:加 logo icon + 品牌名 visionA Local + tagline Edge AI Workspace
- Wails window title: "visionA Local — Edge AI Workspace"
- wails.json productName: "visionA Local"
- Next.js metadata title + icons
- i18n: en/zh-TW 把殘留的 "Edge AI 平台" 字串改為 visionA Local 品牌
- .iss: SetupIconFile 指向 branding/icon.ico + UninstallDisplayIcon +
  ArchitecturesAllowed 改 x64compatible 修掉之前的 deprecation warning

品牌色票:
- 主色 #4F7EFF(電子藍)
- 輔色 #6EF3C5(mint 點綴)
- 深色背景漸層 #1A1F36 → #0E1222
- 警示 #FF6B6B

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 04:42:41 +08:00
8e7b6ae435 feat(local-tool): clean build 為預設 + 藏 server 小黑窗 + 預設真實模式
Makefile:
- 新增 clean-all target:clean + wails build/ + frontend build/ + server embed
- 新增 clean-build-exe / clean-build-dmg / clean-build-appimage

bootstrap-windows.ps1:
- 預設改為 clean build(每次重做 wails + server binary + frontend embed)
- 保留 vendor/ 快取避免重下 200MB+ 第三方相依
- 需要 fast path(只重跑 iscc)時設 VISIONA_FAST=1

app.go:
- configureSysProcAttr() 注入子行程,Windows 下 CREATE_NO_WINDOW 藏掉 server 小黑窗
- 覆蓋 server spawn / tar 解壓 / venv 建立 / pip install 四個關鍵點
- mockMode 預設改 false(依使用者決策 Q8,預設走真實硬體模式)
  需要強制 mock 時設環境變數 VISIONA_MOCK=1

platform_{windows,darwin,linux}.go:
- 新增 configureSysProcAttr(cmd):Windows 設 HideWindow + CREATE_NO_WINDOW,
  macOS/Linux 空實作

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 04:25:09 +08:00
eb52f8c690 fix(local-tool): locateServerBinary 找 {app}\bin\ 子目錄(Windows/Linux installer 佈局)
根因:Windows installer 把 visiona-local-server.exe 裝到 {app}\bin\
      (.iss 的 DestDir: "{app}\bin"),但 locateServerBinary 只搜
      exeDir\visiona-local-server.exe 和 macOS bundle 專屬路徑,
      Windows/Linux 打包後的 bin/ 子目錄完全沒被搜尋,導致執行時
      "server binary not found" 嚴重錯誤。

修法:
- locateServerBinary 第一優先搜 exeDir\bin\visiona-local-server
  (Inno Setup installer / AppImage 的標準佈局)
- 開發模式 fallback 新增 payload/<goos>/bin/ 候選路徑
- 同時修正 locateBundleBinDir / locateBundledPythonAssets 的開發模式
  fallback 寫死 "payload/darwin",改用 runtime.GOOS 動態選 payload 子目錄

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 03:45:17 +08:00
83981e5b1b docs(local-tool): progress.md 記錄 M7 Windows 一鍵 build + splash regression
- 新增 M7-A:Windows 一鍵 build 工具鏈踩坑紀錄(11 項修好)
- 新增 M7-B:splash regression P0 修復(visiona-local/frontend 殘留 wizard → 改為 splash+redirect)
- 補「M1 驗收流程漏看 Wails 視窗內容」到未解決問題,作為後續 M 任務驗收 checklist
- 補 ffmpeg GPL release blocker 到未解決問題清單

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 03:35:20 +08:00
570e040a67 fix(local-tool): Wails 主視窗改為 splash + redirect 到 Next.js 主 UI
根因:visiona-local/frontend/ 是從 edge-ai-platform 複製過來的 installer wizard
HTML/JS/CSS,整組沒清理。main.go 的 //go:embed all:frontend 把這堆 wizard
直接當 Wails 主視窗內容,使用者開啟 app 看到的就是 "Edge AI Platform Installer"
而不是 Next.js 主 UI。macOS dmg 版本也有同樣問題,只是之前驗證時沒開 Wails
視窗而是用瀏覽器直連 localhost:3721 所以沒抓到。

修法:把 visiona-local/frontend/ 重寫為極簡 splash:
- index.html:splash 畫面
- app.js:import GetServerStatus / GetServerURL binding,輪詢直到 server ready,
  window.location.replace(url + '/') 跳到 Next.js 主 UI
- style.css:splash 樣式

Next.js 主 UI 不使用任何 Wails JS binding(純 HTTP API),所以從 wails://
跳到 http://127.0.0.1:<port>/ 後功能完整可用。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 03:32:31 +08:00
1c5866ed14 debug(local-tool): Windows build 失敗追蹤
Makefile _run-iscc:
- 開頭印出 ISCC 環境變數和 PATH 前幾項,確認有沒有正確傳進來

bootstrap-windows.ps1:
- 不再用 bash.exe -lc "..." 傳整條字串(含空格路徑會被 PS 雙層 quoting 切斷)
- 改寫成 tmp .sh 檔,用 bash.exe -l file.sh 執行
- 執行前印出 script 內容,執行後刪掉 tmp 檔
- script 開頭加 'set -e' 確保任何一行失敗立即停止並回非 0

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 03:17:07 +08:00
06031206af feat(local-tool): Windows build fast path + 產物驗證
Makefile:
- 新增 exe-only target:只跑 iscc 打包 installer,不重 build wails/payload
- 拆出 _run-iscc 共用 recipe,exe 和 exe-only 都依賴它

bootstrap-windows.ps1:
- 偵測 visiona-local.exe / server.exe / ffmpeg.exe / python.tar.gz 都在時走 fast path
  只跑 make exe-only,省掉重複 wails build 的數分鐘
- 跑完驗證 dist\visiona-local-*-windows-x64.exe 確實存在,否則明確 Fail 並提示手動 iscc 指令

使用情境:使用者刪掉 dist\ 想重打 installer,再跑一次 bootstrap 就能秒出 .exe

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 03:11:42 +08:00
4521ee3119 fix(local-tool): Inno Setup 6.3+ 不再內建 ChineseTraditional.isl
Inno Setup 6.3 起官方只保留 ChineseSimplified,繁體中文語系需額外下載。
改為以 WITH_TRAD_CHINESE 宏條件啟用,預設只用英文 installer UI,
避免在新版 Inno Setup 上直接 compile error。

這只影響「安裝精靈本身」的語系,應用程式 UI 的 i18n 不受影響。
未來若要帶繁體中文 installer,下載 istrans 檔案後用 iscc /DWITH_TRAD_CHINESE=1 編譯。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 02:45:51 +08:00
80252b12dc chore(local-tool): 為 make exe 加診斷輸出
印出 iscc 的 cwd、exit code、dist/ 實際內容,
避免靜默失敗讓人找不到產物去向。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 02:41:51 +08:00
dbad729da3 fix(local-tool): Inno Setup 偵測加入 user-scope 安裝路徑
winget 7.x 的 Inno Setup 可能裝到 %LOCALAPPDATA%\Programs\Inno Setup 6\
而非傳統的 Program Files (x86)。新增 user-scope 固定路徑 + HKCU 登錄檔 +
%LOCALAPPDATA%\Programs 遞迴掃描三種偵測方式。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 02:35:13 +08:00
e6f7afe8db fix(local-tool): 強化 Inno Setup 偵測,支援 ISCC 環境變數 override
Makefile (exe target):
- 新增 ISCC 環境變數 override(絕對路徑優先)
- 偵測順序:\$ISCC → command -v iscc → 已知絕對路徑
- 找不到時列出已嘗試路徑方便 debug

bootstrap-windows.ps1:
- Find-Iscc 函數改用多層策略:固定路徑 → 登錄檔 InstallLocation → Program Files 遞迴掃描
- 偵測不到就自動 winget --force 重裝再試一次
- 同時 export PATH 和 ISCC 雙保險傳給 Makefile

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 02:27:38 +08:00
634e4011fd fix(local-tool): bootstrap 把 Inno Setup 目錄加進 MSYS2 bash PATH
winget 裝的 Inno Setup 6 在 'C:\Program Files (x86)\Inno Setup 6\',
不在 PATH 裡,MSYS2 bash 找不到 iscc.exe 導致 make exe 失敗。
改由 bootstrap 主動偵測安裝路徑並 export 進 bash session PATH。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 02:23:37 +08:00
13ce654ac2 fix(local-tool): ffmpeg zip 下載改用相對路徑
Windows 版 python.exe 不懂 MSYS2 的 /tmp 路徑語法,會拿著字面值 '/tmp/...'
去 Windows filesystem 找不到檔案。改下載到 vendor/ffmpeg/windows/ffmpeg-win.zip
相對路徑,bash 跟 python 都看得懂。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 02:17:18 +08:00
a66fd5665b fix(local-tool): 繞過 Windows Store 的 python stub
- Makefile:vendor-wheels-windows / vendor-ffmpeg-windows 改用迴圈偵測真實 python
  排除 WindowsApps 路徑下的 Store alias stub,優先使用 VISIONA_PYTHON 環境變數
- Makefile:vendor-ffmpeg-windows 解壓完驗證檔案存在,失敗時 exit 1 而非靜默
- bootstrap-windows.ps1:主動找 winget 裝的真實 python.exe(LOCALAPPDATA / Program Files / py launcher),
  轉成 MSYS2 路徑後以 VISIONA_PYTHON 傳給 Makefile

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 02:11:16 +08:00
071964bddd fix(local-tool): Windows build 跨平台相容性修正
Makefile:
- vendor-wheels-windows 自動偵測 pip3/pip/python -m pip,MSYS2 bash 裡沒 pip3 也能跑
- vendor-ffmpeg-windows 改用 python zipfile 解壓,移除 unzip 依賴
- 新增 build-server-windows / build-server-linux 兩個 cross-build target
- payload-windows / payload-linux 改依賴對應的 build-server-*,不再只印警告

bootstrap-windows.ps1:
- 設定 MSYS2_PATH_TYPE=inherit,讓 MSYS2 bash 繼承 Windows PATH 找到 go/pnpm/python/wails

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 01:58:25 +08:00
ba15097e9d fix(local-tool): PowerShell 5.1 compatibility for bootstrap-windows.ps1
- 改用陣列 + -join ' && ' 組 bash 指令,避開 PS5.1 不支援 && 運算子
- 加入 UTF-8 BOM,避免 Windows 10 預設用 ANSI/Big5 解讀造成中文亂碼

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 01:44:06 +08:00
5a8d2797c2 chore(local-tool): rename local_tool → local-tool, add linux/windows bootstrap scripts
- 統一目錄名為 local-tool(連字號),修正所有文件中殘留的底線版本
- 新增 scripts/bootstrap-linux.sh 與 scripts/bootstrap-windows.ps1
  一鍵安裝依賴(Go/Node/pnpm/Wails/MSYS2)並執行 payload + installer build

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 23:23:29 +08:00
c54f16fca0 Initial commit: visionA monorepo with local-tool subproject
local-tool/: visionA-local desktop app
- M1: Wails shell + Go server + Next.js UI + Mock mode (macOS dmg ready)
- M2: i18n (zh-TW/en) + Settings 4-tab refactor
- M3: Embedded Python 3.12 runtime (python-build-standalone) + KneronPLUS wheels
- M4: Windows Inno Setup script (build on Windows runner)
- M5: Linux AppImage script + udev rule (build on Linux runner)
- M6: ffmpeg (GPL, pending legal review) + yt-dlp bundled
- Lifecycle: watchServer health check, fatal native dialog,
            Wails IPC raise endpoint, stale process cleanup

.autoflow/: full PRD / Design Spec / Architecture / Testing docs
            (4 rounds tri-party discussion + cross review)
.github/workflows/: macOS / Windows / Linux build CI

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 22:10:38 +08:00