diff --git a/console-ui/public/config.js b/console-ui/public/config.js
index dca204f..0ca6b7b 100644
--- a/console-ui/public/config.js
+++ b/console-ui/public/config.js
@@ -1,2 +1,6 @@
// Arcrun UI runtime 組態——改這一行就能切 API 目標,不必重新 build。
+// 可選 key(t72):
+// daemonDownload ── 同步小幫手 Mac 版 zip 網址(省略=用 index.html 內建的鏡像網址)
+// daemonDownloadWin ── Windows 版 zip 網址。**真機驗過、zip 上鏡像之後才填**;
+// 沒填時下載頁會誠實顯示「Windows 版封測驗證中」而不是給一個 404 連結。
window.ARCRUN_CONFIG = { apiBase: "https://cypher.arcrun.dev" };
diff --git a/console-ui/public/portal/index.html b/console-ui/public/portal/index.html
index d1669f4..a1d3aae 100644
--- a/console-ui/public/portal/index.html
+++ b/console-ui/public/portal/index.html
@@ -670,6 +670,35 @@ function taipeiMonthDay(ms) { var d = new Date(ms + TAIPEI_OFFSET_MS); return {
try { localStorage.setItem('arcrun_setup_steps', JSON.stringify(s)); } catch (e) { /* noop */ }
renderSetupChecklist();
}
+ // ── t72:下載頁依作業系統分流 ──────────────────────────────
+ // 原本寫死「下載 Mac 版」:Windows 用戶按下去會拿到一個 .app 的 zip,打不開也不知道為什麼。
+ // 認不出系統時**不猜**,兩個連結都給(同「按了連到錯的機制=不友善」判準)。
+ function detectOS() {
+ var uad = navigator.userAgentData; // Chromium 系最準(不受 UA 字串凍結影響)
+ var s = (((uad && uad.platform) || navigator.platform || '') + ' ' + (navigator.userAgent || '')).toLowerCase();
+ if (s.indexOf('win') >= 0) return 'win';
+ // iPadOS 會自稱 Macintosh:有多點觸控=平板,不給桌機安裝檔
+ if (s.indexOf('mac') >= 0 && !(navigator.maxTouchPoints > 1)) return 'mac';
+ return 'unknown'; // Linux/手機/認不出來
+ }
+ function osLabel(os) { return os === 'win' ? 'Windows ' : 'Mac '; }
+ function firstOpenHint(os) {
+ return os === 'win'
+ // 未簽章=SmartScreen 必攔一次。不解釋的話用戶會以為是病毒(t72 README 有完整文案)
+ ? '(封測版未簽章,Windows 會跳「已保護您的電腦」→ 點「其他資訊」→「仍要執行」)'
+ : '(封測版未簽章,第一次請右鍵→打開)';
+ }
+ function otherOsLine(os, macUrl, winUrl) {
+ var other = os === 'win' ? macUrl : winUrl;
+ var name = os === 'win' ? 'Mac' : 'Windows';
+ if (!other) {
+ return os === 'win' ? ''
+ : '
用 Windows?封測驗證中,做好會通知你。
';
+ }
+ return '';
+ }
+
function renderSetupChecklist() {
var old = document.getElementById('setup-checklist');
if (old) old.remove();
@@ -678,7 +707,12 @@ function taipeiMonthDay(ms) { var d = new Date(ms + TAIPEI_OFFSET_MS); return {
var s = setupSteps();
if (s.daemon && s.key) return; // t54 起只剩兩件:設定改由小幫手輸入帳密自取,不再下載檔案
var cfg = window.ARCRUN_CONFIG || {};
- var daemonUrl = cfg.daemonDownload || 'https://raw.githubusercontent.com/youlinhsieh/arcrun-rag-bundles/main/daemon/ArcrunRAG-mac-unsigned.zip';
+ var macUrl = cfg.daemonDownload || 'https://raw.githubusercontent.com/youlinhsieh/arcrun-rag-bundles/main/daemon/ArcrunRAG-mac-unsigned.zip';
+ // t72:Windows 版的下載點**還沒上鏡像**(交叉編譯已通、真機未驗)。
+ // 沒設 daemonDownloadWin 就不放連結——按下去 404 比沒有按鈕更傷(同下面「誠實降級」判準)。
+ var winUrl = cfg.daemonDownloadWin || '';
+ var os = detectOS();
+ var daemonUrl = os === 'win' ? winUrl : macUrl;
var row = function (done, id, html) {
return ''
+ '
' + (done ? '✅' : '⬜') + '' + html + '
';
@@ -690,12 +724,17 @@ function taipeiMonthDay(ms) { var d = new Date(ms + TAIPEI_OFFSET_MS); return {
+ row(s.daemon, 'daemon',
'下載同步小幫手(把資料夾變成知識庫)
'
+ (daemonUrl
- ? '下載 Mac 版'
- + '(封測版未簽章,第一次請右鍵→打開)'
+ ? '下載 ' + osLabel(os) + '版'
+ + '' + firstOpenHint(os) + ''
+ + otherOsLine(os, macUrl, winUrl)
// 誠實降級(leo 判準:按了連到錯的機制=不友善):沒有可用下載點時
// 不放死連結,說明現況並讓這步可手動打勾,不卡住清單。
- : '封測期由我們直接寄給你安裝檔(Mac 版);'
- + '收到後回來按 我已經裝好了。')
+ : ''
+ + (os === 'win'
+ ? 'Windows 版還在封測驗證中(做好會寄給你);先用 Mac 的話 '
+ + '下載 Mac 版,'
+ : '封測期由我們直接寄給你安裝檔;')
+ + '裝好後回來按 我已經裝好了。')
// t54(leo:「最好的就是把它的帳密直接輸入」):設定不再是一個要下載的檔案——
// 小幫手第一次開啟會問網址+帳密,自己去換設定。
+ '裝好第一次開啟時,貼上這個網址+你的帳號密碼就連上了,不用下載設定檔。
')
diff --git a/console-ui/test/portal-os-split.test.mjs b/console-ui/test/portal-os-split.test.mjs
new file mode 100644
index 0000000..3e9d43f
--- /dev/null
+++ b/console-ui/test/portal-os-split.test.mjs
@@ -0,0 +1,54 @@
+// t72 下載頁 OS 分流單測(2026-07-27):8 種 navigator 情境 → 分流結果。
+// 用法:node console-ui/test/portal-os-split.test.mjs
+// 直接從 index.html 抽最大的