Files
arcrun-rag-bundles-staging/tier2/ui/index.js
T
2026-08-26 08:00:50 +08:00

81 lines
706 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// arcrun-rag-ui — 用戶實例的 GUIconsole-ui/public 內嵌;由 Arcrun scripts/build-ui-worker.mjs 產生,勿手改)
const FILES = {"/apple-touch-icon.png":{"type":"image/png","b64":true,"data":"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"},"/console/dashboard/index.html":{"type":"text/html; charset=utf-8","b64":false,"data":"<!doctype html>\n<html lang=\"zh-Hant\">\n<head>\n<meta charset=\"utf-8\"/>\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>Arcrun 駕駛艙</title>\n<script>\n // 主題預載(防閃色):預設淺色(leo 2026-07-04 明示),與 /console 共用同一 localStorage key\n document.documentElement.setAttribute('data-theme', (function () {\n try { return localStorage.getItem('arcrun_console_theme') === 'dark' ? 'dark' : 'light'; } catch (e) { return 'light'; }\n })());\n</script>\n<style>\n /* Mira Console 定稿視覺(紙感「2a」,Mira Style Guide 2026-07-04):\n 紙紋底 repeating-linear-gradient、明體標題級聯、琥珀強調、呼吸狀態球嵌單字。\n 2026-07-04 二輪:CSS custom properties 兩份色板——預設淺色(宣紙米白+墨字),深色=原定稿暖黑不動。 */\n * { box-sizing: border-box; }\n :root {\n --paper-a: #f4eddc; --paper-b: #f1e9d6;\n --ink: #2f2a20; --ink-rgb: 30,24,14;\n --amber: #8a5f1e; --amber-rgb: 138,95,30;\n --ok: #1d7a48; --ok-rgb: 29,122,72;\n --err: #b03a26; --err-rgb: 176,58,38;\n --track: rgba(30,24,14,.12);\n }\n :root[data-theme=\"dark\"] {\n --paper-a: #191410; --paper-b: #1b1611;\n --ink: #ede4d3; --ink-rgb: 237,228,211;\n --amber: #e8b45a; --amber-rgb: 232,180,90;\n --ok: #7fe0a8; --ok-rgb: 63,190,120;\n --err: #e58575; --err-rgb: 217,95,76;\n --track: rgba(255,255,255,.08);\n }\n html, body { margin: 0; background: repeating-linear-gradient(0deg,var(--paper-a) 0px,var(--paper-a) 3px,var(--paper-b) 3px,var(--paper-b) 4px); color: var(--ink);\n font-family: -apple-system, \"PingFang TC\", \"Microsoft JhengHei\", system-ui, sans-serif; font-size: 16px; -webkit-font-smoothing: antialiased; }\n .serif { font-family: 'Songti TC','LiSong Pro',PMingLiU,serif; }\n main { max-width: 560px; margin: 0 auto; padding: 0 20px 40px; }\n .pagehead { padding: 22px 2px 14px; border-bottom: 2px solid rgba(var(--amber-rgb),.4); display: flex; justify-content: space-between; align-items: baseline; }\n .pagehead .title { font-family: 'Songti TC','LiSong Pro',PMingLiU,serif; font-size: 23px; letter-spacing: .2em; }\n .pagehead .title small { font-size: 14px; letter-spacing: .3em; color: rgba(var(--ink-rgb),.5); }\n .pagehead .date { font-family: 'Songti TC','LiSong Pro',PMingLiU,serif; font-size: 14px; color: rgba(var(--ink-rgb),.55); }\n .orb-row { display: flex; align-items: center; gap: 20px; padding: 26px 2px 20px; }\n .orb { width: 84px; height: 84px; border-radius: 50%; flex: none; display: grid; place-items: center; }\n .orb span { font-family: 'Songti TC','LiSong Pro',PMingLiU,serif; font-size: 30px; font-weight: 600; color: rgba(10,20,14,.85); text-shadow: 0 1px 0 rgba(255,255,255,.25); }\n .orb-title { font-family: 'Songti TC','LiSong Pro',PMingLiU,serif; font-size: 23px; font-weight: 600; }\n .orb-sub { margin-top: 5px; font-size: 15px; color: rgba(var(--ink-rgb),.6); line-height: 1.55; }\n @keyframes breatheGreen { 0%,100% { box-shadow: 0 0 24px 6px rgba(var(--ok-rgb),.35); } 50% { box-shadow: 0 0 42px 14px rgba(var(--ok-rgb),.55); } }\n @keyframes breatheAmber { 0%,100% { box-shadow: 0 0 24px 6px rgba(var(--amber-rgb),.35); } 50% { box-shadow: 0 0 42px 14px rgba(var(--amber-rgb),.6); } }\n @keyframes breatheRed { 0%,100% { box-shadow: 0 0 24px 6px rgba(var(--err-rgb),.4); } 50% { box-shadow: 0 0 44px 16px rgba(var(--err-rgb),.65); } }\n .bricks { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }\n .brick { padding: 16px; border-radius: 12px; }\n .brick.amber { background: rgba(var(--amber-rgb),.07); border: 1px solid rgba(var(--amber-rgb),.22); }\n .brick.plain { background: rgba(var(--ink-rgb),.04); border: 1px solid rgba(var(--ink-rgb),.14); }\n .brick .lbl { font-size: 13.5px; color: rgba(var(--ink-rgb),.55); margin-bottom: 6px; }\n .brick .num { font-family: ui-monospace, Menlo, monospace; font-size: 26px; color: var(--amber); }\n .brick .num small { font-size: 15px; color: rgba(var(--ink-rgb),.5); }\n .bar { margin-top: 10px; height: 6px; border-radius: 3px; background: var(--track); }\n .bar > i { display: block; height: 100%; border-radius: 3px; background: linear-gradient(90deg,#b98330,#e8b45a); transition: width .6s; }\n .wait-box { margin-top: 14px; padding: 20px; border-radius: 12px; border: 1px dashed rgba(var(--ok-rgb),.3); background: rgba(var(--ok-rgb),.05); }\n .wait-box.has { border-color: rgba(var(--amber-rgb),.45); background: rgba(var(--amber-rgb),.05); }\n .wait-head { font-family: 'Songti TC','LiSong Pro',PMingLiU,serif; font-size: 16px; letter-spacing: .2em; color: rgba(var(--ink-rgb),.6); margin-bottom: 10px; text-align: center; }\n .wait-none { font-family: 'Songti TC','LiSong Pro',PMingLiU,serif; font-size: 20px; color: var(--ok); letter-spacing: .08em; text-align: center; }\n .wait-item { display: flex; align-items: center; gap: 12px; padding: 12px 14px; margin-top: 8px; border-radius: 10px; background: rgba(var(--amber-rgb),.1); border: 1px solid rgba(var(--amber-rgb),.3); font-size: 16px; line-height: 1.5; }\n .wait-item .dm { color: var(--amber); font-size: 17px; flex: none; }\n .wait-meta { margin-top: 10px; text-align: center; font-size: 12.5px; color: rgba(var(--ink-rgb),.45); line-height: 1.7; }\n .wait-meta .warn { color: var(--err); }\n .subhead { display: flex; justify-content: space-between; align-items: baseline; margin: 24px 0 10px; }\n .subhead .t { font-family: 'Songti TC','LiSong Pro',PMingLiU,serif; font-size: 16px; letter-spacing: .2em; color: rgba(var(--ink-rgb),.6); }\n .subhead .m { font-size: 13px; color: rgba(var(--ink-rgb),.4); }\n ul.route { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }\n ul.route li { display: flex; align-items: flex-start; gap: 12px; padding: 13px 16px; border-radius: 11px; background: rgba(var(--ink-rgb),.045); border: 1px solid transparent; font-size: 16px; line-height: 1.4; }\n ul.route li.doing { background: rgba(var(--amber-rgb),.09); border-color: rgba(var(--amber-rgb),.3); }\n ul.route li .ic { flex: none; font-size: 15px; margin-top: 2px; }\n ul.route li.done { color: rgba(var(--ink-rgb),.65); }\n ul.route li.done .ic { color: var(--ok); }\n ul.route li.doing .ic { color: var(--amber); }\n ul.route li.todo { color: rgba(var(--ink-rgb),.6); }\n ul.route li.todo .ic { color: rgba(var(--ink-rgb),.35); }\n ul.route li.blocked .ic { color: var(--err); }\n ul.route.faded li { opacity: .55; }\n .sys { margin-top: 6px; display: flex; flex-direction: column; gap: 6px; }\n .sys .row { display: flex; justify-content: space-between; align-items: baseline; padding: 10px 14px; border-radius: 10px; background: rgba(var(--ink-rgb),.04); border: 1px solid rgba(var(--ink-rgb),.12); font-size: 14.5px; }\n .sys .row .k { color: rgba(var(--ink-rgb),.6); }\n .sys .row .v { font-family: ui-monospace, Menlo, monospace; font-size: 14px; }\n .sys .ok { color: var(--ok); }\n .sys .bad { color: var(--err); }\n .sys .off { color: rgba(var(--ink-rgb),.5); }\n .muted { color: rgba(var(--ink-rgb),.45); font-size: 14px; }\n .err { color: var(--err); font-size: 14px; }\n .stamp { margin: 16px 0 8px; text-align: center; font-size: 12.5px; color: rgba(var(--ink-rgb),.35); line-height: 1.8; }\n .enter { display: block; text-align: center; font-size: 13.5px; color: rgba(var(--amber-rgb),.75); text-decoration: none; margin-top: 6px; }\n .theme-btn { flex: none; margin-left: 12px; width: 34px; height: 34px; border-radius: 50%; border: 1px solid rgba(var(--ink-rgb),.25); background: none; color: rgba(var(--ink-rgb),.65); font-size: 16px; cursor: pointer; line-height: 1; align-self: center; }\n</style>\n<script src=\"/config.js\"></script>\n<script>\n// 2026-08-01arcrun-rag#10 同族):拔掉寫死中央位址的 fallback。\n// apiBase 由 worker 動態產生的 /config.js 注入;缺它就讓它明顯壞掉,\n// **不要靜默把請求(可能含金鑰)送去中央實例**。\nwindow.ARCRUN_API_BASE = (window.ARCRUN_CONFIG && window.ARCRUN_CONFIG.apiBase) || \"\";\n</script>\n</head>\n<body>\n<main>\n <div class=\"pagehead\">\n <div class=\"title serif\">Arcrun<small> 駕駛艙</small></div>\n <div style=\"display:flex;align-items:baseline\">\n <div class=\"date serif\" id=\"date-str\"></div>\n <button class=\"theme-btn\" id=\"theme-btn\" title=\"切換深/淺色\">☾</button>\n </div>\n </div>\n <div class=\"orb-row\">\n <div class=\"orb\" id=\"orb\" style=\"background:radial-gradient(circle at 36% 30%,#8fe8b4,#3fbe78 55%,#22754a 100%)\"><span id=\"orb-char\">…</span></div>\n <div>\n <div class=\"orb-title\" id=\"orb-title\">載入中</div>\n <div class=\"orb-sub\" id=\"orb-sub\"></div>\n </div>\n </div>\n <div class=\"bricks\">\n <div class=\"brick amber\">\n <div class=\"lbl\">今日完成</div>\n <div class=\"num\"><span id=\"done-n\"></span><small> / <span id=\"total-n\"></span> 件</small></div>\n <div class=\"bar\"><i id=\"bar-fill\" style=\"width:0%\"></i></div>\n </div>\n <div class=\"brick plain\">\n <div class=\"lbl\">收件匣未處理</div>\n <div class=\"num\"><span id=\"inbox-n\"></span><small> 條</small></div>\n <div class=\"lbl\" style=\"margin:10px 0 0\">來自 Telegram</div>\n </div>\n </div>\n <div class=\"wait-box\" id=\"wait-box\">\n <div class=\"wait-head\">等你的事</div>\n <div id=\"wait-body\" class=\"wait-none\">載入中…</div>\n <div class=\"wait-meta\" id=\"wait-meta\"></div>\n </div>\n <div class=\"subhead\"><span class=\"t\">今日路線</span><span class=\"m\" id=\"route-m\"></span></div>\n <ul class=\"route\" id=\"today-list\"><li class=\"todo\"><span class=\"ic\">○</span>載入中…</li></ul>\n <div class=\"subhead\" id=\"week-head\" style=\"display:none\"><span class=\"t\">本週</span></div>\n <ul class=\"route\" id=\"week-list\"></ul>\n <div class=\"subhead\"><span class=\"t\">系統狀況</span><span class=\"m\">live 健康信號</span></div>\n <div class=\"sys\" id=\"sys-list\"><div class=\"row\"><span class=\"k\">載入中…</span></div></div>\n <div class=\"stamp\" id=\"stamp\">每 60 秒自動刷新</div>\n <a class=\"enter\" href=\"/console\">進入完整控制台 </a>\n</main>\n<script>\n(function () {\n var API_BASE = window.ARCRUN_API_BASE || '';\n // 台北時間 helperlib/taipei-time.ts 注入,與 server 判定同一套——顯示不隨看的裝置時區漂移)\n var TAIPEI_OFFSET_MS = 28800000; // UTC+8,台北無 DST\nfunction tpePad(n) { n = String(n); return n.length < 2 ? '0' + n : n; }\nfunction taipeiDayKey(ms) { return new Date(ms + TAIPEI_OFFSET_MS).toISOString().slice(0, 10); }\nfunction taipeiDateStr(ms) { return taipeiDayKey(ms); }\nfunction taipeiDateTimeStr(ms) { var d = new Date(ms + TAIPEI_OFFSET_MS); return taipeiDayKey(ms) + ' ' + tpePad(d.getUTCHours()) + ':' + tpePad(d.getUTCMinutes()); }\nfunction taipeiTimeStr(ms) { var d = new Date(ms + TAIPEI_OFFSET_MS); return tpePad(d.getUTCHours()) + ':' + tpePad(d.getUTCMinutes()) + ':' + tpePad(d.getUTCSeconds()); }\nfunction taipeiMonthDay(ms) { var d = new Date(ms + TAIPEI_OFFSET_MS); return { month: d.getUTCMonth() + 1, day: d.getUTCDate() }; }\n const $ = (id) => document.getElementById(id);\n const LIGHT = {\n green: { ch: '安', title: '系統運轉中', grad: 'radial-gradient(circle at 36% 30%,#8fe8b4,#3fbe78 55%,#22754a 100%)', anim: 'breatheGreen' },\n yellow: { ch: '趕', title: '落後趕工中', grad: 'radial-gradient(circle at 36% 30%,#f2d194,#e8b45a 55%,#8a5f1e 100%)', anim: 'breatheAmber' },\n red: { ch: '滯', title: '卡住或斷訊', grad: 'radial-gradient(circle at 36% 30%,#f0a094,#d95f4c 55%,#7e2c20 100%)', anim: 'breatheRed' }\n };\n const ICONS = { done: '✓', doing: '◐', todo: '○', blocked: '●' };\n function esc(s) {\n return String(s ?? '').replace(/[&<>\"']/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' }[c]));\n }\n function taskLine(t) {\n const cls = ICONS[t.status] ? t.status : 'blocked';\n const ic = ICONS[t.status] || '●';\n return '<li class=\"' + cls + '\"><span class=\"ic\">' + ic + '</span><span>' + esc(t.title) + '</span></li>';\n }\n function humanAge(m) {\n if (m == null || m < 0) return '時間不明';\n if (m < 60) return m + ' 分鐘前';\n if (m < 2880) return Math.round(m / 60) + ' 小時前';\n return Math.round(m / 1440) + ' 天前';\n }\n const CNUM = ['零','一','二','三','四','五','六','七','八','九','十'];\n function cnDay(n) { return n <= 10 ? CNUM[n] : (n < 20 ? '十' + (n % 10 ? CNUM[n % 10] : '') : CNUM[Math.floor(n / 10)] + '十' + (n % 10 ? CNUM[n % 10] : '')); }\n // 頁首日期=台北日(原本用瀏覽器本地時區,換裝置會漂)\n const nowTpe = taipeiMonthDay(Date.now());\n $('date-str').textContent = CNUM[nowTpe.month] + '月' + cnDay(nowTpe.day) + '日';\n // 深/淺切換(與 /console 共用 arcrun_console_theme;預設淺色)\n function syncThemeBtn() { $('theme-btn').textContent = document.documentElement.getAttribute('data-theme') === 'dark' ? '☀' : '☾'; }\n $('theme-btn').addEventListener('click', () => {\n const next = document.documentElement.getAttribute('data-theme') === 'dark' ? 'light' : 'dark';\n document.documentElement.setAttribute('data-theme', next);\n try { localStorage.setItem('arcrun_console_theme', next); } catch (e) { /* 私密模式忽略 */ }\n syncThemeBtn();\n });\n syncThemeBtn();\n // fetch 失敗(斷網)的裸訊息 → 友善誠實文案;60 秒定時器常駐,網路恢復自動刷回\n function friendlyErr(e) {\n const m = e && e.message ? String(e.message) : String(e);\n return /failed to fetch|load failed|networkerror|network request failed/i.test(m) ? '連線中斷' : m;\n }\n function sysRow(k, v, cls) {\n return '<div class=\"row\"><span class=\"k\">' + esc(k) + '</span><span class=\"v ' + cls + '\">' + esc(v) + '</span></div>';\n }\n async function load() {\n try {\n const res = await fetch(API_BASE + '/console/dashboard-data');\n if (!res.ok) throw new Error('HTTP ' + res.status);\n const d = await res.json();\n const cfg = LIGHT[d.light] || LIGHT.green;\n const orb = $('orb');\n orb.style.background = cfg.grad;\n orb.style.animation = cfg.anim + ' 3.4s ease-in-out infinite';\n $('orb-char').textContent = cfg.ch;\n $('orb-title').textContent = cfg.title;\n $('orb-sub').textContent = (d.last_beat\n ? d.last_beat.actor + '・' + d.last_beat.ago_minutes + ' 分鐘前' + (d.last_beat.note ? '・' + d.last_beat.note : '')\n : '尚無心跳資料') + (d.light !== 'green' && d.light_reason ? '' + d.light_reason + '' : '');\n const done = d.today_done || 0, total = d.today_total || 0;\n $('done-n').textContent = done; $('total-n').textContent = total;\n $('bar-fill').style.width = (total ? Math.round((done / total) * 100) : 0) + '%';\n $('inbox-n').textContent = d.inbox_new || 0;\n // ── 等你的事:來源 + 維護時間攤開講,stale 一定警示 ──\n const wb = $('wait-box'), body = $('wait-body'), wmeta = $('wait-meta');\n const wm = d.waiting_meta || {};\n if (d.waiting && d.waiting.length) {\n wb.classList.add('has');\n body.className = '';\n body.innerHTML = d.waiting.map((w) =>\n '<div class=\"wait-item\"><span class=\"dm\">' + (w.urgency ? esc(w.urgency) : '◆') + '</span><span>' +\n (w.id ? '<b>#' + esc(w.id) + '</b> ' : '') + esc(w.title) + '</span></div>').join('');\n } else {\n wb.classList.remove('has');\n body.className = 'wait-none';\n body.textContent = wm.source === 'none' ? '(管線未接)' : '無,你不用做任何事';\n }\n let metaTxt = '';\n if (wm.source === 'gitea_sprint') {\n metaTxt = '來源:sprint 等leo清單(' + esc((wm.sprint_files || []).join('、')) + ')・清單維護於 ' + humanAge(wm.updated_ago_minutes);\n if (wm.stale) metaTxt += '<br><span class=\"warn\">⚠ 清單超過 2 天沒維護,可能過時</span>';\n } else if (wm.source === 'kbdb_dash_wait') {\n metaTxt = '<span class=\"warn\">⚠ ' + esc(wm.note || 'dash_wait 殘資料') + '・上次寫入 ' + humanAge(wm.updated_ago_minutes) + ',可能過時</span>';\n } else {\n metaTxt = '<span class=\"warn\">管線未接:Gitea sprint 清單與 dash_wait 皆無資料</span>';\n }\n wmeta.innerHTML = metaTxt;\n // ── 今日路線:sprint 任務板優先(來源攤開講);dash_task fallback 沿舊誠實降級 ──\n const rm = d.route_meta || {};\n const today = (d.tasks || []).filter((t) => t.scope === 'today');\n const week = (d.tasks || []).filter((t) => t.scope === 'week');\n if (rm.source === 'gitea_sprint_board') {\n $('route-m').textContent = '來源 sprint 任務板・更新於 ' + humanAge(rm.updated_ago_minutes);\n $('today-list').className = 'route';\n const staleHead = rm.is_today ? '' :\n '<li class=\"todo\"><span class=\"ic\">○</span><span class=\"muted\">⚠ 今日任務板未更新(最後 ' + humanAge(rm.updated_ago_minutes) + ')——以下是板上現況</span></li>';\n $('today-list').innerHTML = staleHead + (today.length\n ? today.map(taskLine).join('')\n : '<li class=\"todo\"><span class=\"ic\">○</span><span class=\"muted\">任務板上沒有可解析的事項</span></li>');\n } else if (rm.is_today) {\n $('route-m').textContent = '更新於 ' + humanAge(rm.updated_ago_minutes);\n $('today-list').className = 'route';\n $('today-list').innerHTML = today.length ? today.map(taskLine).join('') : '<li class=\"todo\"><span class=\"ic\">○</span><span class=\"muted\">今日無排定項目</span></li>';\n } else if (today.length) {\n $('route-m').textContent = '最後路線・' + humanAge(rm.updated_ago_minutes) + '寫入';\n $('today-list').className = 'route faded';\n $('today-list').innerHTML =\n '<li class=\"todo\"><span class=\"ic\">○</span><span class=\"muted\">今日尚無路線寫入——以下是 ' + humanAge(rm.updated_ago_minutes) +\n '的殘留路線(sprint 任務板→dashboard 投影管線未接,等leo清單#15 裁決中)</span></li>' + today.map(taskLine).join('');\n } else {\n $('route-m').textContent = '';\n $('today-list').className = 'route';\n $('today-list').innerHTML = '<li class=\"todo\"><span class=\"ic\">○</span><span class=\"muted\">無資料——dash_task 管線未接</span></li>';\n }\n $('week-head').style.display = week.length ? '' : 'none';\n $('week-list').innerHTML = week.map(taskLine).join('');\n // ── 系統狀況 + 總庫規模(全 live,讀不到就標讀不到)──\n const sys = d.system || {}, kb = d.kb || {};\n const rows = [];\n rows.push(sysRow('KBDB 基本盤', sys.kbdb_ok ? '● 正常' : '● 打不通', sys.kbdb_ok ? 'ok' : 'bad'));\n if (sys.embed) {\n rows.push(sys.embed.enabled\n ? sysRow('語意嵌入', '● 啟用(已嵌 ' + (sys.embed.embedded ?? '?') + '・待嵌 ' + (sys.embed.pending ?? '?') + '', 'ok')\n : sysRow('語意嵌入', '○ 停用(已嵌 ' + (sys.embed.embedded ?? '?') + '・待嵌 ' + (sys.embed.pending ?? '?') + '', 'bad'));\n } else {\n rows.push(sysRow('語意嵌入', '狀態讀不到', 'off'));\n }\n // Arcrun#100:「服務活著嗎」與「庫裡有幾條」拆兩列。混一列時,圖服務打不通會把\n // 「其實有 1854 條」整個吞掉,畫面看起來就像知識庫是空的。數字讀不到寫「讀不到」,不寫 0。\n var gOk = !!(sys.graph && sys.graph.ok);\n var tri = sys.graph && sys.graph.triplets != null ? sys.graph.triplets : null;\n rows.push(sysRow('知識圖譜服務', gOk ? '● 正常' : '● 打不通', gOk ? 'ok' : 'bad'));\n rows.push(sysRow('三元組(關聯)', tri == null ? '讀不到' : tri.toLocaleString() + ' 條', tri == null ? 'off' : ''));\n rows.push(sysRow('工作流', sys.workflow_total == null ? '讀不到' : sys.workflow_total + ' 條', sys.workflow_total == null ? 'off' : ''));\n // 精耕層 wiki 卡(leo 2026-07-07 裁:14-E 遺產總數 deprecated 不再顯示,只顯示真的新的;\n // 三元組/已嵌入 已各有一列)\n rows.push(sysRow('精耕層 wiki 卡', kb.wiki_card_total == null ? '讀不到' : kb.wiki_card_total + ' 張', kb.wiki_card_total == null ? 'off' : ''));\n $('sys-list').innerHTML = rows.join('');\n $('stamp').innerHTML = '每 60 秒自動刷新・上次 ' + esc(taipeiTimeStr(Date.parse(d.generated_at))) + '(台北)<br>此頁不含機敏內容,免登入';\n } catch (e) {\n $('orb-char').textContent = '';\n $('orb-title').textContent = '讀不到狀態';\n $('orb-sub').innerHTML = '<span class=\"err\">' + esc(friendlyErr(e)) + '・每 60 秒自動重試</span>';\n }\n }\n load();\n setInterval(load, 60000);\n})();\n</script>\n</body>\n</html>\n"},"/console/index.html":{"type":"text/html; charset=utf-8","b64":false,"data":"<!doctype html>\n<html lang=\"zh-Hant\">\n<head>\n<meta charset=\"utf-8\"/>\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>Arcrun Console</title>\n<script>\n // 主題預載(防閃色):預設淺色(leo 2026-07-04 明示),選擇存 localStorage\n document.documentElement.setAttribute('data-theme', (function () {\n try { return localStorage.getItem('arcrun_console_theme') === 'dark' ? 'dark' : 'light'; } catch (e) { return 'light'; }\n })());\n</script>\n<style>\n * { box-sizing: border-box; }\n /* ── 主題色板(一套結構兩份色值):預設淺色=宣紙米白紙紋+墨色文字;深色=定稿紙感暖黑 2a 原值不動 ── */\n :root {\n --paper-a: #f4eddc; --paper-b: #f1e9d6; /* 宣紙米白紙紋 */\n --ink: #2f2a20; --ink-rgb: 30,24,14; /* 墨色文字 */\n --amber: #8a5f1e; --amber-rgb: 138,95,30; /* 琥珀沿用、調深到淺底可讀 */\n --ok: #1d7a48; --ok-rgb: 29,122,72; --ok-soft: #1d6b40;\n --err: #b03a26; --err-rgb: 176,58,38;\n --well: rgba(30,24,14,.06); --well2: rgba(30,24,14,.08);\n --bar-bg: #efe7d3; --track: rgba(30,24,14,.12); --knob: #ffffff;\n }\n :root[data-theme=\"dark\"] {\n --paper-a: #191410; --paper-b: #1b1611;\n --ink: #ede4d3; --ink-rgb: 237,228,211;\n --amber: #e8b45a; --amber-rgb: 232,180,90;\n --ok: #7fe0a8; --ok-rgb: 63,190,120; --ok-soft: #a8e8c4;\n --err: #e58575; --err-rgb: 217,95,76;\n --well: rgba(0,0,0,.25); --well2: rgba(0,0,0,.3);\n --bar-bg: #17120e; --track: rgba(255,255,255,.08); --knob: #ede4d3;\n }\n html, body { margin: 0; background: repeating-linear-gradient(0deg,var(--paper-a) 0px,var(--paper-a) 3px,var(--paper-b) 3px,var(--paper-b) 4px); color: var(--ink);\n font-family: -apple-system, \"PingFang TC\", \"Microsoft JhengHei\", system-ui, sans-serif; font-size: 16px; -webkit-font-smoothing: antialiased; }\n input, textarea, button { font-family: inherit; }\n ::placeholder { color: rgba(var(--ink-rgb),.35); }\n input:focus, textarea:focus { outline: 2px solid rgba(var(--amber-rgb),.5); outline-offset: 1px; }\n a { color: var(--amber); }\n .serif { font-family: 'Songti TC','LiSong Pro',PMingLiU,serif; }\n .mono { font-family: ui-monospace, Menlo, monospace; }\n .muted { color: rgba(var(--ink-rgb),.55); }\n .dim { color: rgba(var(--ink-rgb),.4); }\n .err { color: var(--err); }\n .ok { color: var(--ok); }\n @keyframes breatheGreen { 0%,100% { box-shadow: 0 0 24px 6px rgba(var(--ok-rgb),.35); } 50% { box-shadow: 0 0 42px 14px rgba(var(--ok-rgb),.55); } }\n @keyframes breatheAmber { 0%,100% { box-shadow: 0 0 24px 6px rgba(var(--amber-rgb),.35); } 50% { box-shadow: 0 0 42px 14px rgba(var(--amber-rgb),.6); } }\n @keyframes breatheRed { 0%,100% { box-shadow: 0 0 24px 6px rgba(var(--err-rgb),.4); } 50% { box-shadow: 0 0 44px 16px rgba(var(--err-rgb),.65); } }\n\n /* ── auth 全屏 ── */\n .authwrap { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 24px; }\n .authbox { width: 100%; max-width: 400px; display: flex; flex-direction: column; gap: 24px; text-align: center; }\n .brand { font-family: 'Songti TC','LiSong Pro',PMingLiU,serif; font-size: 44px; letter-spacing: .24em; color: var(--amber); }\n .brand-sub { margin-top: 10px; font-size: 15px; color: rgba(var(--ink-rgb),.55); letter-spacing: .1em; }\n\n /* ── 版面骨架 ── */\n #shell { display: none; min-height: 100vh; }\n #shell.on { display: flex; }\n #sidenav { display: none; }\n main { flex: 1; min-width: 0; padding-bottom: 96px; }\n .page { max-width: 980px; margin: 0 auto; padding: 0 20px 40px; }\n .page.narrow { max-width: 760px; }\n .page.wide { max-width: 1080px; }\n .pagehead { padding: 22px 2px 14px; border-bottom: 2px solid rgba(var(--amber-rgb),.4); display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }\n .pagehead .t { font-family: 'Songti TC','LiSong Pro',PMingLiU,serif; font-size: 23px; letter-spacing: .2em; white-space: nowrap; }\n .pagehead .m { font-size: 13.5px; color: rgba(var(--ink-rgb),.45); }\n #tabbar { position: fixed; left: 0; right: 0; bottom: 0; background: var(--bar-bg); border-top: 2px solid rgba(var(--amber-rgb),.4); display: none; z-index: 50; padding-bottom: env(safe-area-inset-bottom); }\n #tabbar.on { display: flex; }\n #tabbar .tab { flex: 1; text-align: center; padding: 15px 0 13px; font-size: 14.5px; cursor: pointer; min-height: 44px; color: rgba(var(--ink-rgb),.5); border-top: 2px solid transparent; margin-top: -2px; }\n #tabbar .tab.on { color: var(--amber); font-weight: 600; border-top-color: var(--amber); }\n @media (min-width: 1024px) {\n #tabbar.on { display: none; }\n main { padding-bottom: 20px; }\n #sidenav { display: flex; width: 216px; flex: none; position: sticky; top: 0; height: 100vh; border-right: 2px solid rgba(var(--amber-rgb),.35); padding: 28px 0; flex-direction: column; gap: 4px; }\n #sidenav .logo { font-family: 'Songti TC','LiSong Pro',PMingLiU,serif; font-size: 26px; letter-spacing: .22em; color: var(--amber); padding: 0 24px 20px; }\n #sidenav .nav { padding: 13px 24px; font-size: 16px; cursor: pointer; letter-spacing: .08em; color: rgba(var(--ink-rgb),.6); border-right: 2px solid transparent; }\n #sidenav .nav.on { color: var(--amber); background: rgba(var(--amber-rgb),.08); border-right-color: var(--amber); font-family: 'Songti TC','LiSong Pro',PMingLiU,serif; font-weight: 600; }\n #sidenav .foot { margin-top: auto; padding: 0 24px; font-size: 12.5px; color: rgba(var(--ink-rgb),.35); line-height: 1.7; }\n }\n .view { display: none; }\n .view.on { display: block; }\n /* 登入/首次設定=flex 置中(.view.on 的 display:block 會蓋掉 .authwrap 的 flex → 內容靠左,leo 實測回饋修正) */\n .authwrap.view.on { display: flex; }\n\n /* ── 元件 ── */\n .btn { padding: 13px; font-size: 16px; font-weight: 600; border-radius: 10px; border: none; background: linear-gradient(90deg,#b98330,#e8b45a); color: #241804; cursor: pointer; }\n .btn:disabled { opacity: .45; cursor: default; }\n .btn2 { padding: 11px 16px; font-size: 15px; border-radius: 10px; border: 1px solid rgba(var(--amber-rgb),.6); background: none; color: var(--amber); cursor: pointer; }\n .btn3 { padding: 11px 16px; font-size: 15px; border-radius: 10px; border: 1px solid rgba(var(--ink-rgb),.25); background: none; color: rgba(var(--ink-rgb),.7); cursor: pointer; }\n .btn-danger { padding: 12px 18px; font-size: 15px; border-radius: 10px; border: 1px solid rgba(var(--err-rgb),.5); background: none; color: var(--err); cursor: pointer; }\n .btn-danger:disabled { opacity: .4; cursor: default; }\n .txt { width: 100%; padding: 13px 15px; font-size: 16px; border-radius: 10px; border: 1px solid rgba(var(--ink-rgb),.2); background: rgba(var(--ink-rgb),.05); color: var(--ink); }\n textarea.txt { resize: vertical; font-family: ui-monospace, Menlo, monospace; font-size: 14.5px; }\n .panel { padding: 18px; border-radius: 13px; background: rgba(var(--ink-rgb),.04); border: 1px solid rgba(var(--ink-rgb),.12); }\n .card-item { border-radius: 13px; background: rgba(var(--ink-rgb),.045); border: 1px solid rgba(var(--ink-rgb),.1); }\n .card-item.hl { border-color: rgba(var(--amber-rgb),.3); }\n .tag { display: inline-block; padding: 3px 9px; border-radius: 5px; background: rgba(var(--amber-rgb),.12); color: var(--amber); font-size: 12.5px; }\n .tag.green { background: rgba(var(--ok-rgb),.12); color: var(--ok); }\n .chip { flex: none; padding: 9px 16px; font-size: 14.5px; border-radius: 999px; cursor: pointer; border: 1px solid rgba(var(--ink-rgb),.18); background: none; color: rgba(var(--ink-rgb),.6); }\n .chip.on { border-color: rgba(var(--amber-rgb),.6); background: rgba(var(--amber-rgb),.14); color: var(--amber); font-weight: 600; }\n .hscroll { display: flex; gap: 8px; overflow-x: auto; padding-bottom: 4px; }\n .subhead { font-family: 'Songti TC','LiSong Pro',PMingLiU,serif; font-size: 16px; letter-spacing: .2em; color: rgba(var(--ink-rgb),.6); }\n .honest { padding: 22px; border-radius: 13px; border: 1px dashed rgba(var(--amber-rgb),.4); background: rgba(var(--amber-rgb),.06); text-align: center; }\n .honest .h { font-family: 'Songti TC','LiSong Pro',PMingLiU,serif; font-size: 19px; color: var(--amber); margin-bottom: 8px; }\n .honest .b { font-size: 15px; color: rgba(var(--ink-rgb),.6); line-height: 1.7; }\n #toast { position: fixed; left: 50%; bottom: 110px; transform: translateX(-50%); z-index: 99; padding: 13px 22px; border-radius: 11px; background: #e8b45a; color: #241804; font-size: 15.5px; font-weight: 600; box-shadow: 0 6px 24px rgba(0,0,0,.5); white-space: nowrap; display: none; }\n\n /* ── 駕駛艙 ── */\n .orb-row { display: flex; align-items: center; gap: 20px; padding: 26px 2px 20px; }\n .orb { width: 84px; height: 84px; border-radius: 50%; flex: none; display: grid; place-items: center; }\n .orb span { font-family: 'Songti TC','LiSong Pro',PMingLiU,serif; font-size: 30px; font-weight: 600; color: rgba(10,20,14,.85); text-shadow: 0 1px 0 rgba(255,255,255,.25); }\n .orb-title { font-family: 'Songti TC','LiSong Pro',PMingLiU,serif; font-size: 23px; font-weight: 600; }\n .orb-sub { margin-top: 5px; font-size: 15px; color: rgba(var(--ink-rgb),.6); line-height: 1.55; }\n .cockgrid { display: grid; grid-template-columns: 1fr; gap: 0 40px; }\n @media (min-width: 1024px) { .cockgrid { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); } }\n .bricks { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }\n .brick { padding: 16px; border-radius: 12px; }\n .brick.amber { background: rgba(var(--amber-rgb),.07); border: 1px solid rgba(var(--amber-rgb),.22); }\n .brick.plain { background: rgba(var(--ink-rgb),.04); border: 1px solid rgba(var(--ink-rgb),.14); cursor: pointer; }\n .brick .lbl { font-size: 13.5px; color: rgba(var(--ink-rgb),.55); margin-bottom: 6px; }\n .brick .num { font-family: ui-monospace, Menlo, monospace; font-size: 26px; color: var(--amber); }\n .brick .num small { font-size: 15px; color: rgba(var(--ink-rgb),.5); }\n .bar { margin-top: 10px; height: 6px; border-radius: 3px; background: var(--track); }\n .bar > i { display: block; height: 100%; border-radius: 3px; background: linear-gradient(90deg,#b98330,#e8b45a); transition: width .6s; }\n .wait-box { margin-top: 14px; padding: 20px; border-radius: 12px; border: 1px dashed rgba(var(--ok-rgb),.3); background: rgba(var(--ok-rgb),.05); }\n .wait-box.has { border-color: rgba(var(--amber-rgb),.45); background: rgba(var(--amber-rgb),.05); }\n .wait-head { font-family: 'Songti TC','LiSong Pro',PMingLiU,serif; font-size: 16px; letter-spacing: .2em; color: rgba(var(--ink-rgb),.6); margin-bottom: 10px; text-align: center; }\n .wait-none { font-family: 'Songti TC','LiSong Pro',PMingLiU,serif; font-size: 20px; color: var(--ok); letter-spacing: .08em; text-align: center; }\n .wait-item { display: flex; align-items: center; gap: 12px; padding: 12px 14px; margin-top: 8px; border-radius: 10px; background: rgba(var(--amber-rgb),.1); border: 1px solid rgba(var(--amber-rgb),.3); font-size: 16px; line-height: 1.5; }\n .wait-item .dm { color: var(--amber); font-size: 17px; flex: none; }\n ul.route { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }\n ul.route li { display: flex; align-items: flex-start; gap: 12px; padding: 13px 16px; border-radius: 11px; background: rgba(var(--ink-rgb),.045); border: 1px solid transparent; font-size: 16px; line-height: 1.4; }\n ul.route li.doing { background: rgba(var(--amber-rgb),.09); border-color: rgba(var(--amber-rgb),.3); }\n ul.route li .ic { flex: none; font-size: 15px; margin-top: 2px; }\n ul.route li.done { color: rgba(var(--ink-rgb),.65); } ul.route li.done .ic { color: var(--ok); }\n ul.route li.doing .ic { color: var(--amber); }\n ul.route li.todo { color: rgba(var(--ink-rgb),.6); } ul.route li.todo .ic { color: rgba(var(--ink-rgb),.35); }\n ul.route li.blocked .ic { color: var(--err); }\n\n /* ── 搜尋 ── */\n .searchrow { display: flex; gap: 10px; align-items: stretch; }\n .searchrow input { flex: 1; min-width: 0; padding: 16px 18px; font-size: 18px; border-radius: 13px; border: 1.5px solid rgba(var(--amber-rgb),.35); background: rgba(var(--ink-rgb),.05); color: var(--ink); }\n .sembtn { flex: none; padding: 0 20px; font-size: 16px; border-radius: 13px; cursor: pointer; letter-spacing: .1em; border: 1.5px solid rgba(var(--ink-rgb),.2); background: none; color: rgba(var(--ink-rgb),.55); }\n .sembtn.on { border-color: var(--amber); background: rgba(var(--amber-rgb),.15); color: var(--amber); font-weight: 600; }\n .kgrid { display: grid; grid-template-columns: 1fr; gap: 12px; padding-bottom: 8px; }\n @media (min-width: 700px) { .kgrid { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); } }\n .kcard { padding: 18px; border-radius: 13px; background: rgba(var(--ink-rgb),.045); border: 1px solid rgba(var(--ink-rgb),.1); cursor: pointer; display: flex; flex-direction: column; gap: 9px; }\n .kcard:hover { border-color: rgba(var(--amber-rgb),.45); background: rgba(var(--amber-rgb),.06); }\n .kcard .kt { font-family: 'Songti TC','LiSong Pro',PMingLiU,serif; font-size: 18.5px; font-weight: 600; line-height: 1.45; word-break: break-word; }\n .kcard .ks { font-size: 15px; color: rgba(var(--ink-rgb),.65); line-height: 1.65; word-break: break-word; }\n .kcard .km { display: flex; gap: 10px; align-items: center; margin-top: auto; font-size: 13px; flex-wrap: wrap; }\n\n /* ── 卡片詳頁 ── */\n .cardwrap { display: flex; flex-wrap: wrap; gap: 32px; padding: 24px 0 40px; }\n .cardmain { flex: 1 1 540px; min-width: 0; }\n .cardside { flex: 1 1 360px; min-width: 0; }\n .cardtitle { font-family: 'Songti TC','LiSong Pro',PMingLiU,serif; font-size: 28px; font-weight: 600; line-height: 1.4; word-break: break-word; }\n .md { margin-top: 18px; }\n .md p { font-size: 16.5px; line-height: 1.85; color: rgba(var(--ink-rgb),.82); margin: 8px 0; word-break: break-word; }\n .md h1, .md h2, .md h3, .md h4 { font-family: 'Songti TC','LiSong Pro',PMingLiU,serif; font-weight: 600; color: var(--amber); margin: 18px 0 6px; line-height: 1.4; }\n .md h1 { font-size: 22px; } .md h2 { font-size: 20px; } .md h3 { font-size: 18px; } .md h4 { font-size: 17px; }\n .md ul, .md ol { margin: 8px 0; padding-left: 24px; }\n .md li { font-size: 16.5px; line-height: 1.8; color: rgba(var(--ink-rgb),.82); margin: 4px 0; word-break: break-word; }\n .md blockquote { margin: 10px 0; padding: 12px 18px; border-left: 3px solid rgba(var(--amber-rgb),.5); font-family: 'Songti TC','LiSong Pro',PMingLiU,serif; font-size: 17px; line-height: 1.8; color: rgba(var(--ink-rgb),.7); }\n .md code { font-family: ui-monospace, Menlo, monospace; font-size: 14.5px; background: var(--well2); border-radius: 4px; padding: 1px 6px; word-break: break-all; }\n .md pre { background: var(--well2); border: 1px solid rgba(var(--ink-rgb),.1); border-radius: 10px; padding: 14px; overflow-x: auto; }\n .md pre code { background: none; padding: 0; }\n .srcline { margin-top: 24px; display: flex; align-items: center; gap: 12px; padding: 14px 16px; border-radius: 11px; background: rgba(var(--ink-rgb),.045); border: 1px solid rgba(var(--ink-rgb),.12); }\n .graphbox { position: relative; height: 340px; border-radius: 14px; background: var(--well); border: 1px solid rgba(var(--ink-rgb),.1); overflow: hidden; }\n .gnode { position: absolute; transform: translate(-50%,-50%); max-width: 96px; padding: 8px 11px; border-radius: 999px; text-align: center; font-size: 12.5px; line-height: 1.3; cursor: pointer; word-break: break-word; background: rgba(var(--ok-rgb),.1); border: 1px solid rgba(var(--ok-rgb),.35); color: var(--ok-soft); }\n .gcenter { position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%); width: 104px; height: 104px; border-radius: 50%; background: radial-gradient(circle at 36% 30%,rgba(242,209,148,.95),rgba(232,180,90,.9) 55%,rgba(138,95,30,.95)); display: grid; place-items: center; text-align: center; padding: 8px; box-shadow: 0 0 30px rgba(var(--amber-rgb),.3); }\n .gcenter span { font-family: 'Songti TC','LiSong Pro',PMingLiU,serif; font-size: 13.5px; font-weight: 600; line-height: 1.35; color: #241804; word-break: break-word; }\n .nbrow { display: flex; align-items: center; gap: 11px; padding: 12px 14px; border-radius: 10px; cursor: pointer; background: rgba(var(--ink-rgb),.045); border: 1px solid rgba(var(--ink-rgb),.1); font-size: 15.5px; }\n\n /* ── 工作流 / 憑證 / 分流台 清單 ── */\n .listcol { display: flex; flex-direction: column; gap: 10px; padding: 16px 0 8px; }\n .rowhead { display: flex; align-items: center; gap: 12px; padding: 16px 18px; cursor: pointer; }\n .rowbody { padding: 0 18px 18px; border-top: 1px solid rgba(var(--ink-rgb),.1); }\n .pinbtn { flex: none; width: 34px; height: 34px; border-radius: 8px; border: none; cursor: pointer; font-size: 17px; background: rgba(var(--ink-rgb),.06); color: rgba(var(--ink-rgb),.4); }\n .pinbtn.on { background: rgba(var(--amber-rgb),.15); color: var(--amber); }\n .urlbox { display: flex; align-items: center; gap: 10px; padding: 12px 14px; border-radius: 10px; background: var(--well); border: 1px solid rgba(var(--ink-rgb),.1); min-width: 0; }\n .urlbox .u { font-family: ui-monospace, Menlo, monospace; font-size: 13.5px; color: var(--amber); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }\n .avatar { width: 38px; height: 38px; border-radius: 10px; background: rgba(var(--amber-rgb),.1); border: 1px solid rgba(var(--amber-rgb),.25); display: grid; place-items: center; font-family: 'Songti TC','LiSong Pro',PMingLiU,serif; font-size: 17px; color: var(--amber); flex: none; }\n .maskline { display: flex; align-items: center; gap: 10px; padding: 14px; border-radius: 10px; background: var(--well); border: 1px solid rgba(var(--ink-rgb),.1); }\n /* 分流台(Arcrun#9):三欄 80/15/5 手機直排;欄色點 ai=綠 collab=琥珀 leo=紅 */\n .tri-sec { margin-top: 24px; }\n .tri-sechead { display: flex; align-items: baseline; gap: 9px; }\n .tri-sechead .dot { flex: none; width: 9px; height: 9px; border-radius: 50%; align-self: center; }\n .tri-sec.ai .dot { background: var(--ok); } .tri-sec.collab .dot { background: var(--amber); } .tri-sec.leo .dot { background: var(--err); }\n .tri-sechead .nm { font-family: 'Songti TC','LiSong Pro',PMingLiU,serif; font-size: 17px; letter-spacing: .14em; }\n .tri-sechead .pc { font-size: 12.5px; color: rgba(var(--ink-rgb),.4); }\n .tri-sechead .ct { margin-left: auto; font-family: ui-monospace, Menlo, monospace; font-size: 14px; color: rgba(var(--ink-rgb),.55); }\n .tri-item { padding: 14px 16px; border-radius: 12px; margin-top: 9px; }\n .tri-item.new { background: rgba(var(--amber-rgb),.07); border: 1px solid rgba(var(--amber-rgb),.28); }\n .tri-sec.leo .tri-item.new { background: rgba(var(--err-rgb),.06); border-color: rgba(var(--err-rgb),.3); }\n .tri-item.done { background: rgba(var(--ink-rgb),.04); border: 1px solid rgba(var(--ink-rgb),.1); opacity: .7; }\n .tri-item.done .tx { text-decoration: line-through; color: rgba(var(--ink-rgb),.6); }\n .tri-item .tx { font-size: 16.5px; line-height: 1.6; word-break: break-word; }\n .tri-item .mt { margin-top: 9px; display: flex; gap: 7px; align-items: center; flex-wrap: wrap; font-size: 12.5px; color: rgba(var(--ink-rgb),.45); }\n .tri-item .row { display: flex; gap: 12px; align-items: flex-start; }\n .tri-item .row .tx { flex: 1; min-width: 0; }\n /* 勾掉鈕:≥44px 圓形(手機好按),綠框空心=待勾;按下去由後端回寫才算數(誠實,不先假裝成功) */\n .tri-check { flex: none; width: 44px; height: 44px; border-radius: 50%; cursor: pointer; font-size: 19px; line-height: 1;\n border: 1.5px solid rgba(var(--ok-rgb),.55); background: rgba(var(--ok-rgb),.06); color: var(--ok); }\n .tri-check:active { background: rgba(var(--ok-rgb),.22); }\n .tri-check:disabled { opacity: .45; cursor: default; }\n /* 還原鈕(誤勾救濟,只出現在「顯示已完成」清單):小顆但仍 44px 高好按 */\n .tri-restore { flex: none; min-height: 32px; padding: 5px 14px; border-radius: 999px; cursor: pointer; font-size: 13px;\n border: 1px solid rgba(var(--amber-rgb),.5); background: none; color: var(--amber); }\n .tri-restore:disabled { opacity: .45; cursor: default; }\n .tag.red { background: rgba(var(--err-rgb),.12); color: var(--err); }\n .tag.dim { background: rgba(var(--ink-rgb),.08); color: rgba(var(--ink-rgb),.55); }\n\n /* ── 設定 ── */\n .setcol { display: flex; flex-direction: column; gap: 14px; padding: 20px 0 40px; }\n .switch { flex: none; margin-left: auto; width: 56px; height: 32px; border-radius: 999px; padding: 3px; background: rgba(var(--ink-rgb),.15); transition: background .25s; }\n .switch.on { background: rgba(var(--ok-rgb),.5); }\n .switch i { display: block; width: 26px; height: 26px; border-radius: 50%; background: var(--knob); box-shadow: 0 1px 3px rgba(0,0,0,.25); transition: transform .25s; }\n .switch.on i { transform: translateX(24px); }\n .kvline { display: flex; justify-content: space-between; gap: 12px; font-size: 15px; margin: 5px 0; }\n</style>\n<script src=\"/config.js\"></script>\n<script>\n// 2026-08-01arcrun-rag#10 同族):拔掉寫死中央位址的 fallback。\n// apiBase 由 worker 動態產生的 /config.js 注入;缺它就讓它明顯壞掉,\n// **不要靜默把請求(可能含金鑰)送去中央實例**。\nwindow.ARCRUN_API_BASE = (window.ARCRUN_CONFIG && window.ARCRUN_CONFIG.apiBase) || \"\";\n</script>\n</head>\n<body>\n\n<!-- 登入 -->\n<div class=\"authwrap view\" id=\"v-login\">\n <div class=\"authbox\">\n <div>\n <div class=\"brand\">Arcrun</div>\n <div class=\"brand-sub\">私人系統・僅供擁有者進入</div>\n </div>\n <div style=\"display:flex;flex-direction:column;gap:12px;text-align:left\">\n <input type=\"email\" id=\"login-email\" class=\"txt\" placeholder=\"Email\" style=\"padding:15px 16px;font-size:17px;border-radius:11px\">\n <input type=\"password\" id=\"login-password\" class=\"txt\" placeholder=\"密碼\" style=\"padding:15px 16px;font-size:17px;border-radius:11px\">\n <button class=\"btn\" id=\"login-submit\" style=\"margin-top:6px;padding:15px;font-size:17px;letter-spacing:.2em\">進入</button>\n <div id=\"login-status\" class=\"err\" style=\"font-size:14px;min-height:1.2em\"></div>\n </div>\n <div style=\"font-size:13.5px;color:rgba(var(--ink-rgb),.4);line-height:1.7\">這是一個人的智慧總部。<br>若你不是擁有者,這裡沒有你要找的東西。</div>\n \n <button class=\"btn3 themelabel\" data-themetoggle style=\"align-self:center;padding:8px 16px;font-size:13.5px;border-radius:999px\">☾ 切深色</button>\n </div>\n</div>\n\n<!-- 首次設定 -->\n<div class=\"authwrap view\" id=\"v-setup\">\n <div class=\"authbox\" style=\"max-width:440px;text-align:left\">\n <div style=\"text-align:center\">\n <div class=\"brand\" style=\"font-size:38px\">Arcrun</div>\n <div class=\"serif\" style=\"margin-top:12px;font-size:21px\">首次設定</div>\n <div style=\"margin-top:8px;font-size:15px;color:rgba(var(--ink-rgb),.55);line-height:1.7\">系統偵測到尚未設定擁有者帳號。<br>設定一組 Email 與密碼,之後只有你能進入。</div>\n </div>\n <div style=\"display:flex;flex-direction:column;gap:12px\">\n <input type=\"email\" id=\"setup-email\" class=\"txt\" placeholder=\"你的 Email\" style=\"padding:15px 16px;font-size:17px;border-radius:11px\">\n <input type=\"password\" id=\"setup-password\" class=\"txt\" placeholder=\"設定密碼(至少 8 碼)\" style=\"padding:15px 16px;font-size:17px;border-radius:11px\">\n <input type=\"password\" id=\"setup-password2\" class=\"txt\" placeholder=\"再輸入一次密碼\" style=\"padding:15px 16px;font-size:17px;border-radius:11px\">\n <button class=\"btn\" id=\"setup-submit\" style=\"margin-top:6px;padding:15px;font-size:17px;letter-spacing:.12em\">完成設定並進入</button>\n <div id=\"setup-status\" class=\"err\" style=\"font-size:14px;min-height:1.2em\"></div>\n </div>\n <button class=\"btn3 themelabel\" data-themetoggle style=\"align-self:center;padding:8px 16px;font-size:13.5px;border-radius:999px\">☾ 切深色</button>\n </div>\n</div>\n\n<!-- 主應用 -->\n<div id=\"shell\">\n <div id=\"sidenav\">\n <div class=\"logo\">Arcrun</div>\n \n <div class=\"nav\" data-nav=\"search\">總庫搜尋</div>\n <div class=\"nav\" data-nav=\"workflows\">工作流</div>\n \n <div class=\"nav\" data-nav=\"settings\">設定</div>\n <div class=\"nav themelabel\" data-themetoggle style=\"margin-top:8px;font-size:14.5px\">☾ 切深色</div>\n <div class=\"foot\" id=\"side-foot\"></div>\n </div>\n <main>\n\n <!-- 駕駛艙 -->\n <div class=\"view page\" id=\"v-cockpit\">\n <div class=\"pagehead\"><span class=\"t\">Arcrun<span style=\"font-size:14px;letter-spacing:.3em;color:rgba(var(--ink-rgb),.5)\"> 控制台</span></span><span class=\"m serif\" id=\"ck-date\"></span></div>\n <div class=\"cockgrid\">\n <div>\n <div class=\"orb-row\">\n <div class=\"orb\" id=\"ck-orb\" style=\"background:radial-gradient(circle at 36% 30%,#8fe8b4,#3fbe78 55%,#22754a 100%)\"><span id=\"ck-char\">…</span></div>\n <div>\n <div class=\"orb-title\" id=\"ck-title\">載入中</div>\n <div class=\"orb-sub\" id=\"ck-sub\"></div>\n </div>\n </div>\n <div class=\"bricks\">\n <div class=\"brick amber\">\n <div class=\"lbl\">今日完成</div>\n <div class=\"num\"><span id=\"ck-done\"></span><small> / <span id=\"ck-total\"></span> 件</small></div>\n <div class=\"bar\"><i id=\"ck-bar\" style=\"width:0%\"></i></div>\n </div>\n <div class=\"brick plain\" data-nav=\"inbox\">\n <div class=\"lbl\">收件匣未處理</div>\n <div class=\"num\"><span id=\"ck-inbox\"></span><small> 條</small></div>\n <div class=\"lbl\" style=\"margin:10px 0 0\">來自 Telegram</div>\n </div>\n </div>\n <div class=\"wait-box\" id=\"ck-waitbox\">\n <div class=\"wait-head\">等你的事</div>\n <div id=\"ck-wait\" class=\"wait-none\">載入中…</div>\n <div id=\"ck-waitmeta\" style=\"margin-top:10px;text-align:center;font-size:12.5px;color:rgba(var(--ink-rgb),.45);line-height:1.7\"></div>\n </div>\n </div>\n <div>\n <div style=\"display:flex;justify-content:space-between;align-items:baseline;margin:24px 0 10px\">\n <span class=\"subhead\">今日路線</span><span id=\"ck-route-src\" style=\"font-size:13px;color:rgba(var(--ink-rgb),.4)\">狀態即時同步</span>\n </div>\n <ul class=\"route\" id=\"ck-today\"><li class=\"todo\"><span class=\"ic\">○</span><span class=\"muted\">載入中…</span></li></ul>\n <div class=\"subhead\" id=\"ck-weekhead\" style=\"display:none;margin:18px 0 10px\">本週</div>\n <ul class=\"route\" id=\"ck-week\"></ul>\n <div style=\"margin:16px 0 8px;text-align:center;font-size:12.5px;color:rgba(var(--ink-rgb),.35);line-height:1.8\" id=\"ck-stamp\">每 60 秒自動刷新</div>\n </div>\n </div>\n </div>\n\n <!-- 總庫搜尋(library-map SDD M5/R4:搜尋框上方=藏書地圖——先看全館有哪些庫,點庫卡片帶 library filter 進庫搜尋) -->\n <div class=\"view page wide\" id=\"v-search\">\n <div class=\"pagehead\"><span class=\"t\">總庫搜尋</span><span class=\"m mono\" id=\"se-scale\"></span></div>\n <div style=\"padding-top:20px\">\n <div id=\"lm-section\" style=\"margin-bottom:24px\">\n <div style=\"display:flex;justify-content:space-between;align-items:baseline;margin-bottom:10px\">\n <span class=\"subhead\">藏書地圖</span><span id=\"lm-meta\" style=\"font-size:13px;color:rgba(var(--ink-rgb),.4)\"></span>\n </div>\n <div class=\"kgrid\" id=\"lm-cards\"><div class=\"muted\" style=\"font-size:14px\">地圖載入中…</div></div>\n <div id=\"lm-bridges\"></div>\n </div>\n <div class=\"searchrow\">\n <input id=\"se-q\" placeholder=\"搜尋知識…\" autocomplete=\"off\">\n <button class=\"sembtn\" id=\"se-sem\">語意</button>\n </div>\n <div id=\"se-libbar\"></div>\n <div class=\"hscroll\" id=\"se-chips\" style=\"margin-top:12px\"></div>\n <div id=\"se-banner\"></div>\n <div id=\"se-count\" style=\"margin:20px 0 12px;font-size:14px;color:rgba(var(--ink-rgb),.5)\"></div>\n <div class=\"kgrid\" id=\"se-results\"></div>\n </div>\n </div>\n\n <!-- 卡片詳頁 -->\n <div class=\"view page wide\" id=\"v-card\">\n <div class=\"pagehead\" style=\"justify-content:flex-start;gap:14px\">\n <button class=\"btn2\" style=\"border:none;padding:0;font-size:16px\" data-nav=\"search\"> 搜尋</button>\n <span class=\"serif\" style=\"font-size:17px;letter-spacing:.14em;color:rgba(var(--ink-rgb),.55)\">知識卡片</span>\n </div>\n <div class=\"cardwrap\">\n <div class=\"cardmain\" id=\"cd-main\"><div class=\"muted\" style=\"padding:24px 0\">載入中…</div></div>\n <div class=\"cardside\">\n <div class=\"subhead\" style=\"margin:6px 0 12px;display:block\">關聯視圖</div>\n <div id=\"cd-graph\"></div>\n <div id=\"cd-neighbors\" style=\"margin-top:16px;display:flex;flex-direction:column;gap:7px\"></div>\n </div>\n </div>\n </div>\n\n <!-- 工作流 -->\n <div class=\"view page narrow\" id=\"v-workflows\">\n <div class=\"pagehead\"><span class=\"t\">工作流</span><span class=\"m\" id=\"wf-count\"></span></div>\n <input id=\"wf-q\" class=\"txt\" placeholder=\"搜尋工作流…\" style=\"margin-top:18px\" autocomplete=\"off\">\n <div class=\"listcol\" id=\"wf-list\"><div class=\"muted\">載入中…</div></div>\n <div style=\"margin-top:26px\">\n <div class=\"subhead\" style=\"display:block;margin-bottom:10px\">零件與 Recipes(框架資源)</div>\n <div class=\"searchrow\">\n <input id=\"cr-q\" class=\"txt\" placeholder=\"如「telegram send」「gsheets append」\" style=\"font-size:15px;padding:12px 14px;border-radius:11px;border-width:1px\">\n <button class=\"btn2\" id=\"cr-go\" style=\"flex:none\">搜</button>\n </div>\n <div id=\"cr-out\" style=\"margin-top:10px\"></div>\n </div>\n </div>\n\n <!-- 憑證管理 -->\n <div class=\"view page narrow\" id=\"v-creds\">\n <div class=\"pagehead\"><span class=\"t\">憑證管理</span><button class=\"btn2\" id=\"cred-addbtn\" style=\"padding:9px 16px;font-size:14.5px\"> 新增憑證</button></div>\n <div style=\"margin-top:16px;padding:13px 16px;border-radius:11px;background:rgba(var(--ok-rgb),.05);border:1px solid rgba(var(--ok-rgb),.2);font-size:14px;line-height:1.7;color:rgba(var(--ink-rgb),.65)\">\n <span class=\"ok\">🛡 保險箱原則</span>:系統只保存目錄與加密後的值,<b style=\"color:var(--ink)\">任何頁面都看不到密文內容</b>。只能整筆替換或刪除。\n </div>\n <div id=\"cred-form\" style=\"display:none;margin-top:14px\" class=\"panel\">\n <div class=\"serif\" style=\"font-size:17px;color:var(--amber);margin-bottom:10px\">新增憑證</div>\n <div style=\"display:flex;flex-direction:column;gap:10px\">\n <input id=\"cred-name\" class=\"txt\" placeholder=\"名稱(英數與底線,例:openai_main_key\">\n <input id=\"cred-service\" class=\"txt\" placeholder=\"服務(例:OpenAI\">\n <textarea id=\"cred-secret\" class=\"txt\" placeholder=\"密文值(保存後不再顯示)\" rows=\"2\"></textarea>\n <button class=\"btn\" id=\"cred-save\">加密保存</button>\n <div id=\"cred-form-status\" style=\"font-size:14px;min-height:1.2em\"></div>\n </div>\n </div>\n <div class=\"listcol\" id=\"cred-list\"><div class=\"muted\">載入中…</div></div>\n </div>\n\n <!-- 分流台(原收件匣,Arcrun#9 改裝=全部待辦分流台) -->\n <div class=\"view page narrow\" id=\"v-inbox\">\n <div class=\"pagehead\"><span class=\"t\">分流台</span><span class=\"m\">全部待辦・80/15/5</span></div>\n <div class=\"hscroll\" id=\"tg-chips\" style=\"margin-top:14px\"></div>\n <div id=\"tg-out\" style=\"padding-top:2px\"><div class=\"muted\" style=\"padding:14px 0\">載入中…</div></div>\n </div>\n\n <!-- 設定 -->\n <div class=\"view page narrow\" id=\"v-settings\">\n <div class=\"pagehead\"><span class=\"t\">設定</span></div>\n <div class=\"setcol\">\n <div class=\"panel\">\n <div style=\"display:flex;align-items:center;gap:14px\">\n <div style=\"min-width:0\">\n <div style=\"font-size:17px;font-weight:600\">深色模式</div>\n <div style=\"margin-top:4px;font-size:14px;line-height:1.65;color:rgba(var(--ink-rgb),.55)\">預設淺色(紙感)。切換立即生效,選擇記在這台裝置(localStorage)。</div>\n </div>\n <div class=\"switch\" id=\"st-theme-switch\" data-themetoggle style=\"cursor:pointer\"><i></i></div>\n </div>\n </div>\n <div class=\"panel\">\n <!-- t36leo 2026-07-25 定案:語意搜尋預設開啟、不做開關):\n 這裡原本是一個「長得像開關、其實不能按」的唯讀狀態燈(title 自承「不能遠端改」),\n 旁邊還教用戶去部署端改 config.yaml 跑 CLI——對一鍵安裝進來的用戶那是天書,\n 而且安裝器現在裝機時就把語意索引開好了,那段指示已經不成立。\n 改成單純的狀態列:能用就說能用,不能用就說原因,不擺一個按不動的開關讓人誤會。 -->\n <div style=\"font-size:17px;font-weight:600\">語意搜尋</div>\n <div id=\"st-vec\" style=\"margin-top:4px;font-size:14px;line-height:1.65;color:rgba(var(--ink-rgb),.55)\">狀態偵測中…</div>\n <div id=\"st-vec-hint\" style=\"margin-top:12px;padding:12px 14px;border-radius:10px;background:rgba(var(--amber-rgb),.07);border:1px dashed rgba(var(--amber-rgb),.35);font-size:14px;line-height:1.7;color:rgba(var(--ink-rgb),.65);display:none\"></div>\n </div>\n <div class=\"panel\">\n <div style=\"font-size:17px;font-weight:600\">MCP token 有效期(TTL</div>\n <div id=\"st-mcp-ttl\" style=\"margin-top:4px;font-size:14px;line-height:1.65;color:rgba(var(--ink-rgb),.55)\">讀取中…</div>\n <div style=\"margin-top:12px;padding:12px 14px;border-radius:10px;background:rgba(var(--amber-rgb),.07);border:1px dashed rgba(var(--amber-rgb),.35);font-size:14px;line-height:1.7;color:rgba(var(--ink-rgb),.65)\">\n 誠實佔位:此頁<b style=\"color:var(--amber)\">還不能改</b>這個值——可調功能=Arcrun#19(設定頁改→存 KBDB→發 token 時讀)。實作前要調整請在部署端 env <code style=\"font-size:12.5px\">MCP_TOKEN_TTL</code>mcp worker)設定。\n </div>\n </div>\n <div class=\"panel\">\n <div style=\"font-size:17px;font-weight:600\">更換帳號密碼</div>\n <div style=\"margin-top:4px;font-size:14px;color:rgba(var(--ink-rgb),.55)\">需輸入舊密碼驗證身分</div>\n <div style=\"margin-top:14px;display:flex;flex-direction:column;gap:10px\">\n <input type=\"password\" id=\"st-pw-old\" class=\"txt\" placeholder=\"舊密碼\">\n <input type=\"email\" id=\"st-pw-email\" class=\"txt\" placeholder=\"Email(可沿用或換新)\">\n <input type=\"password\" id=\"st-pw-new\" class=\"txt\" placeholder=\"新密碼(至少 8 碼)\">\n <button class=\"btn\" id=\"st-pw-save\">更新密碼</button>\n <div id=\"st-pw-status\" style=\"font-size:14px;min-height:1.2em\"></div>\n </div>\n </div>\n \n <div class=\"panel\">\n <div style=\"font-size:17px;font-weight:600\">Portal 帳號密碼救援</div>\n <div style=\"margin-top:4px;font-size:14px;line-height:1.65;color:rgba(var(--ink-rgb),.55)\">忘記某個 Portal(RAG 搜尋頁)帳號的密碼,包含你自己那組管理員帳號——不需要先登進 Portal。輸入該帳號的 Email,會產生一組新密碼,只顯示這一次,請立刻抄下並拿去 Portal 登入頁使用。</div>\n <div style=\"margin-top:14px;display:flex;flex-direction:column;gap:10px\">\n <input type=\"email\" id=\"st-portal-recover-email\" class=\"txt\" placeholder=\"Portal 帳號 Email\">\n <button class=\"btn\" id=\"st-portal-recover-btn\">產生新密碼</button>\n <div id=\"st-portal-recover-status\" style=\"font-size:14px;min-height:1.2em\"></div>\n </div>\n </div>\n <div class=\"panel\">\n <div style=\"font-size:17px;font-weight:600;margin-bottom:12px\">系統資訊</div>\n <div id=\"st-info\"><div class=\"muted\">載入中…</div></div>\n </div>\n <button class=\"btn3\" id=\"st-logout\" style=\"padding:14px;font-size:16px;border-radius:11px\">登出</button>\n </div>\n </div>\n\n </main>\n</div>\n\n<!-- 手機底部導覽 -->\n<div id=\"tabbar\">\n \n <div class=\"tab\" data-nav=\"search\">搜尋</div>\n <div class=\"tab\" data-nav=\"workflows\">工作流</div>\n \n <div class=\"tab\" data-nav=\"settings\">設定</div>\n</div>\n\n<div id=\"toast\"></div>\n\n<script>\n(function () {\n var API_BASE = window.ARCRUN_API_BASE || '';\n 'use strict';\n // 台北時間 helperlib/taipei-time.ts 注入,與駕駛艙 #36 台北日判定同一套)——\n // console 所有日期/時間顯示固定 Asia/Taipei,不隨看的裝置時區漂移\n var TAIPEI_OFFSET_MS = 28800000; // UTC+8,台北無 DST\nfunction tpePad(n) { n = String(n); return n.length < 2 ? '0' + n : n; }\nfunction taipeiDayKey(ms) { return new Date(ms + TAIPEI_OFFSET_MS).toISOString().slice(0, 10); }\nfunction taipeiDateStr(ms) { return taipeiDayKey(ms); }\nfunction taipeiDateTimeStr(ms) { var d = new Date(ms + TAIPEI_OFFSET_MS); return taipeiDayKey(ms) + ' ' + tpePad(d.getUTCHours()) + ':' + tpePad(d.getUTCMinutes()); }\nfunction taipeiTimeStr(ms) { var d = new Date(ms + TAIPEI_OFFSET_MS); return tpePad(d.getUTCHours()) + ':' + tpePad(d.getUTCMinutes()) + ':' + tpePad(d.getUTCSeconds()); }\nfunction taipeiMonthDay(ms) { var d = new Date(ms + TAIPEI_OFFSET_MS); return { month: d.getUTCMonth() + 1, day: d.getUTCDate() }; }\n var REGISTRY_BASE = \"https://registry.arcrun.dev\";\n var $ = function (id) { return document.getElementById(id); };\n\n // ── 狀態 ──\n var S = {\n token: localStorage.getItem('arcrun_console_session') || '',\n tenant: '',\n chip: '', // entry_type filter'' = 全部)\n library: '', // library filter'' = 全館;藏書地圖點庫卡片設定,M5/R4\n semantic: false,\n cardId: '',\n graphCenter: '',\n wfCache: null,\n pins: (function () { try { return JSON.parse(localStorage.getItem('arcrun_console_pins') || '{}'); } catch (e) { return {}; } })()\n };\n\n function esc(s) {\n return String(s == null ? '' : s).replace(/[&<>\"']/g, function (c) {\n return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' }[c];\n });\n }\n function toast(msg) {\n var el = $('toast');\n el.textContent = msg;\n el.style.display = 'block';\n clearTimeout(toast._t);\n toast._t = setTimeout(function () { el.style.display = 'none'; }, 2000);\n }\n function apiHeaders() { return { 'X-Arcrun-API-Key': S.tenant }; }\n\n // fetch 失敗(斷網)的裸 TypeError 訊息(Failed to fetch / Load failed)→ 友善誠實文案\n function friendlyErr(e) {\n var m = e && e.message ? String(e.message) : String(e);\n if (/failed to fetch|load failed|networkerror|network request failed/i.test(m)) return '連線中斷——請檢查網路後重試';\n return m;\n }\n\n // ── 主題(深/淺):預設淺色,選擇存 localStorage(head 預載腳本已先套用防閃色)──\n function getTheme() { return document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light'; }\n function setTheme(t) {\n document.documentElement.setAttribute('data-theme', t);\n try { localStorage.setItem('arcrun_console_theme', t); } catch (e) { /* 私密模式存不了就只影響本次 */ }\n syncThemeUI();\n }\n function syncThemeUI() {\n var dark = getTheme() === 'dark';\n document.querySelectorAll('.themelabel').forEach(function (el) { el.textContent = dark ? '☀ 切淺色' : '☾ 切深色'; });\n var sw = $('st-theme-switch');\n if (sw) sw.classList.toggle('on', dark);\n }\n document.addEventListener('click', function (ev) {\n var t = ev.target.closest('[data-themetoggle]');\n if (t) setTheme(getTheme() === 'dark' ? 'light' : 'dark');\n });\n syncThemeUI();\n\n // created_at 容錯:epoch 秒 / 毫秒 / ISO / 'YYYY-MM-DD HH:MM:SS'\n function parseAtMs(v) {\n if (v == null || v === '') return null;\n if (typeof v === 'number') return v < 1e12 ? v * 1000 : v;\n if (/^\\d+$/.test(v)) { var n = Number(v); return n < 1e12 ? n * 1000 : n; }\n var s = /T/.test(v) ? v : String(v).replace(' ', 'T') + 'Z';\n var ms = Date.parse(s);\n return isNaN(ms) ? null : ms;\n }\n // 顯示一律台北時間(bug 修正:原本用瀏覽器本地 getFullYear/getHours——顯示結果\n // 隨看的裝置時區漂移,且與後端「台北日」判定不同套;憑證頁 7/6 22:57(台北)建立的\n // credential 在非 +8 裝置上會顯示成另一天)\n function fmtDate(v) {\n var ms = parseAtMs(v);\n return ms == null ? '' : taipeiDateStr(ms);\n }\n function fmtDateTime(v) {\n var ms = parseAtMs(v);\n return ms == null ? '' : taipeiDateTimeStr(ms);\n }\n\n // ── 極簡 Markdown 渲染(先全 escape 再上格式,防 XSS)──\n function mdInline(s) {\n return s\n .replace(/\\*\\*([^*]+)\\*\\*/g, '<b>$1</b>')\n .replace(/(^|[^\\\\])\\x60([^\\x60]+)\\x60/g, '$1<code>$2</code>');\n }\n function mdRender(src) {\n var lines = String(src || '').split(/\\r?\\n/);\n var out = [], inCode = false, listMode = '';\n function closeList() { if (listMode) { out.push(listMode === 'ul' ? '</ul>' : '</ol>'); listMode = ''; } }\n for (var i = 0; i < lines.length; i++) {\n var raw = lines[i];\n if (/^\\s*\\x60\\x60\\x60/.test(raw)) {\n closeList();\n if (inCode) { out.push('</code></pre>'); inCode = false; }\n else { out.push('<pre><code>'); inCode = true; }\n continue;\n }\n if (inCode) { out.push(esc(raw) + '\\n'); continue; }\n var line = esc(raw);\n var h = raw.match(/^(#{1,4})\\s+(.*)$/);\n if (h) { closeList(); out.push('<h' + h[1].length + '>' + mdInline(esc(h[2])) + '</h' + h[1].length + '>'); continue; }\n if (/^\\s*&gt;\\s?/.test(line)) { closeList(); out.push('<blockquote>' + mdInline(line.replace(/^\\s*&gt;\\s?/, '')) + '</blockquote>'); continue; }\n var li = raw.match(/^\\s*[-*+]\\s+(.*)$/);\n if (li) { if (listMode !== 'ul') { closeList(); out.push('<ul>'); listMode = 'ul'; } out.push('<li>' + mdInline(esc(li[1])) + '</li>'); continue; }\n var oli = raw.match(/^\\s*\\d+[.)]\\s+(.*)$/);\n if (oli) { if (listMode !== 'ol') { closeList(); out.push('<ol>'); listMode = 'ol'; } out.push('<li>' + mdInline(esc(oli[1])) + '</li>'); continue; }\n if (/^\\s*$/.test(raw)) { closeList(); continue; }\n closeList();\n out.push('<p>' + mdInline(line) + '</p>');\n }\n closeList();\n if (inCode) out.push('</code></pre>');\n return out.join('');\n }\n\n // ── 路由 ──\n // VIEWS / HOME 由 server 依 CONSOLE_PROFILE 注入(full=全套 7 頁落地駕駛艙;rag=4 頁落地搜尋)。\n // 不在 VIEWS 裡的 hash(含被 profile 裁掉的頁)一律導回 HOME——手打 #/cockpit 也進不去。\n var VIEWS = [\"search\",\"card\",\"workflows\",\"settings\"];\n var HOME = \"search\";\n function currentRoute() {\n var h = location.hash.replace(/^#\\/?/, '');\n var seg = h.split('/');\n return { raw: seg[0] || '', view: VIEWS.indexOf(seg[0]) >= 0 ? seg[0] : HOME, arg: seg.slice(1).join('/') };\n }\n function nav(view, arg) {\n location.hash = '#/' + view + (arg ? '/' + encodeURIComponent(arg) : '');\n }\n function showView(name) {\n VIEWS.forEach(function (v) { $('v-' + v).classList.toggle('on', v === name); });\n var activeKey = name === 'card' ? 'search' : name;\n document.querySelectorAll('#sidenav .nav, #tabbar .tab').forEach(function (el) {\n el.classList.toggle('on', el.getAttribute('data-nav') === activeKey);\n });\n window.scrollTo(0, 0);\n }\n var LOADERS = { cockpit: loadCockpit, search: initSearchOnce, card: loadCard, workflows: loadWorkflows, creds: loadCreds, inbox: loadTriage, settings: loadSettings };\n function route() {\n var r = currentRoute();\n // 隱藏頁/不存在頁 guardhash 不在 VIEWS → 改寫成 HOMEhashchange 會再進來一次正常渲染)\n if (r.raw && r.raw !== r.view) { location.hash = '#/' + r.view; return; }\n if (r.view === 'card' && r.arg) S.cardId = decodeURIComponent(r.arg);\n showView(r.view);\n if (LOADERS[r.view]) LOADERS[r.view]();\n }\n window.addEventListener('hashchange', route);\n document.addEventListener('click', function (ev) {\n var t = ev.target.closest('[data-nav]');\n if (t) nav(t.getAttribute('data-nav'));\n });\n\n // ── 認證 ──\n function showAuth(which) {\n $('v-login').classList.toggle('on', which === 'login');\n $('v-setup').classList.toggle('on', which === 'setup');\n $('shell').classList.remove('on');\n $('tabbar').classList.remove('on');\n }\n function showApp() {\n $('v-login').classList.remove('on');\n $('v-setup').classList.remove('on');\n $('shell').classList.add('on');\n $('tabbar').classList.add('on');\n $('side-foot').innerHTML = '租戶 ' + esc(S.tenant) + '<br>' + esc(location.host);\n if (!location.hash) location.hash = '#/' + HOME;\n route();\n }\n function init() {\n if (S.token) {\n fetch(API_BASE + '/console/session', { headers: { Authorization: 'Bearer ' + S.token } })\n .then(function (r) { return r.ok ? r.json() : Promise.reject(new Error('session 失效')); })\n .then(function (d) { S.tenant = d.tenant || ''; showApp(); })\n .catch(function () {\n S.token = ''; localStorage.removeItem('arcrun_console_session');\n checkConfigured();\n });\n } else {\n checkConfigured();\n }\n }\n function checkConfigured() {\n fetch(API_BASE + '/console/auth-status')\n .then(function (r) { return r.json(); })\n .then(function (d) { showAuth(d.configured ? 'login' : 'setup'); })\n .catch(function () { showAuth('login'); });\n }\n function handleAuthResponse(d) {\n S.token = d.session_token;\n localStorage.setItem('arcrun_console_session', S.token);\n S.tenant = d.tenant || '';\n showApp();\n }\n $('login-submit').addEventListener('click', function () {\n var email = $('login-email').value.trim(), password = $('login-password').value;\n $('login-status').textContent = '';\n fetch(API_BASE + '/console/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: email, password: password }) })\n .then(function (r) { return r.json().then(function (d) { return { ok: r.ok, d: d }; }); })\n .then(function (x) { if (!x.ok) { $('login-status').textContent = x.d.error || '登入失敗'; return; } handleAuthResponse(x.d); })\n .catch(function (e) { $('login-status').textContent = '請求失敗:' + friendlyErr(e); });\n });\n $('login-password').addEventListener('keydown', function (ev) { if (ev.key === 'Enter') $('login-submit').click(); });\n $('setup-submit').addEventListener('click', function () {\n var email = $('setup-email').value.trim(), pw = $('setup-password').value, pw2 = $('setup-password2').value;\n if (pw !== pw2) { $('setup-status').textContent = '兩次密碼不一致'; return; }\n $('setup-status').textContent = '';\n fetch(API_BASE + '/console/setup', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: email, password: pw }) })\n .then(function (r) { return r.json().then(function (d) { return { ok: r.ok, d: d }; }); })\n .then(function (x) { if (!x.ok) { $('setup-status').textContent = x.d.error || '設定失敗'; return; } handleAuthResponse(x.d); })\n .catch(function (e) { $('setup-status').textContent = '請求失敗:' + friendlyErr(e); });\n });\n\n // ── 駕駛艙 ──\n var LIGHT = {\n green: { ch: '安', title: '系統運轉中', grad: 'radial-gradient(circle at 36% 30%,#8fe8b4,#3fbe78 55%,#22754a 100%)', anim: 'breatheGreen' },\n yellow: { ch: '趕', title: '落後趕工中', grad: 'radial-gradient(circle at 36% 30%,#f2d194,#e8b45a 55%,#8a5f1e 100%)', anim: 'breatheAmber' },\n red: { ch: '滯', title: '卡住或斷訊', grad: 'radial-gradient(circle at 36% 30%,#f0a094,#d95f4c 55%,#7e2c20 100%)', anim: 'breatheRed' }\n };\n var TASK_ICONS = { done: '✓', doing: '◐', todo: '○', blocked: '●' };\n var CNUM = ['零','一','二','三','四','五','六','七','八','九','十'];\n function cnDay(n) { return n <= 10 ? CNUM[n] : (n < 20 ? '十' + (n % 10 ? CNUM[n % 10] : '') : CNUM[Math.floor(n / 10)] + '十' + (n % 10 ? CNUM[n % 10] : '')); }\n function taskLine(t) {\n var cls = TASK_ICONS[t.status] ? t.status : 'blocked';\n return '<li class=\"' + cls + '\"><span class=\"ic\">' + (TASK_ICONS[t.status] || '●') + '</span><span>' + esc(t.title) + '</span></li>';\n }\n function ckAge(m) {\n if (m == null || m < 0) return '時間不明';\n if (m < 60) return m + ' 分鐘前';\n if (m < 2880) return Math.round(m / 60) + ' 小時前';\n return Math.round(m / 1440) + ' 天前';\n }\n function loadCockpit() {\n var nowTpe = taipeiMonthDay(Date.now()); // 頁首日期=台北日,不吃裝置時區\n $('ck-date').textContent = CNUM[nowTpe.month] + '月' + cnDay(nowTpe.day) + '日';\n fetch(API_BASE + '/console/dashboard-data')\n .then(function (r) { if (!r.ok) throw new Error('HTTP ' + r.status); return r.json(); })\n .then(function (d) {\n var cfg = LIGHT[d.light] || LIGHT.green;\n var orb = $('ck-orb');\n orb.style.background = cfg.grad;\n orb.style.animation = cfg.anim + ' 3.4s ease-in-out infinite';\n $('ck-char').textContent = cfg.ch;\n $('ck-title').textContent = cfg.title;\n $('ck-sub').textContent = (d.last_beat\n ? d.last_beat.actor + '・' + d.last_beat.ago_minutes + ' 分鐘前' + (d.last_beat.note ? '・' + d.last_beat.note : '')\n : '尚無心跳資料') + (d.light !== 'green' && d.light_reason ? '' + d.light_reason + '' : '');\n var done = d.today_done || 0, total = d.today_total || 0;\n $('ck-done').textContent = done; $('ck-total').textContent = total;\n $('ck-bar').style.width = (total ? Math.round(done / total * 100) : 0) + '%';\n $('ck-inbox').textContent = d.inbox_new || 0;\n // 等你的事:來源與維護時間攤開講(fix/console-dashboard-live-data)——\n // Gitea sprint 等leo清單是活資料源;fallback dash_wait 一定標 stale,不假裝是今天的\n var wb = $('ck-waitbox'), body = $('ck-wait'), wmeta = $('ck-waitmeta');\n var wm = d.waiting_meta || {};\n if (d.waiting && d.waiting.length) {\n wb.classList.add('has'); body.className = '';\n body.innerHTML = d.waiting.map(function (w) {\n return '<div class=\"wait-item\"><span class=\"dm\">' + (w.urgency ? esc(w.urgency) : '◆') + '</span><span>' +\n (w.id ? '<b>#' + esc(w.id) + '</b> ' : '') + esc(w.title) + '</span></div>';\n }).join('');\n } else {\n wb.classList.remove('has'); body.className = 'wait-none';\n body.textContent = wm.source === 'none' ? '(管線未接)' : '無,你不用做任何事';\n }\n if (wm.source === 'gitea_sprint') {\n wmeta.innerHTML = '來源:sprint 等leo清單・維護於 ' + ckAge(wm.updated_ago_minutes) +\n (wm.stale ? '<br><span class=\"err\">⚠ 清單超過 2 天沒維護,可能過時</span>' : '');\n } else if (wm.source === 'kbdb_dash_wait') {\n wmeta.innerHTML = '<span class=\"err\">⚠ ' + esc(wm.note || 'dash_wait 殘資料') + '・上次寫入 ' + ckAge(wm.updated_ago_minutes) + ',可能過時</span>';\n } else if (wm.source === 'none') {\n wmeta.innerHTML = '<span class=\"err\">管線未接:Gitea sprint 清單與 dash_wait 皆無資料</span>';\n } else {\n wmeta.textContent = '';\n }\n // 今日路線:sprint 任務板優先(來源與更新時間攤開講);dash_task fallback 沿舊誠實降級\n var rm = d.route_meta || {};\n var today = (d.tasks || []).filter(function (t) { return t.scope === 'today'; });\n var week = (d.tasks || []).filter(function (t) { return t.scope === 'week'; });\n if (rm.source === 'gitea_sprint_board') {\n $('ck-route-src').textContent = '來源 sprint 任務板・更新於 ' + ckAge(rm.updated_ago_minutes);\n var staleHead = rm.is_today ? '' :\n '<li class=\"todo\"><span class=\"ic\">○</span><span class=\"muted\">⚠ 今日任務板未更新(最後 ' + ckAge(rm.updated_ago_minutes) + ')——以下是板上現況</span></li>';\n $('ck-today').innerHTML = staleHead + (today.length\n ? today.map(taskLine).join('')\n : '<li class=\"todo\"><span class=\"ic\">○</span><span class=\"muted\">任務板上沒有可解析的事項</span></li>');\n } else if (rm.is_today || !today.length) {\n $('ck-route-src').textContent = '來源 dash_task';\n $('ck-today').innerHTML = today.length ? today.map(taskLine).join('') : '<li class=\"todo\"><span class=\"ic\">○</span><span class=\"muted\">今日無排定項目——dash_task 今天沒有寫入</span></li>';\n } else {\n $('ck-route-src').textContent = '來源 dash_task';\n $('ck-today').innerHTML = '<li class=\"todo\"><span class=\"ic\">○</span><span class=\"muted\">今日尚無路線寫入——以下是 ' + ckAge(rm.updated_ago_minutes) + '的殘留路線</span></li>' + today.map(taskLine).join('');\n }\n $('ck-weekhead').style.display = week.length ? '' : 'none';\n $('ck-week').innerHTML = week.map(taskLine).join('');\n $('ck-stamp').textContent = '每 60 秒自動刷新・上次 ' + taipeiTimeStr(Date.parse(d.generated_at)) + '(台北)';\n })\n .catch(function (e) {\n $('ck-char').textContent = '';\n $('ck-title').textContent = '讀不到狀態';\n $('ck-sub').innerHTML = '<span class=\"err\">' + esc(friendlyErr(e)) + '・每 60 秒自動重試</span>';\n });\n }\n // 60 秒定時器無條件常駐:斷網期間照跑,網路恢復後下一輪自動刷新回正常畫面\n setInterval(function () { if (currentRoute().view === 'cockpit' && $('shell').classList.contains('on')) loadCockpit(); }, 60000);\n\n // ── 總庫搜尋 ──\n // chips = KBDB 真能篩的 entry_type(誠實:不編造「電腦筆記/手機筆記」等 KBDB 沒有的分類軸)\n var CHIPS = [\n { label: '全部', v: '' },\n { label: '筆記 note', v: 'note' },\n { label: '區塊 block', v: 'block' },\n { label: '數值 value', v: 'value' },\n { label: '工作流 workflow', v: 'workflow' }\n ];\n var searchInited = false;\n function initSearchOnce() {\n if (searchInited) { return; }\n searchInited = true;\n renderChips();\n loadScale();\n loadLibraryMap();\n }\n\n // ── 藏書地圖(library-map SDD M5/R4)──\n // 資料源:GET /kbdb/mapcypher 代轉 KBDB 基本盤,kbdb-proxy.ts——同 /kbdb/search 慣例)。\n // 兩段式渲染:先用全館列表(top_entities=名字 top3)立即出卡片,再逐庫拉 /kbdb/map/:library\n // 補 degreebridgescommit_hash(庫數少;詳圖拉不到就維持名字版——加分項不擋渲染)。\n // 空陣列/錯誤=誠實空狀態,只佔地圖區塊,不擋下方搜尋。\n var LM = { libs: null, details: {} }; // 地圖快取:點卡片重繪「搜尋中」標記時不用重打 API\n function lmHonest(head, body) {\n $('lm-cards').innerHTML = '<div class=\"honest\" style=\"grid-column:1/-1\"><div class=\"h\">' + esc(head) + '</div><div class=\"b\">' + body + '</div></div>';\n $('lm-bridges').innerHTML = '';\n $('lm-meta').textContent = '';\n }\n function lmEntityLine(ents) {\n // ents:詳圖版 [{name, degree}] 或全館列表版 ['name']——兩形都渲染,degree 有才顯示\n return (ents || []).slice(0, 5).map(function (t) {\n var name = typeof t === 'string' ? t : (t && t.name) || '';\n var deg = t && typeof t === 'object' && typeof t.degree === 'number' ? t.degree : null;\n return '<span class=\"tag green\">' + esc(name) + (deg != null ? '<span style=\"opacity:.65\">・' + deg + '</span>' : '') + '</span>';\n }).join(' ');\n }\n function renderLmCards(libs, details) {\n $('lm-meta').textContent = libs.length + ' 個庫・點卡片進該庫搜尋';\n $('lm-cards').innerHTML = libs.map(function (l) {\n var d = details[l.library];\n var ents = d && d.top_entities && d.top_entities.length ? d.top_entities : l.top_entities;\n // 更新時間感:commit_hash(詳圖有才顯示,短碼)+ updated_at(epoch 秒,台北時間)\n var stamp = (d && d.commit_hash ? '<span class=\"mono\">' + esc(String(d.commit_hash).slice(0, 7)) + '</span>・' : '') +\n '更新 ' + esc(fmtDateTime(l.updated_at) || '—');\n return '<div class=\"kcard\" data-lib=\"' + esc(l.library) + '\">' +\n '<div class=\"kt\">' + esc(l.library) + (S.library === l.library ? ' <span class=\"tag\" style=\"font-size:11.5px;vertical-align:middle\">搜尋中</span>' : '') + '</div>' +\n '<div class=\"ks\">' + (l.narrative ? esc(l.narrative) : '<span class=\"dim\">(此庫尚無 narrative——recompute 時可帶入)</span>') + '</div>' +\n (ents && ents.length ? '<div style=\"display:flex;gap:6px;flex-wrap:wrap\">' + lmEntityLine(ents) + '</div>' : '') +\n // Arcrun#87 三次收尾(2026-08-13):triplet_count=0 不等於這庫沒有知識——entries 有標庫、\n // 只是三元組萃取沒對它跑過(kb 以外幾乎全庫皆此況)。entry_count>0 時附一句,別讓看板\n // 的「0 三元組」被讀成「這庫是空的」(同 MCP 端 kbdb_map.ts 的 entryOnlyHint 同一件事)。\n '<div class=\"km\"><span class=\"mono\" style=\"color:var(--amber)\">' + (Number(l.triplet_count) || 0) + ' 三元組' +\n (!(Number(l.triplet_count) || 0) && (Number(l.entry_count) || 0) > 0\n ? '<span class=\"dim\">・' + (Number(l.entry_count) || 0) + ' 筆原始內容(尚未萃取)</span>' : '') + '</span>' +\n '<span class=\"dim\" style=\"margin-left:auto;font-size:12.5px\">' + stamp + '</span></div></div>';\n }).join('');\n }\n function renderLmBridges(details) {\n // 跨庫橋:詳圖 bridges[{entity, libraries[]}],多庫詳圖去重後列一小區;沒資料就整區不出\n var seen = {}, rows = [];\n Object.keys(details).forEach(function (k) {\n (details[k].bridges || []).forEach(function (b) {\n if (!b || !b.entity || seen[b.entity]) return;\n seen[b.entity] = true;\n rows.push(b);\n });\n });\n if (!rows.length) { $('lm-bridges').innerHTML = ''; return; }\n $('lm-bridges').innerHTML = '<div style=\"margin-top:14px;padding:14px 16px;border-radius:12px;background:rgba(var(--ok-rgb),.05);border:1px solid rgba(var(--ok-rgb),.2)\">' +\n '<div style=\"font-size:13px;letter-spacing:.14em;color:rgba(var(--ink-rgb),.5);margin-bottom:8px\">跨庫橋(同一 entity 出現在多個庫)</div>' +\n '<div style=\"display:flex;gap:8px;flex-wrap:wrap\">' + rows.slice(0, 12).map(function (b) {\n return '<span class=\"tag green\">' + esc(b.entity) + '</span><span class=\"dim\" style=\"font-size:12.5px;align-self:center\">' + esc((b.libraries || []).join(' ↔ ')) + '</span>';\n }).join('<span style=\"width:6px\"></span>') + '</div></div>';\n }\n function loadLibraryMap() {\n fetch(API_BASE + '/kbdb/map', { headers: apiHeaders() })\n .then(function (r) { return r.json().then(function (d) { return { ok: r.ok, status: r.status, d: d }; }); })\n .then(function (x) {\n if (!x.ok || x.d.success === false) {\n lmHonest('讀不到藏書地圖', esc(x.d.error || ('HTTP ' + x.status)) + '<br>不影響下方搜尋,可直接搜全庫。');\n return;\n }\n var libs = x.d.libraries || [];\n if (!libs.length) {\n lmHonest('還沒有藏書地圖', '這個租戶目前沒有任何三元組資料(地圖是查詢時即時核對重算的,不是要人手動 backfill——資料一進來下次載入就會出現)。<br>不影響下方搜尋,可直接搜全庫。');\n return;\n }\n LM.libs = libs; LM.details = {};\n renderLmCards(libs, {});\n Promise.allSettled(libs.map(function (l) {\n return fetch(API_BASE + '/kbdb/map/' + encodeURIComponent(l.library), { headers: apiHeaders() })\n .then(function (r) { return r.ok ? r.json() : null; });\n })).then(function (rs) {\n var details = {};\n rs.forEach(function (r) {\n if (r.status === 'fulfilled' && r.value && r.value.map && r.value.map.library) details[r.value.map.library] = r.value.map;\n });\n LM.details = details;\n renderLmCards(libs, details);\n renderLmBridges(details);\n });\n })\n .catch(function (e) { lmHonest('地圖服務不可達', esc(friendlyErr(e)) + '<br>不影響下方搜尋,可直接搜全庫。'); });\n }\n // 點庫卡片=設 library filter/kbdb/search 既有 library 參數,多值逗號分隔——此處單庫)進庫搜尋\n $('lm-cards').addEventListener('click', function (ev) {\n var t = ev.target.closest('[data-lib]');\n if (!t) return;\n S.library = t.getAttribute('data-lib');\n renderLibBar();\n if (LM.libs) renderLmCards(LM.libs, LM.details);\n $('se-q').focus();\n if ($('se-q').value.trim()) doSearch();\n toast('已鎖定庫「' + S.library + '」——輸入關鍵字搜這個庫');\n });\n function renderLibBar() {\n $('se-libbar').innerHTML = S.library\n ? '<div style=\"margin-top:10px;display:flex;align-items:center;gap:8px;font-size:14px\">' +\n '<span class=\"tag\">庫 ' + esc(S.library) + '</span>' +\n '<button class=\"chip\" id=\"se-libclear\" style=\"padding:5px 12px;font-size:13px\">✕ 清除庫篩選(搜全館)</button></div>'\n : '';\n var clear = document.getElementById('se-libclear');\n if (clear) clear.addEventListener('click', function () {\n S.library = '';\n renderLibBar();\n if (LM.libs) renderLmCards(LM.libs, LM.details);\n if ($('se-q').value.trim()) doSearch();\n });\n }\n function renderChips() {\n $('se-chips').innerHTML = CHIPS.map(function (c, i) {\n return '<button class=\"chip' + (S.chip === c.v ? ' on' : '') + '\" data-chip=\"' + i + '\">' + esc(c.label) + '</button>';\n }).join('');\n }\n $('se-chips').addEventListener('click', function (ev) {\n var t = ev.target.closest('[data-chip]');\n if (!t) return;\n S.chip = CHIPS[Number(t.getAttribute('data-chip'))].v;\n renderChips();\n if ($('se-q').value.trim()) doSearch();\n });\n // 頭部統計=精耕層 live 數字(leo 2026-07-07 裁:45.8 萬 14-E 搬遷遺產已 deprecated、\n // 之後要刪——不再拿遺產總數撐場面,只顯示真的新的)。搜尋本身仍搜全庫,資料不藏。\n function loadScale() {\n fetch(API_BASE + '/console/kb-scale-data')\n .then(function (r) { return r.ok ? r.json() : null; })\n .then(function (d) {\n // #100:讀不到就明說讀不到(原本靜默 return,會把上一輪的舊數字留在畫面上)\n if (!d) { $('se-scale').textContent = '精耕層 讀不到(規模統計讀取失敗,不影響搜尋)'; return; }\n var n = function (v) { return v == null ? '讀不到' : v.toLocaleString(); };\n var parts = ['wiki 卡 ' + n(d.wiki_card_total), '三元組 ' + n(d.triplets_total), '已嵌入 ' + n(d.embedded)];\n var latest = d.wiki_card_latest_ago_minutes;\n $('se-scale').textContent = '精耕層 ' + parts.join('・') +\n (latest != null && latest >= 0 ? '・最近寫入 ' + ckAge(latest) : '');\n })\n .catch(function () { $('se-scale').textContent = '精耕層 讀不到(規模統計讀取失敗,不影響搜尋)'; });\n }\n $('se-sem').addEventListener('click', function () {\n S.semantic = !S.semantic;\n $('se-sem').classList.toggle('on', S.semantic);\n if ($('se-q').value.trim()) doSearch();\n });\n $('se-q').addEventListener('keydown', function (ev) { if (ev.key === 'Enter') doSearch(); });\n function entryTitle(e) {\n if (e.page_name) return e.page_name;\n var first = String(e.content || '').split(/\\r?\\n/).find(function (l) { return l.trim(); }) || '';\n first = first.replace(/^#+\\s*/, '').replace(/^[-*>]\\s*/, '').trim();\n if (first.length > 60) first = first.slice(0, 60) + '…';\n return first || '(無標題・' + (e.entry_type || 'entry') + '';\n }\n function entrySnippet(e) {\n var lines = String(e.content || '').split(/\\r?\\n/).filter(function (l) { return l.trim(); });\n var body = lines.slice(1).join(' ').replace(/\\s+/g, ' ').trim();\n if (!body) body = lines.join(' ');\n if (body.length > 140) body = body.slice(0, 140) + '…';\n return body;\n }\n function doSearch() {\n var q = $('se-q').value.trim();\n if (!q) { $('se-count').textContent = '請輸入查詢字'; return; }\n $('se-banner').innerHTML = '';\n $('se-count').textContent = '查詢中…';\n $('se-results').innerHTML = '';\n var url = API_BASE + '/kbdb/search?q=' + encodeURIComponent(q) + '&mode=' + (S.semantic ? 'semantic' : 'keyword');\n if (S.chip) url += '&entry_type=' + encodeURIComponent(S.chip);\n // 藏書地圖進庫(M5/R4):library filter/kbdb/search 既有參數(portal-auth P1 順延項),不新造\n if (S.library) url += '&library=' + encodeURIComponent(S.library);\n fetch(url, { headers: apiHeaders() })\n .then(function (r) { return r.json().then(function (d) { return { ok: r.ok, status: r.status, d: d }; }); })\n .then(function (x) {\n if (!x.ok) { $('se-count').innerHTML = '<span class=\"err\">' + esc(x.d.error || ('查詢失敗(HTTP ' + x.status + '')) + '</span>'; return; }\n var d = x.d;\n if (S.semantic && d.mode === 'keyword') {\n // 2026-08-09 leo:語意搜尋是安裝即提供的功能,降級=故障,不說「尚未啟用」。\n $('se-banner').innerHTML = '<div class=\"honest\" style=\"margin-top:18px\"><div class=\"h\">語意搜尋目前故障</div><div class=\"b\">' + esc(d.capability_hint || '語意搜尋目前故障(實例缺 Vectorize/AI 設定),以下先給關鍵字結果,不假裝是語意結果。') + '<br>維運資訊:' + esc(d.admin_hint || '(此版本後端未回報細節)') + '</div></div>';\n }\n var entries = d.entries || [];\n $('se-count').textContent = '命中 ' + entries.length + ' 筆・模式 ' + (d.mode || 'keyword') +\n '・搜尋範圍=' + (S.library ? '庫「' + S.library + '」' : '全庫(含 14-E 遺產)');\n if (!entries.length) {\n $('se-results').innerHTML = '<div class=\"muted\" style=\"padding:30px 10px;text-align:center;grid-column:1/-1\">找不到「' + esc(q) + '」——換個關鍵字試試。</div>';\n return;\n }\n $('se-results').innerHTML = entries.map(function (e) {\n // 精耕層(wiki_card)綠標突顯;其餘照 entry_type 原樣(不誤標——block/value/note\n // 大宗是 14-E 遺產,但 entry_type 本身不足以斷言,僅精耕層正向標記)\n var typeTag = e.entry_type === 'wiki_card'\n ? '<span class=\"tag green\">wiki_card・精耕</span>'\n : '<span class=\"tag\">' + esc(e.entry_type || 'entry') + '</span>';\n return '<div class=\"kcard\" data-card=\"' + esc(e.id) + '\">' +\n '<div class=\"kt\">' + esc(entryTitle(e)) + '</div>' +\n '<div class=\"ks\">' + esc(entrySnippet(e)) + '</div>' +\n '<div class=\"km\">' + typeTag +\n (e.source ? '<span class=\"dim\">' + esc(e.source) + '</span>' : '') +\n '<span class=\"dim mono\" style=\"margin-left:auto\">' + esc(fmtDate(e.created_at)) + '</span></div></div>';\n }).join('');\n })\n .catch(function (e) { $('se-count').innerHTML = '<span class=\"err\">請求失敗:' + esc(friendlyErr(e)) + '</span>'; });\n }\n $('se-results').addEventListener('click', function (ev) {\n var t = ev.target.closest('[data-card]');\n if (t) nav('card', t.getAttribute('data-card'));\n });\n\n // ── 卡片詳頁 + 關聯 ──\n function loadCard() {\n if (!S.cardId) { $('cd-main').innerHTML = '<div class=\"muted\" style=\"padding:24px 0\">沒有指定卡片——從「總庫搜尋」點一張進來。</div>'; renderGraphEmpty('尚未載入卡片'); return; }\n $('cd-main').innerHTML = '<div class=\"muted\" style=\"padding:24px 0\">載入中…</div>';\n fetch(API_BASE + '/kbdb/entries/' + encodeURIComponent(S.cardId), { headers: apiHeaders() })\n .then(function (r) { return r.json().then(function (d) { return { ok: r.ok, d: d }; }); })\n .then(function (x) {\n if (!x.ok || !x.d.entry) { $('cd-main').innerHTML = '<div class=\"err\" style=\"padding:24px 0\">' + esc(x.d.error || '讀不到這張卡片') + '</div>'; renderGraphEmpty('讀不到卡片'); return; }\n var e = x.d.entry;\n var title = entryTitle(e);\n var html = '<div class=\"cardtitle\">' + esc(title) + '</div>' +\n '<div style=\"display:flex;gap:10px;align-items:center;margin-top:12px;font-size:13.5px;flex-wrap:wrap\">' +\n '<span class=\"tag\">' + esc(e.entry_type || 'entry') + '</span>' +\n (e.page_name ? '<span class=\"tag green\">' + esc(e.page_name) + '</span>' : '') +\n '<span class=\"muted mono\">' + esc(fmtDateTime(e.created_at)) + '</span></div>' +\n '<div class=\"md\">' + mdRender(e.content || '(此條目沒有內文)') + '</div>' +\n (e.source\n ? '<div class=\"srcline\"><span style=\"font-size:13px;letter-spacing:.14em;color:rgba(var(--ink-rgb),.5);flex:none\">來源回溯</span><span class=\"mono\" style=\"font-size:14px;color:var(--amber);word-break:break-all\">' + esc(e.source) + '</span></div>'\n : '');\n $('cd-main').innerHTML = html;\n var nodeName = e.page_name || title;\n S.graphCenter = nodeName;\n loadNeighbors(nodeName);\n })\n .catch(function (er) { $('cd-main').innerHTML = '<div class=\"err\" style=\"padding:24px 0\">請求失敗:' + esc(friendlyErr(er)) + '</div>'; renderGraphEmpty('請求失敗'); });\n }\n function renderGraphEmpty(msg) {\n $('cd-graph').innerHTML = '<div class=\"graphbox\" style=\"display:grid;place-items:center;height:160px\"><span class=\"muted\" style=\"font-size:14px;padding:0 20px;text-align:center\">' + esc(msg) + '</span></div>';\n $('cd-neighbors').innerHTML = '';\n }\n function loadNeighbors(name) {\n renderGraphEmpty('查詢關聯中…');\n fetch(API_BASE + '/kbdb/graph/neighbors/' + encodeURIComponent(name), { headers: apiHeaders() })\n .then(function (r) { return r.json().then(function (d) { return { ok: r.ok, status: r.status, d: d }; }); })\n .then(function (x) {\n if (!x.ok) { renderGraphEmpty(x.d.error || ('關聯查詢失敗(HTTP ' + x.status + '')); return; }\n var neighbors = x.d.neighbors || [];\n var edges = x.d.edges || [];\n if (!neighbors.length) { renderGraphEmpty('尚無關聯資料——這張卡還沒有 triplet 連進知識圖譜。'); return; }\n renderGraph(name, neighbors.slice(0, 10));\n $('cd-neighbors').innerHTML = edges.slice(0, 12).map(function (t) {\n var other = t.subject === name ? t.object : t.subject;\n return '<div class=\"nbrow\" data-gnode=\"' + esc(other) + '\">' +\n '<span class=\"tag green\" style=\"flex:none\">' + esc(t.predicate || '關聯') + '</span>' +\n '<span style=\"word-break:break-word\">' + esc(other) + '</span>' +\n '<span style=\"margin-left:auto;color:rgba(var(--amber-rgb),.6);flex:none\"></span></div>';\n }).join('');\n })\n .catch(function (e) { renderGraphEmpty('關聯服務不可達:' + friendlyErr(e)); });\n }\n function renderGraph(center, nodes) {\n var n = nodes.length || 1;\n var lines = '', chips = '';\n for (var i = 0; i < n; i++) {\n var a = (-90 + i * (360 / n)) * Math.PI / 180;\n var x = 50 + 39 * Math.cos(a), y = 50 + 37 * Math.sin(a);\n lines += '<line x1=\"50\" y1=\"50\" x2=\"' + x.toFixed(2) + '\" y2=\"' + y.toFixed(2) + '\" stroke=\"rgba(var(--ok-rgb),.3)\" stroke-width=\"1\" vector-effect=\"non-scaling-stroke\" stroke-dasharray=\"4 4\"/>';\n chips += '<div class=\"gnode\" style=\"left:' + x.toFixed(2) + '%;top:' + y.toFixed(2) + '%\" data-gnode=\"' + esc(nodes[i]) + '\">' + esc(nodes[i]) + '</div>';\n }\n var shortCenter = center.length > 16 ? center.slice(0, 16) + '…' : center;\n $('cd-graph').innerHTML = '<div class=\"graphbox\">' +\n '<svg viewBox=\"0 0 100 100\" preserveAspectRatio=\"none\" style=\"position:absolute;inset:0;width:100%;height:100%\">' + lines + '</svg>' +\n '<div class=\"gcenter\"><span>' + esc(shortCenter) + '</span></div>' + chips +\n '<div style=\"position:absolute;right:12px;bottom:10px;font-size:11.5px;color:rgba(var(--ink-rgb),.35)\">╌ 知識圖譜鄰居(點節點展開)</div></div>';\n }\n document.addEventListener('click', function (ev) {\n var t = ev.target.closest('[data-gnode]');\n if (!t) return;\n var name = t.getAttribute('data-gnode');\n S.graphCenter = name;\n loadNeighbors(name);\n });\n\n // ── 工作流 ──\n function loadWorkflows() {\n fetch(API_BASE + '/webhooks/named', { headers: apiHeaders() })\n .then(function (r) { return r.json().then(function (d) { return { ok: r.ok, d: d }; }); })\n .then(function (x) {\n if (!x.ok) { $('wf-list').innerHTML = '<div class=\"err\">' + esc(x.d.error || '讀取失敗') + '</div>'; return; }\n S.wfCache = x.d.workflows || [];\n $('wf-count').textContent = S.wfCache.length + ' 條自動化';\n renderWorkflows();\n })\n .catch(function (e) { $('wf-list').innerHTML = '<div class=\"err\">請求失敗:' + esc(friendlyErr(e)) + '</div>'; });\n }\n $('wf-q').addEventListener('input', function () { renderWorkflows(); });\n function renderWorkflows(openName) {\n var list = S.wfCache || [];\n var q = $('wf-q').value.trim().toLowerCase();\n if (q) list = list.filter(function (w) { return (w.name + ' ' + (w.description || '')).toLowerCase().indexOf(q) >= 0; });\n list = list.slice().sort(function (a, b) { return (S.pins[b.name] ? 1 : 0) - (S.pins[a.name] ? 1 : 0); });\n if (!list.length) {\n $('wf-list').innerHTML = '<div class=\"honest\"><div class=\"h\">' + (q ? '沒有符合的工作流' : '還沒有任何工作流') + '</div><div class=\"b\">' + (q ? '換個關鍵字試試。' : '用 acr push 部署第一條 workflow 後,這裡就會出現。') + '</div></div>';\n return;\n }\n $('wf-list').innerHTML = list.map(function (w) {\n var pinned = !!S.pins[w.name];\n var open = w.name === openName;\n return '<div class=\"card-item' + (pinned ? ' hl' : '') + '\" data-wf=\"' + esc(w.name) + '\">' +\n '<div class=\"rowhead\" data-wftoggle=\"' + esc(w.name) + '\">' +\n '<button class=\"pinbtn' + (pinned ? ' on' : '') + '\" data-wfpin=\"' + esc(w.name) + '\" title=\"釘選\">' + (pinned ? '★' : '☆') + '</button>' +\n '<div style=\"min-width:0\"><div style=\"font-size:17px;font-weight:600;line-height:1.4;word-break:break-word\">' + esc(w.name) + '</div>' +\n '<div style=\"margin-top:3px;font-size:13.5px;color:rgba(var(--ink-rgb),.5)\">' + esc(w.cron_expr ? '排程 ' + w.cron_expr : '事件觸發') + (w.created_at ? '・建立 ' + esc(fmtDate(w.created_at)) : '') + '</div></div>' +\n '<span style=\"margin-left:auto;color:rgba(var(--amber-rgb),.6);flex:none\">' + (open ? '▾' : '') + '</span></div>' +\n (open ? renderWfBody(w) : '') + '</div>';\n }).join('');\n if (openName) fetchWfRuns(openName);\n }\n function renderWfBody(w) {\n return '<div class=\"rowbody\">' +\n '<div style=\"margin-top:14px;font-size:15.5px;line-height:1.7;color:rgba(var(--ink-rgb),.7)\">' + (w.description ? esc(w.description) : '<span class=\"dim\">(未填描述——re-deploy 時補一句「能做什麼」它才搜得到)</span>') + '</div>' +\n '<div class=\"urlbox\" style=\"margin-top:14px\"><span style=\"font-size:12.5px;letter-spacing:.1em;color:rgba(var(--ink-rgb),.45);flex:none\">觸發網址</span>' +\n '<span class=\"u\">' + esc(w.webhook_url || '') + '</span>' +\n '<button class=\"btn2\" style=\"margin-left:auto;flex:none;padding:7px 13px;font-size:13.5px\" data-wfcopy=\"' + esc(w.webhook_url || '') + '\">複製</button></div>' +\n '<div style=\"margin-top:14px;font-size:13px;letter-spacing:.14em;color:rgba(var(--ink-rgb),.5)\">最近執行</div>' +\n '<div id=\"wf-runs\" style=\"margin-top:8px;display:flex;flex-direction:column;gap:6px\"><span class=\"dim\" style=\"font-size:14px\">載入中…</span></div>' +\n '<button class=\"btn\" style=\"margin-top:16px;width:100%\" data-wfrun=\"' + esc(w.name) + '\">手動觸發</button>' +\n '<div id=\"wf-runmsg\" style=\"margin-top:8px;font-size:14px;min-height:1.2em\"></div></div>';\n }\n var wfOpen = '';\n $('wf-list').addEventListener('click', function (ev) {\n var pin = ev.target.closest('[data-wfpin]');\n if (pin) {\n var name = pin.getAttribute('data-wfpin');\n if (S.pins[name]) delete S.pins[name]; else S.pins[name] = true;\n localStorage.setItem('arcrun_console_pins', JSON.stringify(S.pins));\n renderWorkflows(wfOpen);\n ev.stopPropagation();\n return;\n }\n var copy = ev.target.closest('[data-wfcopy]');\n if (copy) {\n var url = copy.getAttribute('data-wfcopy');\n (navigator.clipboard ? navigator.clipboard.writeText(url) : Promise.reject()).then(\n function () { toast('已複製觸發網址'); },\n function () { toast('複製失敗——手動選取網址'); }\n );\n ev.stopPropagation();\n return;\n }\n var run = ev.target.closest('[data-wfrun]');\n if (run) { triggerWf(run.getAttribute('data-wfrun'), run); ev.stopPropagation(); return; }\n var tog = ev.target.closest('[data-wftoggle]');\n if (tog) {\n var n = tog.getAttribute('data-wftoggle');\n wfOpen = wfOpen === n ? '' : n;\n renderWorkflows(wfOpen);\n }\n });\n function fetchWfRuns(name) {\n var box = document.getElementById('wf-runs');\n if (!box) return;\n fetch(API_BASE + '/workflows/' + encodeURIComponent(name) + '/executions?limit=3', { headers: apiHeaders() })\n .then(function (r) { return r.json(); })\n .then(function (d) {\n var runs = (d.data && d.data.executions) || [];\n if (!runs.length) { box.innerHTML = '<span class=\"dim\" style=\"font-size:14px\">尚無執行紀錄</span>'; return; }\n box.innerHTML = runs.map(function (r) {\n var okRun = r.verdict === 'success';\n return '<div style=\"display:flex;gap:10px;align-items:baseline;font-size:14.5px\">' +\n '<span style=\"flex:none;font-size:10px;color:' + (okRun ? 'var(--ok)' : 'var(--err)') + '\">●</span>' +\n '<span style=\"color:rgba(var(--ink-rgb),.7)\">' + (okRun ? '成功' : '失敗') + (typeof r.duration_ms === 'number' ? '・' + r.duration_ms + 'ms' : '') + (r.message && !okRun ? '・' + esc(String(r.message).slice(0, 60)) : '') + '</span>' +\n '<span class=\"dim mono\" style=\"margin-left:auto;font-size:12.5px\">' + esc(r.recorded_at ? fmtDateTime(r.recorded_at) : (r.timestamp ? fmtDateTime(Number(r.timestamp)) : '')) + '</span></div>';\n }).join('');\n })\n .catch(function () { box.innerHTML = '<span class=\"dim\" style=\"font-size:14px\">執行紀錄讀取失敗</span>'; });\n }\n function triggerWf(name, btn) {\n btn.disabled = true; btn.textContent = '執行中…';\n var msg = document.getElementById('wf-runmsg');\n fetch(API_BASE + '/webhooks/named/' + encodeURIComponent(name) + '/trigger', {\n method: 'POST',\n headers: Object.assign({ 'Content-Type': 'application/json' }, apiHeaders()),\n body: '{}'\n })\n .then(function (r) { return r.json().then(function (d) { return { ok: r.ok, d: d }; }); })\n .then(function (x) {\n btn.disabled = false; btn.textContent = '手動觸發';\n if (x.ok && x.d.success !== false) {\n if (msg) msg.innerHTML = '<span class=\"ok\">✓ 執行成功' + (typeof x.d.duration_ms === 'number' ? '・' + x.d.duration_ms + 'ms' : '') + '</span>';\n toast('「' + name + '」執行完成');\n } else {\n if (msg) msg.innerHTML = '<span class=\"err\">✕ ' + esc(x.d.error || '執行失敗') + '</span>';\n }\n fetchWfRuns(name);\n })\n .catch(function (e) {\n btn.disabled = false; btn.textContent = '手動觸發';\n if (msg) msg.innerHTML = '<span class=\"err\">請求失敗:' + esc(friendlyErr(e)) + '</span>';\n });\n }\n\n // ── 零件 / recipesv0 搜尋台保留區)──\n $('cr-go').addEventListener('click', doCompSearch);\n $('cr-q').addEventListener('keydown', function (ev) { if (ev.key === 'Enter') doCompSearch(); });\n function doCompSearch() {\n var q = $('cr-q').value.trim();\n if (!q) return;\n var out = $('cr-out');\n out.innerHTML = '<div class=\"muted\">查詢中…</div>';\n Promise.allSettled([\n fetch(REGISTRY_BASE + '/components/search?q=' + encodeURIComponent(q)).then(function (r) { return r.json().then(function (d) { return { ok: r.ok, d: d }; }); }),\n fetch(API_BASE + '/public-recipes?q=' + encodeURIComponent(q)).then(function (r) { return r.json().then(function (d) { return { ok: r.ok, d: d }; }); })\n ]).then(function (rs) {\n var html = '';\n var comp = rs[0];\n html += '<div class=\"dim\" style=\"font-size:12.5px;letter-spacing:.1em;margin:10px 0 6px\">COMPONENTS</div>';\n if (comp.status === 'fulfilled' && comp.value.ok) {\n var results = (comp.value.d.data && comp.value.d.data.results) || [];\n html += results.length\n ? results.map(function (c) { return '<div class=\"card-item\" style=\"padding:10px 14px;margin-bottom:6px;font-size:14px\"><span class=\"tag\">' + esc(c.canonical_id || c.id) + '</span> <span class=\"muted\">' + esc(c.description || c.name || '') + '</span></div>'; }).join('')\n : '<div class=\"muted\" style=\"font-size:14px\">沒查到符合的 component</div>';\n } else {\n html += '<div class=\"err\" style=\"font-size:14px\">components 查詢失敗(零件庫不可達)</div>';\n }\n var rec = rs[1];\n html += '<div class=\"dim\" style=\"font-size:12.5px;letter-spacing:.1em;margin:12px 0 6px\">RECIPES</div>';\n if (rec.status === 'fulfilled' && rec.value.ok) {\n var d = rec.value.d;\n if (d.found === false) {\n html += '<div class=\"muted\" style=\"font-size:14px\">' + esc(d.hint || '沒查到符合的 recipe') + '</div>';\n } else {\n var recipes = d.recipes || [];\n html += recipes.length\n ? recipes.map(function (r) { return '<div class=\"card-item\" style=\"padding:10px 14px;margin-bottom:6px;font-size:14px\"><span class=\"tag\">' + esc(r.canonical_id) + '</span> <span class=\"muted\">' + esc(r.description || r.display_name || '') + '</span></div>'; }).join('')\n : '<div class=\"muted\" style=\"font-size:14px\">沒查到符合的 recipe</div>';\n }\n } else {\n html += '<div class=\"err\" style=\"font-size:14px\">recipes 查詢失敗</div>';\n }\n out.innerHTML = html;\n });\n }\n\n // ── 憑證管理 ──\n $('cred-addbtn').addEventListener('click', function () {\n var f = $('cred-form');\n f.style.display = f.style.display === 'none' ? '' : 'none';\n });\n $('cred-save').addEventListener('click', function () {\n var name = $('cred-name').value.trim(), service = $('cred-service').value.trim(), value = $('cred-secret').value;\n var st = $('cred-form-status');\n if (!name || !value) { st.innerHTML = '<span class=\"err\">名稱與密文值必填</span>'; return; }\n if (!/^\\w+$/.test(name)) { st.innerHTML = '<span class=\"err\">名稱只能包含英文字母、數字和底線</span>'; return; }\n st.textContent = '保存中…';\n fetch(API_BASE + '/credentials', {\n method: 'POST',\n headers: Object.assign({ 'Content-Type': 'application/json' }, apiHeaders()),\n body: JSON.stringify({ name: name, value: value, service: service || undefined })\n })\n .then(function (r) { return r.json().then(function (d) { return { ok: r.ok, d: d }; }); })\n .then(function (x) {\n if (!x.ok || x.d.success === false) { st.innerHTML = '<span class=\"err\">' + esc(x.d.error || '保存失敗') + '</span>'; return; }\n st.textContent = '';\n $('cred-name').value = ''; $('cred-service').value = ''; $('cred-secret').value = '';\n $('cred-form').style.display = 'none';\n toast('已加密保存');\n loadCreds();\n })\n .catch(function (e) { st.innerHTML = '<span class=\"err\">請求失敗:' + esc(friendlyErr(e)) + '</span>'; });\n });\n var credOpen = '';\n var credCache = [];\n function loadCreds() {\n fetch(API_BASE + '/credentials/catalog', { headers: apiHeaders() })\n .then(function (r) { return r.json().then(function (d) { return { ok: r.ok, d: d }; }); })\n .then(function (x) {\n if (!x.ok || x.d.success === false) {\n $('cred-list').innerHTML = '<div class=\"honest\"><div class=\"h\">目錄讀取失敗</div><div class=\"b\">' + esc(x.d.error || '未知錯誤') + '</div></div>';\n return;\n }\n credCache = x.d.credentials || [];\n renderCreds();\n })\n .catch(function (e) { $('cred-list').innerHTML = '<div class=\"err\">請求失敗:' + esc(friendlyErr(e)) + '</div>'; });\n }\n function renderCreds() {\n if (!credCache.length) {\n $('cred-list').innerHTML = '<div class=\"honest\"><div class=\"h\">還沒有任何憑證</div><div class=\"b\">按「+ 新增憑證」加入第一筆。目錄只存名稱與服務,密文進 Workers Secrets、不可回看。</div></div>';\n return;\n }\n $('cred-list').innerHTML = credCache.map(function (c) {\n var open = credOpen === c.name;\n var initial = (c.service || c.name || '?').slice(0, 1).toUpperCase();\n return '<div class=\"card-item' + (open ? ' hl' : '') + '\">' +\n '<div class=\"rowhead\" data-credtoggle=\"' + esc(c.name) + '\">' +\n '<span class=\"avatar\">' + esc(initial) + '</span>' +\n '<div style=\"min-width:0\"><div style=\"font-size:16.5px;font-weight:600;word-break:break-all\">' + esc(c.name) + '</div>' +\n '<div style=\"margin-top:2px;font-size:13.5px;color:rgba(var(--ink-rgb),.5)\">' + esc(c.service || '未填服務') + '・建立於 ' + esc(fmtDateTime(c.created_at) || '—') + '(台北)</div></div>' +\n '<div style=\"margin-left:auto;text-align:right;font-size:12.5px;color:rgba(var(--ink-rgb),.4);flex:none\">最後使用<br>' + esc(c.last_used_at ? fmtDateTime(c.last_used_at) : '尚未記錄') + '</div></div>' +\n (open\n ? '<div class=\"rowbody\">' +\n '<div class=\"maskline\" style=\"margin-top:14px\"><span class=\"mono\" style=\"font-size:16px;letter-spacing:.3em;color:rgba(var(--ink-rgb),.4)\">••••••••••••••••</span><span style=\"margin-left:auto;font-size:12.5px;color:rgba(var(--ink-rgb),.4)\">已加密・不可回看</span></div>' +\n '<textarea class=\"txt\" id=\"cred-newval\" placeholder=\"貼上新值以整筆替換…\" rows=\"2\" style=\"margin-top:10px\"></textarea>' +\n '<div style=\"display:flex;gap:10px;margin-top:10px;flex-wrap:wrap\">' +\n '<button class=\"btn\" style=\"flex:1;min-width:140px\" data-credreplace=\"' + esc(c.name) + '\">整筆替換</button>' +\n '<button class=\"btn-danger\" disabled title=\"刪除端點尚未接上新目錄(T9 範圍)\">刪除・即將開通</button></div>' +\n '<div id=\"cred-msg\" style=\"margin-top:8px;font-size:14px;min-height:1.2em\"></div></div>'\n : '') +\n '</div>';\n }).join('');\n }\n $('cred-list').addEventListener('click', function (ev) {\n var rep = ev.target.closest('[data-credreplace]');\n if (rep) {\n var name = rep.getAttribute('data-credreplace');\n var ta = document.getElementById('cred-newval');\n var msg = document.getElementById('cred-msg');\n var val = ta ? ta.value : '';\n if (!val.trim()) { if (msg) msg.innerHTML = '<span class=\"err\">先貼上新值</span>'; return; }\n rep.disabled = true;\n var cur = credCache.find(function (c) { return c.name === name; });\n fetch(API_BASE + '/credentials/' + encodeURIComponent(name), {\n method: 'PUT',\n headers: Object.assign({ 'Content-Type': 'application/json' }, apiHeaders()),\n body: JSON.stringify({ value: val, service: cur && cur.service ? cur.service : undefined })\n })\n .then(function (r) { return r.json().then(function (d) { return { ok: r.ok, d: d }; }); })\n .then(function (x) {\n rep.disabled = false;\n if (!x.ok || x.d.success === false) { if (msg) msg.innerHTML = '<span class=\"err\">' + esc(x.d.error || '替換失敗') + '</span>'; return; }\n credOpen = '';\n toast('「' + name + '」已整筆替換');\n loadCreds();\n })\n .catch(function (e) { rep.disabled = false; if (msg) msg.innerHTML = '<span class=\"err\">請求失敗:' + esc(friendlyErr(e)) + '</span>'; });\n return;\n }\n var tog = ev.target.closest('[data-credtoggle]');\n if (tog) {\n var n = tog.getAttribute('data-credtoggle');\n credOpen = credOpen === n ? '' : n;\n renderCreds();\n }\n });\n\n // ── 分流台(原收件匣,Arcrun#9todoinbox 二源、三欄 80/15/5、per-project chips)──\n // 頁面只渲染 /console/triage-data 的結果(分欄/計數判定在後端純函式);chips 切換與\n // 「顯示已完成」是同一包資料的前端過濾,零額外請求(leo 手機看,省來回)。\n var TG = { data: null, project: '', showDone: false };\n var TG_TIERS = [\n { key: 'ai', nm: 'AI 會幫我搞定', pc: '80%', empty: '這欄空的——還沒有分給 AI 的待辦' },\n { key: 'collab', nm: '協作・AI 做完你接手', pc: '15%', empty: '這欄空的——沒有要你配合的事' },\n { key: 'leo', nm: '非我不可', pc: '5%', empty: '這欄空的——沒有非你不可的事' }\n ];\n function triItem(m) {\n var done = m.status === 'done';\n var meta = '';\n if (m.marker) meta += '<span class=\"tag dim\">' + esc(m.marker) + '</span>';\n meta += '<span class=\"tag\">' + esc(m.project || '未分項') + '</span>';\n if (m.source) meta += '<span>' + esc(m.source) + '</span>';\n if (m.unclassified && m.origin === 'todo') meta += '<span class=\"tag red\">未分流</span>';\n // 誤勾救濟:done 清單裡給「還原」(status 回 new + 移除 checked_via/checked_at,端點同一個)\n if (done) meta += '<button class=\"tri-restore\" data-trirestore=\"' + esc(m.id) + '\">還原</button>';\n meta += '<span class=\"mono\" style=\"margin-left:auto\">' + esc(fmtDateTime(m.at)) + '</span>';\n // 勾掉=雙向銷案的 console 端終局(checked_via:console,萃取端絕不復活);\n // 後端回寫成功才改本地狀態移出三欄(done 預設隱藏),不樂觀假裝\n var body = done\n ? '<div class=\"tx\">' + esc(m.text) + '</div>'\n : '<div class=\"row\"><div class=\"tx\">' + esc(m.text) + '</div><button class=\"tri-check\" data-tricheck=\"' + esc(m.id) + '\" title=\"勾掉(銷案)\">✓</button></div>';\n return '<div class=\"tri-item ' + (done ? 'done' : 'new') + '\">' + body + '<div class=\"mt\">' + meta + '</div></div>';\n }\n function triChip(label, val, on) {\n return '<button class=\"chip' + (on ? ' on' : '') + '\" data-triproj=\"' + esc(val) + '\">' + esc(label) + '</button>';\n }\n function renderTriage() {\n var d = TG.data || {};\n var items = d.items || [];\n var out = $('tg-out');\n // per-project chips:全部+各 project+(有未分項才出)未分項\n var chips = triChip('全部', '', TG.project === '');\n (d.projects || []).forEach(function (p) { chips += triChip(p, p, TG.project === p); });\n if (items.some(function (i) { return !i.project; })) chips += triChip('未分項', '__none__', TG.project === '__none__');\n $('tg-chips').innerHTML = items.length ? chips : '';\n if (!items.length) {\n out.innerHTML = '<div class=\"honest\" style=\"margin-top:14px\"><div class=\"h\">分流台是空的</div><div class=\"b\">資料源=KBDB todo entriesLogseq 萃取,ingest 灌入中)+ inbox entriesTelegram)。<br>寫入方尚未灌資料時這裡誠實顯示空。</div></div>';\n return;\n }\n var vis = items.filter(function (i) {\n return TG.project === '' || (TG.project === '__none__' ? !i.project : i.project === TG.project);\n });\n var doneN = vis.filter(function (i) { return i.status === 'done'; }).length;\n var html = '';\n TG_TIERS.forEach(function (t) {\n var news = vis.filter(function (i) { return i.tier === t.key && i.status !== 'done'; });\n var dones = TG.showDone ? vis.filter(function (i) { return i.tier === t.key && i.status === 'done'; }) : [];\n html += '<div class=\"tri-sec ' + t.key + '\"><div class=\"tri-sechead\"><span class=\"dot\"></span><span class=\"nm serif\">' + t.nm + '</span><span class=\"pc\">' + t.pc + '</span><span class=\"ct\">' + news.length + ' 件</span></div>';\n if (!news.length && !dones.length) html += '<div class=\"muted\" style=\"font-size:14px;padding:10px 2px 0\">' + t.empty + '</div>';\n html += news.map(triItem).join('') + dones.map(triItem).join('');\n html += '</div>';\n });\n html += '<div style=\"margin:24px 0 20px;text-align:center\"><button class=\"btn3\" id=\"tg-donetoggle\" style=\"padding:9px 18px;font-size:13.5px;border-radius:999px\">' +\n (TG.showDone ? '隱藏已完成' : '顯示已完成(' + doneN + '') + '</button></div>';\n out.innerHTML = html;\n $('tg-donetoggle').addEventListener('click', function () { TG.showDone = !TG.showDone; renderTriage(); });\n }\n $('tg-chips').addEventListener('click', function (ev) {\n var t = ev.target.closest('[data-triproj]');\n if (!t) return;\n TG.project = t.getAttribute('data-triproj');\n renderTriage();\n });\n // 勾掉/還原:POST /console/triage-checkconsole session 保護的小端點——瀏覽器沒有 KBDB\n // tokenPATCH 由 server 端做,先 GET 原 entry 整串回寫防蓋掉別的欄位)。成功才動本地\n // 狀態重繪(該筆立即移出/回到三欄),失敗誠實 toast、按鈕解鎖可重試。\n function triageAct(id, action, btn) {\n btn.disabled = true;\n fetch(API_BASE + '/console/triage-check', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: 'Bearer ' + S.token },\n body: JSON.stringify({ entry_id: id, action: action })\n })\n .then(function (r) { return r.json().then(function (d) { return { ok: r.ok, status: r.status, d: d }; }); })\n .then(function (x) {\n if (!x.ok) { btn.disabled = false; toast(x.d.error || ('失敗(HTTP ' + x.status + '')); return; }\n var items = (TG.data && TG.data.items) || [];\n for (var i = 0; i < items.length; i++) {\n if (items[i].id === id) items[i].status = (action === 'restore' ? 'new' : 'done');\n }\n renderTriage();\n toast(action === 'restore' ? '已還原' : '已勾掉');\n })\n .catch(function (e) { btn.disabled = false; toast('請求失敗:' + friendlyErr(e)); });\n }\n $('tg-out').addEventListener('click', function (ev) {\n var chk = ev.target.closest('[data-tricheck]');\n if (chk) { triageAct(chk.getAttribute('data-tricheck'), 'check', chk); return; }\n var rst = ev.target.closest('[data-trirestore]');\n if (rst) triageAct(rst.getAttribute('data-trirestore'), 'restore', rst);\n });\n function loadTriage() {\n var out = $('tg-out');\n out.innerHTML = '<div class=\"muted\" style=\"padding:14px 0\">載入中…</div>';\n fetch(API_BASE + '/console/triage-data', { headers: { Authorization: 'Bearer ' + S.token } })\n .then(function (r) { return r.json().then(function (d) { return { ok: r.ok, status: r.status, d: d }; }); })\n .then(function (x) {\n if (!x.ok) {\n out.innerHTML = '<div class=\"honest\" style=\"margin-top:14px\"><div class=\"h\">讀不到分流台</div><div class=\"b\">' + esc(x.d.error || ('HTTP ' + x.status)) + '</div></div>';\n return;\n }\n TG.data = x.d;\n // 記著的 project 篩選若已不存在(資料變了)→ 退回全部,別讓頁面空得不明不白\n if (TG.project && TG.project !== '__none__' && (x.d.projects || []).indexOf(TG.project) < 0) TG.project = '';\n renderTriage();\n })\n .catch(function (e) { out.innerHTML = '<div class=\"err\" style=\"padding:14px 0\">請求失敗:' + esc(friendlyErr(e)) + '</div>'; });\n }\n\n // ── 設定 ──\n function loadSettings() {\n // vectorize 狀態:探測既有 /kbdb/search 的 mode / capability_hint(無新端點,誠實讀降級訊號)\n fetch(API_BASE + '/kbdb/search?q=mira&mode=semantic', { headers: apiHeaders() })\n .then(function (r) { return r.json(); })\n .then(function (d) {\n // t36:狀態照實顯示(live 探測 mode,不是讀設定值)。啟用時不再顯示任何操作指示——\n // 沒有東西要用戶操作;未啟用才給一句人話與下一步。\n // 2026-08-09 leo:語意搜尋是安裝即提供的功能——探測到降級=這台實例壞了,\n // 照實標「故障」,不說「尚未啟用」(那會把 bug 說成沒提供的功能)。\n var on = d.mode === 'semantic';\n $('st-vec').textContent = on\n ? '● 正常——搜尋頁切到「語意」就能用意思找資料。'\n : '○ 故障——語意搜尋是內建功能,這台實例現在少了它(系統端問題,不是操作問題)。';\n var hint = $('st-vec-hint');\n if (on) {\n hint.style.display = 'none';\n } else {\n hint.style.display = '';\n hint.innerHTML = '修復方式:重新跑一次安裝流程(用原本的 Cloudflare 帳號),會把缺的語意索引設定補回來;已建好的資料不會重來。'\n + (d.admin_hint ? '<br>維運資訊:' + esc(d.admin_hint) : '');\n }\n })\n .catch(function () {\n $('st-vec').textContent = '狀態偵測失敗(知識庫服務目前連不上)';\n var hint = $('st-vec-hint');\n hint.style.display = '';\n hint.textContent = '這通常是暫時的,稍後重新整理這一頁再看。';\n });\n // MCP token TTL(誠實佔位:只顯示目前生效值,不假裝能改)\n fetch(API_BASE + '/console/settings-data')\n .then(function (r) { return r.ok ? r.json() : null; })\n .then(function (d) {\n if (!d) { $('st-mcp-ttl').textContent = '讀取失敗'; return; }\n var days = Math.round(d.mcp_token_ttl_seconds / 86400 * 10) / 10;\n $('st-mcp-ttl').textContent = '目前生效:' + d.mcp_token_ttl_seconds.toLocaleString() + ' 秒(約 ' + days + ' 天)・' +\n (d.mcp_token_ttl_source === 'env' ? '來自部署端 env MCP_TOKEN_TTL' : '未設 env,用預設值 30 天');\n })\n .catch(function () { $('st-mcp-ttl').textContent = '讀取失敗'; });\n // 系統資訊:worker 自報 + 精耕層規模(14-E 遺產總數不再顯示,leo 2026-07-07 裁)\n Promise.allSettled([\n fetch(API_BASE + '/').then(function (r) { return r.json(); }),\n fetch(API_BASE + '/console/kb-scale-data').then(function (r) { return r.ok ? r.json() : null; })\n ]).then(function (rs) {\n var svc = rs[0].status === 'fulfilled' ? rs[0].value : {};\n var kb = rs[1].status === 'fulfilled' ? rs[1].value : null;\n var n = function (v) { return v == null ? '讀不到' : v.toLocaleString(); };\n var rows = '';\n rows += '<div class=\"kvline\"><span class=\"muted\">服務</span><span class=\"mono\" style=\"font-size:14px\">' + esc(svc.service || 'arcrun-cypher-executor') + '</span></div>';\n rows += '<div class=\"kvline\"><span class=\"muted\">版本</span><span class=\"mono\" style=\"color:var(--amber)\">' + esc(svc.version || '—') + '</span></div>';\n rows += '<div class=\"kvline\"><span class=\"muted\">部署位置</span><span class=\"mono\" style=\"font-size:14px\">' + esc(location.host) + '</span></div>';\n rows += '<div class=\"kvline\"><span class=\"muted\">租戶</span><span class=\"mono\">' + esc(S.tenant) + '</span></div>';\n rows += '<div class=\"kvline\"><span class=\"muted\">精耕層</span><span class=\"mono\" style=\"color:var(--amber)\">' + (kb ? 'wiki 卡 ' + n(kb.wiki_card_total) + '・三元組 ' + n(kb.triplets_total) + '・已嵌入 ' + n(kb.embedded) : '讀取失敗') + '</span></div>';\n $('st-info').innerHTML = rows;\n });\n }\n $('st-pw-save').addEventListener('click', function () {\n var oldPw = $('st-pw-old').value, email = $('st-pw-email').value.trim(), newPw = $('st-pw-new').value;\n var st = $('st-pw-status');\n if (!oldPw) { st.innerHTML = '<span class=\"err\">請先輸入舊密碼</span>'; return; }\n if (!email) { st.innerHTML = '<span class=\"err\">請輸入 Email(沿用原本的也要填)</span>'; return; }\n if (!newPw || newPw.length < 8) { st.innerHTML = '<span class=\"err\">新密碼至少 8 碼</span>'; return; }\n st.textContent = '更新中…';\n fetch(API_BASE + '/console/setup/reset', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ current_password: oldPw, email: email, password: newPw })\n })\n .then(function (r) { return r.json().then(function (d) { return { ok: r.ok, d: d }; }); })\n .then(function (x) {\n if (!x.ok) { st.innerHTML = '<span class=\"err\">' + esc(x.d.error || '更新失敗') + '</span>'; return; }\n st.innerHTML = '<span class=\"ok\">密碼已更新,下次登入用新帳密</span>';\n $('st-pw-old').value = ''; $('st-pw-email').value = ''; $('st-pw-new').value = '';\n toast('密碼已更新');\n })\n .catch(function (e) { st.innerHTML = '<span class=\"err\">請求失敗:' + esc(friendlyErr(e)) + '</span>'; });\n });\n // arcrun-rag#25portal admin 密碼救援——只吃 console owner sessionS.token,本頁登入用的\n // 那把),不吃 portal session,所以就算忘記 portal 密碼、進不去 portal 也走得通。\n $('st-portal-recover-btn').addEventListener('click', function () {\n var email = $('st-portal-recover-email').value.trim();\n var st = $('st-portal-recover-status');\n if (!email) { st.innerHTML = '<span class=\"err\">請輸入 Email</span>'; return; }\n st.textContent = '處理中…';\n fetch(API_BASE + '/portal/admin/recover-password', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: 'Bearer ' + S.token },\n body: JSON.stringify({ email: email })\n })\n .then(function (r) { return r.json().then(function (d) { return { ok: r.ok, d: d }; }); })\n .then(function (x) {\n if (!x.ok) { st.innerHTML = '<span class=\"err\">' + esc(x.d.error || '失敗') + '</span>'; return; }\n st.innerHTML = '<span class=\"ok\">新密碼:<code style=\"font-size:15px;user-select:all\">' + esc(x.d.password) + '</code>(只顯示這一次,請立刻抄下)</span>';\n $('st-portal-recover-email').value = '';\n toast('新密碼已產生,請立刻抄下');\n })\n .catch(function (e) { st.innerHTML = '<span class=\"err\">請求失敗:' + esc(friendlyErr(e)) + '</span>'; });\n });\n // t36:原本這裡綁在那顆假開關上(點了只會 toast 一段 CLI 指示)。開關已移除,\n // 這個 handler 也必須一起拿掉——留著會讓 $('st-vec-switch') 回 null、addEventListener\n // 當場拋錯,把後面所有綁定(含登出)一起打斷。\n $('st-logout').addEventListener('click', function () {\n var t = S.token;\n if (t) fetch(API_BASE + '/console/logout', { method: 'POST', headers: { Authorization: 'Bearer ' + t } }).catch(function () {});\n S.token = ''; S.tenant = '';\n localStorage.removeItem('arcrun_console_session');\n location.hash = '';\n checkConfigured();\n });\n\n init();\n})();\n</script>\n</body>\n</html>\n"},"/favicon.ico":{"type":"image/x-icon","b64":true,"data":"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"},"/favicon.svg":{"type":"image/svg+xml","b64":false,"data":"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 1024 1024\" role=\"img\" aria-label=\"arcrun icon\"><title>arcrun icon</title><rect width=\"1024\" height=\"1024\" fill=\"#17181A\"/><path fill=\"#FDFCFB\" fill-rule=\"nonzero\" d=\"M463.01,612.91 L436.06,612.91 L436.06,485.41 L435.86,477.78 L435.27,470.46 L434.28,463.44 L432.89,456.73 L431.11,450.31 L428.93,444.20 L426.36,438.39 L423.39,432.88 L420.02,427.68 L416.26,422.78 L412.10,418.18 L407.55,413.88 L402.62,409.91 L397.31,406.28 L391.65,402.99 L385.61,400.06 L379.21,397.47 L372.44,395.22 L365.30,393.32 L357.79,391.76 L349.92,390.55 L341.68,389.69 L333.08,389.17 L324.10,389.00 L317.39,389.10 L310.90,389.40 L304.63,389.89 L298.59,390.58 L292.77,391.47 L287.17,392.56 L281.80,393.85 L276.65,395.33 L271.72,397.02 L267.02,398.90 L262.53,400.98 L258.28,403.25 L254.20,405.69 L250.26,408.26 L246.45,410.95 L242.78,413.76 L239.25,416.71 L235.86,419.77 L232.60,422.97 L229.48,426.29 L226.50,429.74 L223.65,433.31 L220.94,437.01 L218.37,440.83 L257.76,476.08 L259.43,473.77 L261.16,471.52 L262.96,469.32 L264.81,467.18 L266.73,465.09 L268.71,463.05 L270.75,461.07 L272.85,459.15 L275.01,457.27 L277.23,455.45 L279.51,453.69 L281.86,451.98 L284.30,450.36 L286.86,448.89 L289.55,447.55 L292.37,446.36 L295.31,445.31 L298.38,444.39 L301.58,443.62 L304.90,442.99 L308.34,442.50 L311.91,442.15 L315.61,441.94 L319.44,441.87 L323.74,441.95 L327.85,442.21 L331.75,442.65 L335.45,443.25 L338.95,444.03 L342.24,444.98 L345.34,446.10 L348.23,447.40 L350.93,448.87 L353.42,450.51 L355.71,452.32 L357.79,454.31 L359.70,456.45 L361.44,458.74 L363.01,461.18 L364.42,463.75 L365.66,466.47 L366.73,469.34 L367.64,472.35 L368.39,475.50 L368.97,478.80 L369.38,482.24 L369.63,485.82 L369.71,489.55 L369.71,509.25 L323.58,509.25 L314.52,509.39 L305.80,509.82 L297.44,510.53 L289.43,511.52 L281.78,512.80 L274.47,514.37 L267.52,516.22 L260.93,518.35 L254.68,520.77 L248.79,523.47 L243.25,526.45 L238.06,529.72 L233.26,533.28 L228.88,537.14 L224.91,541.30 L221.36,545.76 L218.23,550.52 L215.52,555.57 L213.22,560.93 L211.34,566.58 L209.88,572.53 L208.84,578.78 L208.21,585.33 L208.00,592.18 L208.15,598.13 L208.62,603.87 L209.39,609.41 L210.48,614.75 L211.87,619.89 L213.57,624.83 L215.58,629.57 L217.91,634.11 L220.54,638.44 L223.48,642.57 L226.73,646.50 L230.29,650.23 L234.14,653.71 L238.25,656.88 L242.63,659.75 L247.28,662.32 L252.19,664.59 L257.37,666.56 L262.82,668.22 L268.53,669.58 L274.51,670.64 L280.75,671.40 L287.26,671.85 L294.04,672.00 L299.07,671.91 L303.96,671.63 L308.72,671.17 L313.33,670.53 L317.81,669.71 L322.16,668.70 L326.37,667.50 L330.44,666.13 L334.37,664.57 L338.17,662.82 L341.83,660.89 L345.35,658.78 L348.71,656.49 L351.88,654.01 L354.85,651.35 L357.62,648.50 L360.20,645.47 L362.59,642.26 L364.78,638.87 L366.78,635.29 L368.58,631.52 L370.19,627.58 L371.60,623.45 L372.82,619.13 L375.93,619.13 L376.52,622.61 L377.24,625.98 L378.09,629.22 L379.07,632.35 L380.19,635.36 L381.44,638.24 L382.83,641.01 L384.34,643.67 L385.99,646.20 L387.78,648.61 L389.69,650.91 L391.74,653.08 L393.92,655.11 L396.23,656.96 L398.66,658.64 L401.22,660.14 L403.90,661.46 L406.71,662.61 L409.64,663.58 L412.71,664.37 L415.89,664.99 L419.21,665.43 L422.65,665.69 L426.21,665.78 L463.01,665.78 L463.01,612.91 Z M475.77,630.42 L546.23,713.58 L762.31,530.50 L546.23,347.42 L475.77,430.58 L593.69,530.50 L475.77,630.42 Z M667.77,630.42 L738.23,713.58 L954.31,530.50 L738.23,347.42 L667.77,430.58 L785.69,530.50 L667.77,630.42 Z\"/></svg>"},"/index.html":{"type":"text/html; charset=utf-8","b64":false,"data":"<!doctype html>\n<html lang=\"zh-Hant\">\n<head>\n<meta charset=\"utf-8\">\n<title>Arcrun RAG</title>\n<!--\n 根目錄直接導向搜尋 Portal。\n\n 為什麼不做「選擇介面」的導覽頁(2026-07-21 leo 實際撞到):\n 這份 UI 部署出去的網址是給**使用者**的入口(個人站 mira.uncle6.me,\n 以及自架用戶自己的網址),進站就是要能用——多一層選擇=多一個困惑點,\n (2026-08-08 更正:原註解寫「這個網域=rag-demo.arcrun.dev 是客戶測試入口」,\n 那是 uncle6 帳號那個已廢的 demo 站,leo 已定案不再拿它當範例;\n 註解留著會把下一個人導向錯的環境,故改寫。理由本身仍然成立。)\n 而且會讓客戶看到 Admin Console 這個維運介面(不該對客戶露出)。\n\n 維運者要進 console 直接打 /console/ 即可。\n-->\n<meta http-equiv=\"refresh\" content=\"0; url=/portal/\">\n<link rel=\"canonical\" href=\"/portal/\">\n<script>location.replace('/portal/');</script>\n<style>\n body{margin:0;min-height:100vh;display:grid;place-items:center;\n background:#faf8f5;color:#6b635a;\n font:15px/1.7 system-ui,-apple-system,\"Noto Sans TC\",sans-serif}\n @media(prefers-color-scheme:dark){body{background:#1a1816;color:#9a9186}}\n</style>\n</head>\n<body>\n <p>正在前往搜尋頁… <a href=\"/portal/\">沒有自動跳轉請點這裡</a></p>\n</body>\n</html>\n"},"/portal/app-mount.test.mjs":{"type":"application/javascript; charset=utf-8","b64":false,"data":"// App 掛載協定 v0.2 的結構自測(Arcrun#152#82leo 2026-08-24 拍板)\n// 跑法:node console-ui/public/portal/app-mount.test.mjs\n//\n// 這支守的是**協定的形狀**,不是長相——長相要用瀏覽器量(見 #152 的驗收留言)。\n// 之所以要有它:這一輪的病根是「出口與樣式被做成個案」——筆記 App 有返回鍵、總圖沒有;\n// CIS 表複製進 shadow 了、但 App 根本沒接上。個案會悄悄再長出來,所以把\n// 「不准再有個案」這件事寫成可執行的檢查。\nimport fs from 'node:fs';\n\nconst html = fs.readFileSync(new URL('./index.html', import.meta.url).pathname, 'utf8');\nlet pass = 0, fail = 0;\nconst chk = (label, cond, extra = '') => {\n if (cond) { console.log('PASS:', label); pass++; }\n else { console.log('FAIL:', label, extra); fail++; }\n};\n\n// ── ① 出口:每一個非首頁的 view 都必須有 .pagehead ────────────────────────────\n// ensureBackControls() 是往 `#v-<name> .pagehead` 裡塞返回鍵的。少了那一列 = 那個 view\n// 悄悄沒有出口,而且沒有人會發現(leo 就是這樣卡在總圖)。\nconst viewsLine = html.match(/var VIEWS = \\[(.*?)\\];/);\nif (!viewsLine) throw new Error('抽不到 VIEWS 清單');\nconst VIEWS = viewsLine[1].split(',').map((s) => s.trim().replace(/^'|'$/g, ''));\nconst HOME = (html.match(/var HOME = '([^']+)'/) || [])[1];\nchk('抽得到 VIEWS 與 HOME', VIEWS.length > 0 && !!HOME, `VIEWS=${VIEWS.length} HOME=${HOME}`);\n\nfor (const v of VIEWS) {\n if (v === HOME) continue;\n // 抓 `<div ... id=\"v-<name>\">` 之後、下一個 view 之前那一段,看有沒有 pagehead\n const at = html.indexOf(`id=\"v-${v}\"`);\n if (at < 0) { chk(`view ${v} 存在於 HTML`, false); continue; }\n const nextView = html.indexOf('id=\"v-', at + 10);\n const block = html.slice(at, nextView < 0 ? at + 4000 : nextView);\n chk(`非首頁 view「${v}」有 .pagehead(返回鍵才掛得上)`, /class=\"pagehead\"/.test(block));\n}\n\n// ── ② 不准再有「某一頁自己的返回鍵」 ─────────────────────────────────────────\nchk('沒有殘留的個案返回鍵(app-back-btn 已撤)', !html.includes('app-back-btn'));\nchk('返回鍵只由 ensureBackControls() 產生(全檔只有一處 createElement 出 data-portal-back',\n (html.match(/setAttribute\\('data-portal-back'/g) || []).length === 1);\nchk('返回鍵是頁首第一格(insertBefore firstChild', /insertBefore\\(b, head\\.firstChild\\)/.test(html));\nchk('返回鍵一律回 HOME', /data-portal-back\\]'\\)\\) nav\\(HOME\\)/.test(html));\n\n// ── ③ 樣式:兩種模式與層序 ──────────────────────────────────────────────────\nchk('層序=arcrun-base < app < arcrun(全局在最上面才蓋得過 App',\n html.includes('@layer arcrun-base, app, arcrun;'));\nchk('沒宣告=跟隨全局(預設 inherit,不是維持 App 原樣)',\n /var inherit = style !== 'own';/.test(html));\nchk('App 自己的 style 會被包進 app 層', /'@layer app\\{' \\+ st\\.textContent \\+ '\\}'/.test(html));\nchk('全局色票/CIS 都進 arcrun 層', (html.match(/'@layer arcrun\\{'/g) || []).length === 2);\nchk('樣式模式從 App 宣告來(不是 Portal 猜的)', /mountAppUi\\(host, app\\.ui_html, app\\.ui_style\\)/.test(html));\n\n// ── ④ 畫布是全局決定的(兩種模式都一樣)────────────────────────────────────\n// leo:「全局要給它多大的畫布也是全局決定的⋯⋯應該整個右側邊欄都是它的」\nchk('App 頁不吃 .page 的寬度上限與左右留白', /#v-app\\.on \\{[^}]*max-width: none;[^}]*padding: 0;/.test(html));\nchk('shadow host 由**外部文件**決定尺寸(App 在 shadow 裡改不動)',\n /#app-ui-mount \\{[^}]*width: 100%/.test(html));\n\n// ── ⑤ 隔離沒有被拆掉(這一輪的紅線)──────────────────────────────────────\nchk('App 仍然掛進 Shadow DOM', /host\\.attachShadow\\(\\{ mode: 'open' \\}\\)/.test(html));\n\nconsole.log(`\\n${fail === 0 ? '✅' : '❌'} pass=${pass} fail=${fail}`);\nprocess.exit(fail === 0 ? 0 : 1);\n"},"/portal/index.html":{"type":"text/html; charset=utf-8","b64":false,"data":"<!doctype html>\n<html lang=\"zh-Hant\">\n<head>\n<meta charset=\"utf-8\"/>\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>Arcrun Portal</title>\n<link rel=\"icon\" href=\"/favicon.svg\" type=\"image/svg+xml\">\n<link rel=\"alternate icon\" href=\"/favicon.ico\" sizes=\"16x16 32x32 48x48\">\n<link rel=\"apple-touch-icon\" href=\"/apple-touch-icon.png\">\n<script>\n // 主題預載(防閃色):預設淺色,選擇存 localStorage(與 console 同設計語言、不同 key\n document.documentElement.setAttribute('data-theme', (function () {\n try { return localStorage.getItem('arcrun_portal_theme') === 'dark' ? 'dark' : 'light'; } catch (e) { return 'light'; }\n })());\n</script>\n<!-- id=\"portal-cis\"Arcrun#152——App 掛進 Shadow DOM 之後,這份表會被複製一份進\n 每個 App 的 shadow rootleo 2026-08-24:「App 應該先採用整體的 styles」)。\n 要複製就得指得到它 ⇒ 這個 id 是契約的一部分,改名前先看 mountAppUi()。 -->\n<style id=\"portal-cis\">\n * { box-sizing: border-box; }\n /* ── 主題色板(2026-08-01 CIS 第三輪:leo 親驗「Portal 裡的色彩都沒改」——\n 舊「宣紙米白紙紋+墨字+琥珀金」整套換成 Arcrun CIS token。\n Ink #17181APaper #FDFCFBCanvas #F2F1EDMuted #9A978F\n Relation #B04A2F(唯一強調色,≤5% 螢幕)/Relation-dark #D9784F(暗色底用)。\n ── */\n :root {\n --paper-a: #FDFCFB; --paper-b: #F2F1ED;\n --ink: #17181A; --ink-rgb: 23,24,26;\n --amber: #B04A2F; --amber-rgb: 176,74,47;\n --ok: #1d7a48; --ok-rgb: 29,122,72; --ok-soft: #1d6b40;\n --err: #b03a26; --err-rgb: 176,58,38;\n --well: rgba(23,24,26,.06); --well2: rgba(23,24,26,.08);\n --bar-bg: #F2F1ED; --track: rgba(23,24,26,.12); --knob: #FDFCFB;\n }\n :root[data-theme=\"dark\"] {\n --paper-a: #1b1c1e; --paper-b: #1e1f21;\n --ink: #FDFCFB; --ink-rgb: 253,252,251;\n --amber: #D9784F; --amber-rgb: 217,120,79;\n --ok: #7fe0a8; --ok-rgb: 63,190,120; --ok-soft: #a8e8c4;\n --err: #e58575; --err-rgb: 217,95,76;\n --well: rgba(0,0,0,.25); --well2: rgba(0,0,0,.3);\n --bar-bg: #17181A; --track: rgba(255,255,255,.08); --knob: #FDFCFB;\n }\n html, body { margin: 0; background: repeating-linear-gradient(0deg,var(--paper-a) 0px,var(--paper-a) 3px,var(--paper-b) 3px,var(--paper-b) 4px); color: var(--ink);\n font-family: -apple-system, \"IBM Plex Sans\", \"PingFang TC\", \"Noto Sans TC\", \"Microsoft JhengHei\", system-ui, sans-serif; font-size: 16px; -webkit-font-smoothing: antialiased; }\n input, textarea, button { font-family: inherit; }\n ::placeholder { color: rgba(var(--ink-rgb),.35); }\n input:focus { outline: 2px solid rgba(var(--amber-rgb),.5); outline-offset: 1px; }\n a { color: var(--amber); }\n .serif { font-family: -apple-system, \"IBM Plex Sans\", \"PingFang TC\", \"Noto Sans TC\", \"Microsoft JhengHei\", system-ui, sans-serif; }\n .mono { font-family: ui-monospace, Menlo, monospace; }\n .muted { color: rgba(var(--ink-rgb),.55); }\n .dim { color: rgba(var(--ink-rgb),.4); }\n .err { color: var(--err); }\n .ok { color: var(--ok); }\n\n /* ── auth 全屏(.view.on 的 block 會蓋 flex → 補 .authwrap.view.onconsole 同修)── */\n .authwrap { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 24px; }\n .authbox { width: 100%; max-width: 400px; display: flex; flex-direction: column; gap: 24px; text-align: center; }\n /* 08-01 緊急修正:登入頁品牌 lockup 改用官方 PNG(自產 SVG outline 字腔缺失作廢,\n 見 arcrun-cis/README.md 說明)。mark 不上色(NEVER 用 --amberRelation\n 當 logo 色——CISRelation 是「唯一強調色」不是品牌色,logo 上色是一句謊話),\n 靠兩張圖(-ink-paper-on-ink)依 data-theme 切換,不用 filter 避免色偏。\n 08-01 二次修正:官方原始 PNG1840x560)畫布只有 32% 高度是實際字形(上下大留白),\n height:44px 時實際字高僅約 14px,看起來過小。改用裁淨版(493x88,長寬比 5.604:1,\n 四邊已裁到字腔邊緣無留白),此時 height:44px=實際字高 44px。 */\n .brand { display: flex; justify-content: center; }\n .brand img { height: clamp(32px, 8.5vw, 48px); width: auto; display: block; max-width: 100%; }\n .brand .wm-paper { display: none; }\n :root[data-theme=\"dark\"] .brand .wm-ink { display: none; }\n :root[data-theme=\"dark\"] .brand .wm-paper { display: block; }\n .brand-sub { margin-top: 10px; font-size: 15px; color: rgba(var(--ink-rgb),.55); letter-spacing: .1em; }\n\n /* ── 版面骨架 ── */\n #shell { display: none; min-height: 100vh; }\n #shell.on { display: flex; }\n #sidenav { display: none; }\n main { flex: 1; min-width: 0; padding-bottom: 96px; }\n .page { max-width: 980px; margin: 0 auto; padding: 0 20px 40px; }\n .page.narrow { max-width: 760px; }\n /* Arcrun#152leo 2026-08-24 實測第三件):「App 頁的 responsiveness 有問題」。\n 病灶在這一列:flex 不換行 `.t` 是 `white-space:nowrap`min-content =整串長度、\n 且 flex item 預設 `min-width:auto` ⇒ 縮不下去)⇒ 窄寬度時 `.t` 吃光整條線,\n `.m` 被壓到自己的 min-content(中文=一個字寬)⇒ 變成一行一個字的窄柱並溢出畫面右緣。\n 啟動器頁最慘,因為它的 `.t` 是「晚安,<使用者名稱>」——長度由使用者名字決定。\n 實測(375px 視窗、名字 youlin.hsieh.dev):頁首高 219px、`.m` 寬 38px 高 171px、\n 右緣 394px > 視窗寬。\n 修法兩件,都在這一列,不動任何 JS:\n ① `flex-wrap: wrap` ⇒ 擠不下時 `.m` 整段掉到第二行(拿到整條寬度),不再被壓成窄柱;\n ② `.t` 在窄螢幕解除 nowrap `min-width: 0` ⇒ 名字再長也是換行,不會頂破畫面。\n 桌面寬度兩件都不觸發(兩段本來就排得下),所以維持原本的左右對齊一行。 */\n .pagehead { padding: 22px 2px 14px; border-bottom: 2px solid rgba(var(--amber-rgb),.4); display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: 2px 10px; }\n .pagehead .t { font-family: -apple-system, \"IBM Plex Sans\", \"PingFang TC\", \"Noto Sans TC\", \"Microsoft JhengHei\", system-ui, sans-serif; font-size: 23px; letter-spacing: .2em; white-space: nowrap; min-width: 0; }\n .pagehead .m { font-size: 13.5px; color: rgba(var(--ink-rgb),.45); min-width: 0; }\n @media (max-width: 700px) { .pagehead .t { white-space: normal; overflow-wrap: anywhere; } }\n /* Arcrun#152leo 2026-08-24:「所有的 App 都要顯示,不然他要怎麼回 home?」):\n 出口是**協定層**的東西——凡不是首頁的 view,頁首第一格一律是同一顆「← 返回」,\n 由 ensureBackControls() 統一塞(見該函式)。這裡只負責它的長相與位置:\n `.t { margin-right:auto }` 讓標題緊跟在返回鍵右邊、說明 `.m` 仍然靠右,\n 所以**首頁(沒有返回鍵)的排版跟以前一模一樣**。 */\n .pagehead .t { margin-right: auto; }\n .backbtn { flex: none; padding: 7px 12px; font-size: 13.5px; align-self: center; }\n /* Arcrun#152leo 2026-08-24 拍板):「全局要給它多大的畫布也是全局決定的⋯⋯\n 它呈現白底的一個黑框表示那是系統給它的範圍?**應該整個右側邊欄都是它的**」。\n ⇒ App 的畫布=整個右側內容區:`.page` 的 980px 上限與左右留白在這一頁全部拿掉,\n 只有頁首那一列自己補回留白(頁首是 Portal 的東西,不是 App 的畫布)。\n 🔴 兩種樣式模式(inherit/own)都吃這一段——畫布不是 App 能決定的事。 */\n #v-app.on { display: flex; flex-direction: column; max-width: none; padding: 0; min-height: calc(100vh - 96px); }\n /* 22px 不是 20px`.page` 的 20px `.pagehead` 自己的 2px。返回鍵要跟其他頁**同一個\n x 座標**(實測過的:其他頁 22、這頁若寫 20 就會差 2px)——「位置固定」是量出來的。 */\n #v-app > .pagehead { padding-left: 22px; padding-right: 22px; }\n #app-body { flex: 1; display: flex; flex-direction: column; min-width: 0; }\n /* 沒有自帶畫面的 App 走系統預設畫面(工作流清單),那是 Portal 自己的內容 ⇒ 補回\n `.page` 原本的左右留白。只有 App 的畫布(`#app-ui-mount`)才是滿版的。 */\n #app-body > :not(#app-ui-mount) { margin-left: 20px; margin-right: 20px; }\n /* shadow host:寬度吃滿、高度撐滿剩下的地方。App 自己在 shadow 裡寫什麼都改不了這一段\n (外部文件的規則對 host 元素勝過 shadow 內的 `:host` 規則)⇒ 畫布真的由全局說了算。 */\n #app-ui-mount { flex: 1; display: block; width: 100%; min-width: 0; }\n @media (min-width: 1024px) { #v-app.on { min-height: calc(100vh - 20px); } }\n #tabbar { position: fixed; left: 0; right: 0; bottom: 0; background: var(--bar-bg); border-top: 2px solid rgba(var(--amber-rgb),.4); display: none; z-index: 50; padding-bottom: env(safe-area-inset-bottom); }\n #tabbar.on { display: flex; }\n #tabbar .tab { flex: 1; text-align: center; padding: 15px 0 13px; font-size: 14.5px; cursor: pointer; min-height: 44px; color: rgba(var(--ink-rgb),.5); border-top: 2px solid transparent; margin-top: -2px; }\n #tabbar .tab.on { color: var(--amber); font-weight: 600; border-top-color: var(--amber); }\n #tabbar .tab.hide { display: none; }\n @media (min-width: 1024px) {\n #tabbar.on { display: none; }\n main { padding-bottom: 20px; }\n #sidenav { display: flex; width: 216px; flex: none; position: sticky; top: 0; height: 100vh; border-right: 2px solid rgba(var(--amber-rgb),.35); padding: 28px 0; flex-direction: column; gap: 4px; }\n #sidenav .logo { display: flex; color: var(--ink); padding: 0 32px 20px; }\n #sidenav .logo img { height: clamp(22px, 5vw, 28px); width: auto; display: block; max-width: 100%; }\n #sidenav .logo .wm-paper { display: none; }\n :root[data-theme=\"dark\"] #sidenav .logo .wm-ink { display: none; }\n :root[data-theme=\"dark\"] #sidenav .logo .wm-paper { display: block; }\n #sidenav .nav { padding: 13px 24px; font-size: 16px; cursor: pointer; letter-spacing: .08em; color: rgba(var(--ink-rgb),.6); border-right: 2px solid transparent; }\n #sidenav .nav.on { color: var(--amber); background: rgba(var(--amber-rgb),.08); border-right-color: var(--amber); font-family: -apple-system, \"IBM Plex Sans\", \"PingFang TC\", \"Noto Sans TC\", \"Microsoft JhengHei\", system-ui, sans-serif; font-weight: 600; }\n #sidenav .nav.hide { display: none; }\n #sidenav .foot { margin-top: auto; padding: 0 24px; font-size: 12.5px; color: rgba(var(--ink-rgb),.35); line-height: 1.7; }\n }\n .view { display: none; }\n .view.on { display: block; }\n .authwrap.view.on { display: flex; }\n\n /* ── 元件 ── */\n .btn { padding: 13px; font-size: 16px; font-weight: 600; border-radius: 10px; border: none; background: var(--amber); color: #FDFCFB; cursor: pointer; }\n .btn:disabled { opacity: .45; cursor: default; }\n .btn3 { padding: 11px 16px; font-size: 15px; border-radius: 10px; border: 1px solid rgba(var(--ink-rgb),.25); background: none; color: rgba(var(--ink-rgb),.7); cursor: pointer; }\n .txt { width: 100%; padding: 13px 15px; font-size: 16px; border-radius: 10px; border: 1px solid rgba(var(--ink-rgb),.2); background: rgba(var(--ink-rgb),.05); color: var(--ink); }\n .panel { padding: 18px; border-radius: 13px; background: rgba(var(--ink-rgb),.04); border: 1px solid rgba(var(--ink-rgb),.12); }\n .tag { display: inline-block; padding: 3px 9px; border-radius: 5px; background: rgba(var(--amber-rgb),.12); color: var(--amber); font-size: 12.5px; }\n .tag.green { background: rgba(var(--ok-rgb),.12); color: var(--ok); }\n .tag.dim { background: rgba(var(--ink-rgb),.08); color: rgba(var(--ink-rgb),.55); }\n .honest { padding: 22px; border-radius: 13px; border: 1px dashed rgba(var(--amber-rgb),.4); background: rgba(var(--amber-rgb),.06); text-align: center; }\n .honest .h { font-family: -apple-system, \"IBM Plex Sans\", \"PingFang TC\", \"Noto Sans TC\", \"Microsoft JhengHei\", system-ui, sans-serif; font-size: 19px; color: var(--amber); margin-bottom: 8px; }\n .honest .b { font-size: 15px; color: rgba(var(--ink-rgb),.6); line-height: 1.7; }\n #toast { position: fixed; left: 50%; bottom: 110px; transform: translateX(-50%); z-index: 99; padding: 13px 22px; border-radius: 11px; background: var(--amber); color: #FDFCFB; font-size: 15.5px; font-weight: 600; box-shadow: 0 6px 24px rgba(0,0,0,.5); white-space: nowrap; display: none; }\n\n /* ── AI 檢索過程(Arcrun#44leo「要看到從 graph 找到幾個子庫、讀到的 index 敘事、\n 引用的原文位置——不是簡單向量搜尋的結果」)。一眼掃完優先:路徑徽章+非向量徽章\n 常駐可見,細節(命中子庫/索引敘事/原文片段)用原生 <details> 收合,想細看再展開。 */\n .tracehead { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 14px; }\n .trace { margin-top: 10px; border-radius: 13px; border: 1px solid rgba(var(--ink-rgb),.12); background: rgba(var(--ink-rgb),.03); }\n .trace > summary { cursor: pointer; padding: 10px 14px; font-size: 13.5px; color: rgba(var(--ink-rgb),.6); user-select: none; }\n .trace-body { padding: 2px 14px 14px; border-top: 1px solid rgba(var(--ink-rgb),.08); margin-top: 2px; }\n /* 樹狀圖(markmap)。2026-08-18 leo:「希望以樹狀圖來展示⋯⋯就像現有的 graph search 一樣 render」\n ——平鋪的 ①②③ 區塊資訊都在,但「搜尋詞→子庫→索引敘事→原文片段」的層級要用戶自己腦補。 */\n .tracetree { position: relative; height: 430px; margin-top: 10px; border-radius: 12px; background: var(--well); border: 1px solid rgba(var(--ink-rgb),.1); overflow: hidden; }\n @media (max-width: 700px) { .tracetree { height: 340px; } }\n .tracetree > svg { display: block; width: 100%; height: 100%;\n --markmap-font: 400 13px/1.45 -apple-system, \"IBM Plex Sans\", \"PingFang TC\", \"Noto Sans TC\", \"Microsoft JhengHei\", system-ui, sans-serif;\n --markmap-text-color: var(--ink); --markmap-circle-open-bg: var(--well); }\n .tracetree .tt-sub { color: rgba(var(--ink-rgb),.55); font-size: 11.5px; }\n .tracetree .tt-path { font-family: ui-monospace, Menlo, monospace; color: rgba(var(--amber-rgb),.85); font-size: 11px; }\n .tracetree .tt-dim { color: rgba(var(--ink-rgb),.45); }\n /* 異質節點的樣式語彙(D97:三個入口共用同一份 render,節點種類靠這幾個 class 分)。\n 同步庫總覽的四層長這樣:總庫 → 機器 → 資料夾 → 子資料夾/檔案,\n 機器與資料夾必須一眼分得開,所以給不同顏色與前綴圖示。 */\n .tracetree .tt-machine { color: var(--amber); font-weight: 600; }\n .tracetree .tt-machine::before { content: \"🖥 \"; }\n .tracetree .tt-folder::before { content: \"📁 \"; }\n .tracetree .tt-file::before { content: \"📄 \"; }\n /* 拿不到值時的節點:明說「未知」,不要拿別的東西頂替(機器那層現在就是這個狀態) */\n .tracetree .tt-unknown { color: rgba(var(--err-rgb),.75); border-bottom: 1px dashed rgba(var(--err-rgb),.5); }\n .tracetree .tt-count { color: rgba(var(--ink-rgb),.5); font-size: 11.5px; }\n .tracetree .tt-hint { position: absolute; right: 10px; bottom: 8px; font-size: 11.5px; color: rgba(var(--ink-rgb),.35); pointer-events: none; }\n /* markmap 載不進來時的誠實退路:同一份樹資料改用巢狀清單畫(不另外做第二套資料組裝) */\n .tracelist, .tracelist ul { list-style: none; margin: 0; padding-left: 15px; }\n .tracelist { padding-left: 2px; font-size: 13.5px; }\n .tracelist li { position: relative; padding: 4px 0 4px 13px; line-height: 1.55; word-break: break-word; }\n .tracelist li::before { content: \"└\"; position: absolute; left: 0; color: rgba(var(--ink-rgb),.3); }\n .tracelist ul { border-left: 1px solid rgba(var(--ink-rgb),.12); }\n /* 出處麵包屑(leo 2026-08-18:「應該是讓他可以去本機資料夾找到原文⋯⋯帶上原機器的編號、\n 資料夾名稱、檔名的麵包屑⋯⋯不用再開搜尋框了」)*/\n .crumbrow { padding: 11px 13px; border-radius: 11px; background: rgba(var(--ink-rgb),.045); border: 1px solid rgba(var(--ink-rgb),.1); }\n .crumbs { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: 14.5px; }\n .crumbs .sep { color: rgba(var(--ink-rgb),.3); }\n .crumbs .crumb { color: rgba(var(--ink-rgb),.7); }\n .crumbs .crumb.file { font-weight: 600; color: var(--ink); word-break: break-all; }\n .crumbs .crumb.unknown { color: rgba(var(--err-rgb),.75); border-bottom: 1px dashed rgba(var(--err-rgb),.5); cursor: help; }\n .crumbfoot { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 7px; }\n .crumbfoot .p { font-family: ui-monospace, Menlo, monospace; font-size: 12.5px; color: rgba(var(--ink-rgb),.55); word-break: break-all; }\n .btn3 { flex: none; padding: 5px 11px; font-size: 12.5px; border-radius: 8px; cursor: pointer; border: 1px solid rgba(var(--amber-rgb),.45); background: rgba(var(--amber-rgb),.08); color: var(--amber); }\n\n /* ── 搜尋 ── */\n .searchrow { display: flex; gap: 10px; align-items: stretch; }\n .searchrow input { flex: 1; min-width: 0; padding: 16px 18px; font-size: 18px; border-radius: 13px; border: 1.5px solid rgba(var(--amber-rgb),.35); background: rgba(var(--ink-rgb),.05); color: var(--ink); }\n .modebar { display: flex; gap: 8px; margin-top: 12px; }\n .modebtn { flex: none; padding: 9px 18px; font-size: 14.5px; border-radius: 999px; cursor: pointer; border: 1px solid rgba(var(--ink-rgb),.18); background: none; color: rgba(var(--ink-rgb),.6); }\n .modebtn.on { border-color: rgba(var(--amber-rgb),.6); background: rgba(var(--amber-rgb),.14); color: var(--amber); font-weight: 600; }\n .modebtn.hide { display: none; }\n /* 🔴 2026-08-10 實測撞到:`.hide` 一直**只有上面那三條有 scope 的規則**#tabbar .tab / #sidenav .nav / .modebtn),\n 所以任何其他元素掛上 class=\"hide\" 都**完全沒有被藏起來**——看起來有藏、其實沒藏。\n D62 的「忘記密碼」欄位與「現有密碼」欄位就是這樣在瀏覽器上原形畢露的。\n 補一條通用規則;帶 !important 是因為要蓋過 inline 的 display#forgot-box 就有)。\n 既有那三種用法的意圖與本規則一致(都是「藏起來」),加這條不改變它們的行為。 */\n .hide { display: none !important; }\n .kgrid { display: grid; grid-template-columns: 1fr; gap: 12px; padding-bottom: 8px; }\n @media (min-width: 700px) { .kgrid { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); } }\n .kcard { padding: 18px; border-radius: 13px; background: rgba(var(--ink-rgb),.045); border: 1px solid rgba(var(--ink-rgb),.1); cursor: pointer; display: flex; flex-direction: column; gap: 9px; }\n .kcard:hover { border-color: rgba(var(--amber-rgb),.45); background: rgba(var(--amber-rgb),.06); }\n .kcard .kt { font-family: -apple-system, \"IBM Plex Sans\", \"PingFang TC\", \"Noto Sans TC\", \"Microsoft JhengHei\", system-ui, sans-serif; font-size: 18.5px; font-weight: 600; line-height: 1.45; word-break: break-word; }\n .kcard .ks { font-size: 15px; color: rgba(var(--ink-rgb),.65); line-height: 1.65; word-break: break-word; }\n .kcard .km { display: flex; gap: 10px; align-items: center; margin-top: auto; font-size: 13px; flex-wrap: wrap; }\n\n /* ── 卡片詳頁 ── */\n .cardtitle { font-family: -apple-system, \"IBM Plex Sans\", \"PingFang TC\", \"Noto Sans TC\", \"Microsoft JhengHei\", system-ui, sans-serif; font-size: 28px; font-weight: 600; line-height: 1.4; word-break: break-word; }\n .md { margin-top: 18px; }\n .md p { font-size: 16.5px; line-height: 1.85; color: rgba(var(--ink-rgb),.82); margin: 8px 0; word-break: break-word; }\n .md h1, .md h2, .md h3, .md h4 { font-family: -apple-system, \"IBM Plex Sans\", \"PingFang TC\", \"Noto Sans TC\", \"Microsoft JhengHei\", system-ui, sans-serif; font-weight: 600; color: var(--amber); margin: 18px 0 6px; line-height: 1.4; }\n .md h1 { font-size: 22px; } .md h2 { font-size: 20px; } .md h3 { font-size: 18px; } .md h4 { font-size: 17px; }\n .md ul, .md ol { margin: 8px 0; padding-left: 24px; }\n .md li { font-size: 16.5px; line-height: 1.8; color: rgba(var(--ink-rgb),.82); margin: 4px 0; word-break: break-word; }\n .md blockquote { margin: 10px 0; padding: 12px 18px; border-left: 3px solid rgba(var(--amber-rgb),.5); font-family: -apple-system, \"IBM Plex Sans\", \"PingFang TC\", \"Noto Sans TC\", \"Microsoft JhengHei\", system-ui, sans-serif; font-size: 17px; line-height: 1.8; color: rgba(var(--ink-rgb),.7); }\n .md code { font-family: ui-monospace, Menlo, monospace; font-size: 14.5px; background: var(--well2); border-radius: 4px; padding: 1px 6px; word-break: break-all; }\n .md pre { background: var(--well2); border: 1px solid rgba(var(--ink-rgb),.1); border-radius: 10px; padding: 14px; overflow-x: auto; }\n .md pre code { background: none; padding: 0; }\n .srcline { margin-top: 24px; display: flex; align-items: center; gap: 12px; padding: 14px 16px; border-radius: 11px; background: rgba(var(--ink-rgb),.045); border: 1px solid rgba(var(--ink-rgb),.12); }\n\n /* ── graph 模式(console 關聯視圖同款)── */\n .graphbox { position: relative; height: 340px; border-radius: 14px; background: var(--well); border: 1px solid rgba(var(--ink-rgb),.1); overflow: hidden; }\n .gnode { position: absolute; transform: translate(-50%,-50%); max-width: 96px; padding: 8px 11px; border-radius: 999px; text-align: center; font-size: 12.5px; line-height: 1.3; cursor: pointer; word-break: break-word; background: rgba(var(--ok-rgb),.1); border: 1px solid rgba(var(--ok-rgb),.35); color: var(--ok-soft); }\n .gcenter { position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%); width: 104px; height: 104px; border-radius: 50%; background: radial-gradient(circle at 36% 30%,rgba(217,120,79,.95),rgba(176,74,47,.9) 55%,rgba(120,45,25,.95)); display: grid; place-items: center; text-align: center; padding: 8px; box-shadow: 0 0 30px rgba(var(--amber-rgb),.3); }\n .gcenter span { font-family: -apple-system,\"PingFang TC\",\"Microsoft JhengHei\",system-ui,sans-serif; font-size: 13.5px; font-weight: 600; line-height: 1.35; color: #FDFCFB; word-break: break-word; }\n .nbrow { display: flex; align-items: center; gap: 11px; padding: 12px 14px; border-radius: 10px; cursor: pointer; background: rgba(var(--ink-rgb),.045); border: 1px solid rgba(var(--ink-rgb),.1); font-size: 15.5px; }\n /* 總圖(Arcrun#39 GUI 切片):沿用紙感語言——green 章印節點、amber 高度數節點 */\n .mapbox { position: relative; border-radius: 14px; background: var(--well); border: 1px solid rgba(var(--ink-rgb),.1); overflow: hidden; }\n .mapbox svg { display: block; width: 100%; height: auto; }\n .mapnode { cursor: pointer; }\n .mapnode circle { fill: rgba(var(--ok-rgb),.12); stroke: rgba(var(--ok-rgb),.45); stroke-width: 1.4; transition: stroke-width .15s; }\n .mapnode.hub circle { fill: rgba(var(--amber-rgb),.2); stroke: rgba(var(--amber-rgb),.65); }\n .mapnode:hover circle { stroke-width: 3; }\n .mapnode text { font-size: 12.5px; fill: var(--ink); pointer-events: none; }\n .mapedge { stroke: rgba(var(--ink-rgb),.18); stroke-width: 1; stroke-dasharray: 4 4; }\n\n /* ── 管理頁(P4)── */\n .sechead { font-family: -apple-system, \"IBM Plex Sans\", \"PingFang TC\", \"Noto Sans TC\", \"Microsoft JhengHei\", system-ui, sans-serif; font-size: 19px; letter-spacing: .14em; color: var(--amber); margin: 26px 0 12px; padding-bottom: 8px; border-bottom: 1px solid rgba(var(--amber-rgb),.3); }\n .formrow { display: flex; gap: 10px; flex-wrap: wrap; }\n .formrow .txt { flex: 1; min-width: 180px; }\n .formrow select { padding: 12px 14px; font-size: 15.5px; border-radius: 10px; border: 1px solid rgba(var(--ink-rgb),.2); background: rgba(var(--ink-rgb),.05); color: var(--ink); }\n .btnrow { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }\n .btn2 { padding: 9px 14px; font-size: 14px; border-radius: 9px; border: 1px solid rgba(var(--amber-rgb),.45); background: rgba(var(--amber-rgb),.08); color: var(--amber); cursor: pointer; }\n .btn2.warn { border-color: rgba(var(--err-rgb),.45); background: rgba(var(--err-rgb),.06); color: var(--err); }\n .btn2:disabled { opacity: .45; cursor: default; }\n .libgrid { display: flex; gap: 8px 14px; flex-wrap: wrap; margin-top: 10px; }\n .libgrid label { display: flex; align-items: center; gap: 7px; font-size: 14.5px; cursor: pointer; padding: 6px 10px; border-radius: 8px; background: rgba(var(--ink-rgb),.05); border: 1px solid rgba(var(--ink-rgb),.12); }\n .libgrid input[type=checkbox] { accent-color: var(--amber); width: 16px; height: 16px; }\n .otpbox { margin-top: 14px; padding: 18px; border-radius: 13px; border: 2px solid rgba(var(--amber-rgb),.55); background: rgba(var(--amber-rgb),.08); }\n .otpbox .pw { font-family: ui-monospace, Menlo, monospace; font-size: 22px; letter-spacing: .12em; color: var(--amber); word-break: break-all; user-select: all; margin: 10px 0; }\n\n /* ── 清單 / 設定 ── */\n .listcol { display: flex; flex-direction: column; gap: 10px; padding: 16px 0 8px; }\n .card-item { border-radius: 13px; background: rgba(var(--ink-rgb),.045); border: 1px solid rgba(var(--ink-rgb),.1); padding: 16px 18px; }\n .setcol { display: flex; flex-direction: column; gap: 14px; padding: 20px 0 40px; }\n .switch { flex: none; margin-left: auto; width: 56px; height: 32px; border-radius: 999px; padding: 3px; background: rgba(var(--ink-rgb),.15); transition: background .25s; }\n .switch.on { background: rgba(var(--ok-rgb),.5); }\n .switch i { display: block; width: 26px; height: 26px; border-radius: 50%; background: var(--knob); box-shadow: 0 1px 3px rgba(0,0,0,.25); transition: transform .25s; }\n .switch.on i { transform: translateX(24px); }\n .kvline { display: flex; justify-content: space-between; gap: 12px; font-size: 15px; margin: 5px 0; }\n\n /* ── App 啟動器外殼(Arcrun#152):#sidenav#tabbar 從「單層清單」升級成\n App 界面/App 市集/AR 設定/App 開發 四段 OS 級導覽。既有頁面(search/map/\n upload/workflows/admin/settings)原地不動——只在頁內加一列 subnav 或收進對應\n 頁簽的清單;沿用既有 #sidenav/#tabbar 開關與既有 700px/1024px 斷點,不另立系統。\n\n Icon 一律**描邊式 inline SVG**`stroke=\"currentColor\"`),不用 emoji。三個理由:\n ① emoji 是各作業系統自帶的彩色點陣字形,Windows/macOSAndroid 各長一套,\n 同一份畫面在不同機器上不一致,設計稿無法被保證;\n ② emoji 吃不到 CIS 的 --ink--amber ⇒ 切深色模式時它不會跟著變色;\n ③ 本 repo 的 CIS 是紙感墨字(見 system-dev/wiki/cis-web-style.md)。\n 尺寸/筆畫全部照 leo 核准的設計稿(Main.dc.htmlLauncher-Desktop.dc.html):\n 導覽 19/21px・stroke-width 1.9,磚塊 28px・stroke-width 1.8。\n ⚠️ 不引入任何 icon 函式庫/CDN——Portal 要內嵌成單檔 worker 出貨。 */\n .nav.osnav, .tab.ostab { display: flex; align-items: center; gap: 12px; }\n .tab.ostab { flex-direction: column; gap: 3px; }\n .osnav .os-ic, .ostab .os-ic { flex: none; display: flex; line-height: 0; }\n /* 顏色不寫死:SVG 用 currentColor,色彩由 #sidenav .nav#tabbar .tab(含 .on 的\n var(--amber))決定 ⇒ 深淺色模式與選中狀態都自動跟著 CIS token 走。 */\n .osnav .os-ic svg { display: block; width: 19px; height: 19px; stroke-width: 1.9; }\n .ostab .os-ic svg { display: block; width: 21px; height: 21px; stroke-width: 1.9; }\n .subnav { display: flex; gap: 8px; flex-wrap: wrap; margin: 16px 0 4px; }\n .subchip { padding: 8px 16px; border-radius: 999px; font-size: 14px; cursor: pointer; border: 1px solid rgba(var(--ink-rgb),.18); color: rgba(var(--ink-rgb),.6); }\n .subchip.on { border-color: rgba(var(--amber-rgb),.6); background: rgba(var(--amber-rgb),.14); color: var(--amber); font-weight: 600; }\n .launchgrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px 12px; padding: 22px 2px 8px; }\n @media (min-width: 700px) { .launchgrid { grid-template-columns: repeat(5, 1fr); gap: 30px 18px; } }\n .apptile { display: flex; flex-direction: column; align-items: center; gap: 8px; cursor: pointer; }\n .apptile .ic { width: 64px; height: 64px; border-radius: 17px; display: flex; align-items: center; justify-content: center; background: var(--well); border: 1px solid rgba(var(--ink-rgb),.1); color: var(--ink); }\n .apptile .ic svg { display: block; width: 28px; height: 28px; stroke-width: 1.8; }\n /* 已安裝 App 的磚塊:底是琥珀漸層,故 icon 用紙色。#FDFCFB 是本檔既有的\n 「紙色壓在琥珀上」慣例(同 .btn),兩個主題下底色都是琥珀,故不需換色。 */\n .apptile.accent .ic { background: linear-gradient(155deg, var(--amber), #7A331F); border: none; box-shadow: 0 6px 16px rgba(var(--amber-rgb),.28); color: #FDFCFB; }\n .apptile.add .ic { background: transparent; border: 1.5px dashed rgba(var(--ink-rgb),.22); color: rgba(var(--ink-rgb),.55); }\n .apptile.add .ic svg { width: 24px; height: 24px; }\n .apptile .lbl { font-size: 12.5px; text-align: center; line-height: 1.3; word-break: break-word; }\n .apptile-ic-sm { flex: none; width: 40px; height: 40px; border-radius: 11px; display: flex; align-items: center; justify-content: center; background: var(--well); color: var(--ink); }\n .apptile-ic-sm svg { display: block; width: 20px; height: 20px; stroke-width: 1.8; }\n .promorow { display: flex; align-items: center; gap: 12px; padding: 14px 16px; border-radius: 13px; border: 1.5px dashed rgba(var(--amber-rgb),.4); background: rgba(var(--amber-rgb),.06); cursor: pointer; }\n .promorow .ic { flex: none; width: 38px; height: 38px; border-radius: 10px; background: var(--amber); color: #FDFCFB; display: flex; align-items: center; justify-content: center; font-size: 17px; }\n</style>\n<script src=\"/config.js\"></script>\n<!-- markmap-view 0.18.12MIT)=檢索過程樹狀圖的佈局與渲染引擎。leo 2026-08-18\n 「類似 https://markmap.js.org/ 可以把文字轉圖,**不要自造輪胎**。」\n · 為什麼 vendored 不走 CDN:這頁由 worker 內嵌供檔、今天零外部依賴,\n 企業內網/離線實例也要打得開;走 CDN 等於把「能不能看檢索過程」綁在第三方網域活著。\n · 為什麼只有 markmap-view,沒有 markmap-lib:後者是 markdown 解析器(依賴鏈 741KB\n 含 katexhighlight.jsprismjs),而我們的檢索過程本來就是結構化資料,\n 不需要先轉成 markdown 再 parse 回樹。markmap-view 直接吃節點樹。\n · 更新方式(產地在這個 repo,不在別處 build):\n node scripts/vendor-markmap.mjs → 重打 console-ui/public/portal/vendor/markmap-view.min.js -->\n<script src=\"/portal/vendor/markmap-view.min.js\"></script>\n<script>\n// apiBase 由安裝器注入的 config.js 提供(實查用戶實例:\n// window.ARCRUN_CONFIG = { apiBase: \"https://arcrun-cypher-executor.<subdomain>.workers.dev\" })。\n// 🔴 2026-08-01 拔掉舊的 `|| \"https://cypher.arcrun.dev\"` fallback\n// 那是「靜默打到別人家」的未爆彈——config.js 一旦沒載入/被擋/改名,\n// 前端會安靜地把請求(含**用戶金鑰**)送去中央實例,而不是明顯壞掉。\n// **寧可明顯失敗,不要靜默錯置。**\nwindow.ARCRUN_API_BASE = (window.ARCRUN_CONFIG && window.ARCRUN_CONFIG.apiBase) || \"\";\nif (!window.ARCRUN_API_BASE) {\n document.addEventListener('DOMContentLoaded', function () {\n var b = document.createElement('div');\n b.style.cssText = 'position:fixed;top:0;left:0;right:0;z-index:99999;background:#b4462f;color:#fff;padding:12px 16px;font:14px/1.5 system-ui;text-align:center';\n b.textContent = '設定檔沒載入(config.js),這個頁面連不到你的服務。請重新整理;若持續發生,請重跑一次安裝。';\n document.body.appendChild(b);\n });\n}\n</script>\n</head>\n<body>\n\n<!-- ══ Icon spriteArcrun#152)══════════════════════════════════════════════\n 描邊式 inline SVG,一份 <symbol> 定義、靠 <use> 在各處引用 ⇒ 桌面側欄與手機\n tabbar 引的是同一份,兩處不可能長歪(emoji 時代是兩份字面 emoji 各自維護)。\n\n ⚠️ 每個 symbol 都**刻意不寫 stroke-width**——由 CSS 設在外層 <svg> 上再繼承進來,\n 這樣同一顆 icon 能在導覽(1.9)與磚塊(1.8)用不同筆畫,照設計稿。\n stroke=\"currentColor\" ⇒ 顏色一律由 CSS 的 color 決定(CIS token),不寫死。\n\n ⚠️ 不是函式庫、沒有 CDN、沒有外部檔案:Portal 要內嵌成單檔 worker 出貨。 -->\n<svg width=\"0\" height=\"0\" aria-hidden=\"true\" focusable=\"false\" style=\"position:absolute;overflow:hidden\">\n <defs>\n <!-- 四頁簽(Main.dc.htmlLauncher-Desktop.dc.html 原樣) -->\n <symbol id=\"i-apps\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <rect x=\"3.5\" y=\"3.5\" width=\"7\" height=\"7\" rx=\"1.6\"/><rect x=\"13.5\" y=\"3.5\" width=\"7\" height=\"7\" rx=\"1.6\"/>\n <rect x=\"3.5\" y=\"13.5\" width=\"7\" height=\"7\" rx=\"1.6\"/><rect x=\"13.5\" y=\"13.5\" width=\"7\" height=\"7\" rx=\"1.6\"/>\n </symbol>\n <symbol id=\"i-market\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M4 8 5.5 4h13L20 8\"/><path d=\"M4 8v11a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1V8\"/><path d=\"M9 12a3 3 0 0 0 6 0\"/>\n </symbol>\n <!-- 設定=滑桿。用 Launcher-Desktop 那版(Main 那版尾巴多一段 M22 18h0 零長度線段,\n 圓端點會多畫出一個小圓點)⇒ 統一取沒有雜點的,桌面與手機才真的一致。 -->\n <symbol id=\"i-settings\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M4 6h10M18 6h2M4 12h2M10 12h10M4 18h14\"/>\n <circle cx=\"16\" cy=\"6\" r=\"2\"/><circle cx=\"7\" cy=\"12\" r=\"2\"/><circle cx=\"18\" cy=\"18\" r=\"2\"/>\n </symbol>\n <symbol id=\"i-dev\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"m8 8-4 4 4 4M16 8l4 4-4 4M13.5 5l-3 14\"/>\n </symbol>\n\n <!-- 內建磚塊(設計稿原樣) -->\n <symbol id=\"i-search\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <circle cx=\"10.5\" cy=\"10.5\" r=\"6.5\"/><path d=\"m20 20-4.8-4.8\"/>\n </symbol>\n <symbol id=\"i-graph\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <circle cx=\"12\" cy=\"5\" r=\"2.2\"/><circle cx=\"5\" cy=\"17\" r=\"2.2\"/><circle cx=\"19\" cy=\"17\" r=\"2.2\"/>\n <path d=\"M12 7.2 6.3 15.2M12 7.2l5.7 8M7.2 17h9.6\"/>\n </symbol>\n <symbol id=\"i-plus\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M12 5v14M5 12h14\"/>\n </symbol>\n\n <!-- App 磚塊字形集:一對一取代 app-system.ts 的 ICON_SET 那 12 顆 emoji\n (順序必須與它一致,見 APP_GLYPHS)。 -->\n <symbol id=\"i-doc\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M6 3h7l5 5v12a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1Z\"/><path d=\"M13 3v5h5\"/>\n </symbol>\n <symbol id=\"i-note\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M17 3a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4Z\"/><path d=\"M14.5 5.5 18.5 9.5\"/>\n </symbol>\n <symbol id=\"i-layers\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"m12 3 9 5-9 5-9-5 9-5Z\"/><path d=\"m3 13 9 5 9-5\"/>\n </symbol>\n <symbol id=\"i-pin\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M8.5 3h7l-1 6 3.5 3v2H6v-2l3.5-3-1-6Z\"/><path d=\"M12 14v7\"/>\n </symbol>\n <symbol id=\"i-wrench\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M15.5 3.4a5.2 5.2 0 0 0-6.4 6.4l-5.4 5.4a2 2 0 0 0 2.8 2.8l5.4-5.4a5.2 5.2 0 0 0 6.4-6.4l-3 3-2.8-.4-.4-2.8 3-3Z\"/>\n </symbol>\n <symbol id=\"i-box\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M3.5 7.5 12 3l8.5 4.5v9L12 21l-8.5-4.5v-9Z\"/><path d=\"M3.5 7.5 12 12l8.5-4.5M12 12v9\"/>\n </symbol>\n <symbol id=\"i-folder\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M3 6.5A1.5 1.5 0 0 1 4.5 5h4l2 2.5h7A1.5 1.5 0 0 1 19 9v8.5a1.5 1.5 0 0 1-1.5 1.5h-13A1.5 1.5 0 0 1 3 17.5v-11Z\"/>\n </symbol>\n <symbol id=\"i-check\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"8.5\"/><path d=\"m8 12.2 2.8 2.8L16 9.8\"/>\n </symbol>\n <symbol id=\"i-bulb\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M12 3a6 6 0 0 0-3.5 10.9V16h7v-2.1A6 6 0 0 0 12 3Z\"/><path d=\"M9.8 19h4.4M10.5 21.5h3\"/>\n </symbol>\n <symbol id=\"i-bell\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M18 8.5a6 6 0 1 0-12 0c0 5.5-2 7-2 7h16s-2-1.5-2-7Z\"/><path d=\"M10.2 19a2.2 2.2 0 0 0 3.6 0\"/>\n </symbol>\n <symbol id=\"i-chart\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M4 4v16h16\"/><path d=\"M8 20v-6.5M12.5 20V8.5M17 20v-4\"/>\n </symbol>\n <symbol id=\"i-compass\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"8.5\"/><path d=\"m15.6 8.4-2.1 5.1-5.1 2.1 2.1-5.1 5.1-2.1Z\"/>\n </symbol>\n </defs>\n</svg>\n\n<!-- 登入(未登入只見這個殼;本頁不含任何資料)-->\n<div class=\"authwrap view\" id=\"v-login\">\n <div class=\"authbox\">\n <div>\n <div class=\"brand\" role=\"img\" aria-label=\"Arcrun\"><img class=\"wm-ink\" src=\"data:image/png;base64,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\" alt=\"arc>>run\" width=\"986\" height=\"176\"><img class=\"wm-paper\" src=\"data:image/png;base64,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\" alt=\"arc>>run\" width=\"986\" height=\"176\"></div>\n <div class=\"brand-sub\">知識入口・Portal</div>\n </div>\n <div style=\"display:flex;flex-direction:column;gap:12px;text-align:left\">\n <input type=\"email\" id=\"login-email\" class=\"txt\" placeholder=\"Email\" autocomplete=\"username\" style=\"padding:15px 16px;font-size:17px;border-radius:11px\">\n <input type=\"password\" id=\"login-password\" class=\"txt\" placeholder=\"密碼\" autocomplete=\"current-password\" style=\"padding:15px 16px;font-size:17px;border-radius:11px\">\n <button class=\"btn\" id=\"login-submit\" style=\"margin-top:6px;padding:15px;font-size:17px;letter-spacing:.2em\">登入</button>\n <div id=\"login-status\" class=\"err\" style=\"font-size:14px;min-height:1.2em\"></div>\n </div>\n <!-- 🔴 D50/D62:這裡原本寫「忘記密碼請聯絡管理員重設」+一條「用管理主控台密碼救援自己」\n 的 console 連結。**兩條都是已否決的做法**,不准寫回來:\n ① leo:「我要是記得密碼,還來找忘記密碼幹嘛?」——console 登入頁一樣要密碼\n ② console 與 portal 是安裝時**同一組帳密**寫進兩個地方(D50 補刀)\n ⇒ console 不是第二道閘,是同一把鎖的第二個鑰匙孔,往它補洞不會多出任何一條路\n ③ 唯一管理員忘記密碼時「聯絡管理員」=叫他聯絡他自己\n leo 2026-08-10:「**是對 portal 不是對 console**,這樣 youlin 雖然忘記,\n 我還是可以去 portal 忘記密碼。」⇒ 出口就在這裡。 -->\n <div style=\"font-size:13.5px;color:rgba(var(--ink-rgb),.4);line-height:1.7\">\n 忘記密碼了?<a href=\"#\" id=\"login-forgot\" style=\"color:var(--amber)\">寄一條「修改密碼」連結給我</a>\n </div>\n <div id=\"forgot-box\" class=\"hide\" style=\"display:flex;flex-direction:column;gap:10px;margin-top:4px\">\n <input type=\"email\" id=\"forgot-email\" class=\"txt\" placeholder=\"你註冊時用的 Email\" autocomplete=\"username\">\n <button class=\"btn\" id=\"forgot-submit\">寄出連結</button>\n <div id=\"forgot-status\" style=\"font-size:13.5px;min-height:1.2em;line-height:1.6\"></div>\n </div>\n <button class=\"btn3 themelabel\" data-themetoggle style=\"align-self:center;padding:8px 16px;font-size:13.5px;border-radius:999px\">☾ 切深色</button>\n </div>\n</div>\n\n<!-- 修改密碼(D62):忘記密碼點信裡的連結進來的落點。\n 🔴 這個殼**刻意沒有自己的密碼欄位**——真正的表單是設定頁那一份 #pw-form,\n 進到這個模式時被 JS 原封不動搬進 #reset-slot。D62:「同一個畫面、同一條寫入路徑,\n 差別只有一格:現有密碼是要填、還是被連結豁免。」複製一份長得像的就會漂移。 -->\n<div class=\"authwrap view\" id=\"v-reset\">\n <div class=\"authbox\">\n <div>\n <div style=\"font-size:22px;font-weight:600;margin-bottom:6px\">設定新密碼</div>\n <div id=\"reset-who\" style=\"font-size:14px;color:rgba(var(--ink-rgb),.55);line-height:1.7;margin-bottom:14px\"></div>\n <div id=\"reset-slot\"></div>\n <div id=\"reset-error\" class=\"err\" style=\"font-size:14px;line-height:1.7\"></div>\n <div style=\"margin-top:16px;font-size:13.5px\"><a href=\"#/\" id=\"reset-back\" style=\"color:var(--amber)\">回登入頁</a></div>\n </div>\n </div>\n</div>\n\n<!-- 首次設定(t49leo 07-25:一鍵安裝的用戶打開專屬網址,第一件事就是在這裡建帳號,\n 不再需要回安裝器那頁。auth-status 說 configured:false 才會出現。)-->\n<div class=\"authwrap view\" id=\"v-firstsetup\">\n <div class=\"authbox\">\n <div>\n <div class=\"brand\" role=\"img\" aria-label=\"Arcrun\"><img class=\"wm-ink\" src=\"data:image/png;base64,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\" alt=\"arc>>run\" width=\"986\" height=\"176\"><img class=\"wm-paper\" src=\"data:image/png;base64,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\" alt=\"arc>>run\" width=\"986\" height=\"176\"></div>\n <div class=\"brand-sub\">歡迎!先建立你的帳號</div>\n </div>\n <div style=\"display:flex;flex-direction:column;gap:12px;text-align:left\">\n <input type=\"email\" id=\"fs-email\" class=\"txt\" placeholder=\"你的 Email\" autocomplete=\"username\" style=\"padding:15px 16px;font-size:17px;border-radius:11px\">\n <input type=\"password\" id=\"fs-password\" class=\"txt\" placeholder=\"設定密碼(至少 8 碼)\" autocomplete=\"new-password\" style=\"padding:15px 16px;font-size:17px;border-radius:11px\">\n <input type=\"password\" id=\"fs-password2\" class=\"txt\" placeholder=\"再輸入一次密碼\" autocomplete=\"new-password\" style=\"padding:15px 16px;font-size:17px;border-radius:11px\">\n <button class=\"btn\" id=\"fs-submit\" style=\"margin-top:6px;padding:15px;font-size:17px;letter-spacing:.12em\">建立帳號並進入</button>\n <div id=\"fs-status\" class=\"err\" style=\"font-size:14px;min-height:1.2em\"></div>\n <!-- leo 07-25 實撞:已設定過(409)時這頁是死路——必須有回登入的路 -->\n <button class=\"btn3\" id=\"fs-tologin\" style=\"padding:9px 16px;font-size:14px;border-radius:999px;align-self:center;cursor:pointer\">已經有帳號?改用登入</button>\n </div>\n <div style=\"font-size:13.5px;color:rgba(var(--ink-rgb),.4);line-height:1.7\">這組帳密就是之後登入知識庫用的,只需要設定這一次。</div>\n </div>\n</div>\n\n<!-- 主應用 -->\n<div id=\"shell\">\n <div id=\"sidenav\">\n <div class=\"logo\" role=\"img\" aria-label=\"Arcrun\"><img class=\"wm-ink\" src=\"data:image/png;base64,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\" width=\"986\" height=\"176\" alt=\"arcrun\"><img class=\"wm-paper\" src=\"data:image/png;base64,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\" width=\"986\" height=\"176\" alt=\"arcrun\"></div>\n <!-- Arcrun#152OS 級四段導覽——取代原本的單層清單。已安裝的 App 不再各自佔一格\n 側欄項目,改以「App 界面」頁簽裡的九宮格+「App 市集」頁簽裡的清單呈現\n renderAppsNav()K5 泛用 loader 沿用不變,只是渲染目標從側欄換成這兩處)。 -->\n <div class=\"nav osnav\" data-ostab=\"apps\"><span class=\"os-ic\"><svg><use href=\"#i-apps\"/></svg></span><span>App 界面</span></div>\n <div class=\"nav osnav\" data-ostab=\"market\"><span class=\"os-ic\"><svg><use href=\"#i-market\"/></svg></span><span>App 市集</span></div>\n <div class=\"nav osnav\" data-ostab=\"settings\"><span class=\"os-ic\"><svg><use href=\"#i-settings\"/></svg></span><span>AR 設定</span></div>\n <div class=\"nav osnav\" data-ostab=\"dev\"><span class=\"os-ic\"><svg><use href=\"#i-dev\"/></svg></span><span>App 開發</span></div>\n <div class=\"nav themelabel\" data-themetoggle style=\"margin-top:8px;font-size:14.5px\">☾ 切深色</div>\n <div class=\"foot\" id=\"side-foot\"></div>\n </div>\n <main>\n\n <!-- App 界面(Arcrun#152,落地頁):九宮格啟動器——RAG 搜尋/知識總圖/已安裝 App\n 都以有 icon、點開就用的磚塊呈現,磚塊清單由 renderAppsNav()K5 泛用 loader\n 動態產生,這裡本身 0 硬編清單。 -->\n <div class=\"view page\" id=\"v-launcher\">\n <div class=\"pagehead\"><span class=\"t\" id=\"lh-greet\">App 界面</span><span class=\"m\" id=\"lh-sub\"></span></div>\n <div class=\"launchgrid\" id=\"launch-grid\"><div class=\"muted\" style=\"padding:6px 4px\">載入中…</div></div>\n </div>\n\n <!-- 搜尋(落地頁)-->\n <div class=\"view page\" id=\"v-search\">\n <div class=\"pagehead\"><span class=\"t\">搜尋</span><span class=\"m\" id=\"se-scope\"></span></div>\n <div style=\"padding-top:20px\">\n <div class=\"searchrow\">\n <input id=\"se-q\" placeholder=\"搜尋知識…\" autocomplete=\"off\">\n <button class=\"btn\" id=\"se-go\" style=\"flex:none;padding:0 22px;letter-spacing:.2em\">搜</button>\n </div>\n <div class=\"modebar\">\n <button class=\"modebtn on\" data-mode=\"keyword\">關鍵字</button>\n <button class=\"modebtn\" data-mode=\"semantic\">語意</button>\n <button class=\"modebtn hide\" id=\"mode-graph\" data-mode=\"graph\">圖譜</button>\n </div>\n <!-- AI 問答(portal-demo-suite)。設計哲學:AI 檢索=用戶手動搜尋同一套——\n /portal/data/chat 與 /portal/data/search 走同一個 session 閘、同一個租戶資料面,\n AI 只是代查再作答,不多開任何權限。此實例未安裝問答 workflow 時 server 誠實 404。-->\n <div style=\"margin-top:14px;padding:14px;border-radius:13px;background:rgba(var(--amber-rgb),.05);border:1px solid rgba(var(--amber-rgb),.25)\">\n <div style=\"font-size:13.5px;letter-spacing:.1em;color:rgba(var(--ink-rgb),.5);margin-bottom:9px\">AI 問答・答案附出處,可回搜尋驗證</div>\n <div class=\"searchrow\">\n <input id=\"ai-q\" placeholder=\"用一句話問知識庫…\" autocomplete=\"off\" style=\"padding:12px 15px;font-size:16px\">\n <button class=\"btn\" id=\"ai-go\" style=\"flex:none;padding:0 20px\">問 AI</button>\n </div>\n <div id=\"ai-out\"></div>\n </div>\n <div id=\"se-banner\"></div>\n <div id=\"se-count\" style=\"margin:20px 0 12px;font-size:14px;color:rgba(var(--ink-rgb),.5)\"></div>\n <div class=\"kgrid\" id=\"se-results\"></div>\n <div id=\"se-graphout\" style=\"display:none\">\n <div id=\"gr-box\"></div>\n <div id=\"gr-edges\" style=\"margin-top:16px;display:flex;flex-direction:column;gap:7px\"></div>\n </div>\n </div>\n </div>\n\n <!-- 總圖(Arcrun#39 藏書地圖 GUI 切片;graph 粗閘後可見):全庫三元組一張網。\n 力導向佈局內聯手刻(demo 量級 ≤ 數百節點),不引外部套件(頁面自足原則)。-->\n <div class=\"view page\" id=\"v-map\">\n <div class=\"pagehead\"><span class=\"t\">總圖</span><span class=\"m\" id=\"map-meta\"></span></div>\n <div style=\"padding-top:20px\">\n <div id=\"map-box\"></div>\n <div style=\"margin-top:12px;font-size:13.5px;color:rgba(var(--ink-rgb),.5)\">\n 點節點可跳到該實體的圖譜搜尋。這張圖由知識庫的三元組即時算出——同一份地圖的文字版\n (給 AI 注入用的總庫目錄)<span id=\"map-md-link\"></span>。\n </div>\n </div>\n </div>\n\n <!-- 卡片詳頁 -->\n <div class=\"view page\" id=\"v-card\">\n <div class=\"pagehead\" style=\"justify-content:flex-start;gap:14px\">\n <button class=\"btn3\" style=\"border:none;padding:0;font-size:16px;color:var(--amber)\" data-nav=\"search\"> 搜尋</button>\n <span class=\"serif\" style=\"font-size:17px;letter-spacing:.14em;color:rgba(var(--ink-rgb),.55)\">知識卡片</span>\n </div>\n <div id=\"cd-main\" style=\"padding:24px 0 40px\"><div class=\"muted\">載入中…</div></div>\n </div>\n\n <!-- App 市集(Arcrun#152):已安裝清單沿用 renderAppsNav() 同一份資料(K2 單一真相源);\n 「可安裝」讀 /portal/data/apps/catalog(隨引擎出貨的目錄),按一下就裝。\n 「上傳你的 App」=第三方發佈,那是另一份協定(誰託管/誰審/怎麼簽章),\n 刻意維持佔位,不假裝能用。 -->\n <div class=\"view page narrow\" id=\"v-market\">\n <div class=\"pagehead\"><span class=\"t\">App 市集</span><span class=\"m\">瀏覽、安裝、或上傳你自己做的 App</span></div>\n <div style=\"padding-top:16px\">\n <div class=\"promorow\" id=\"market-upload-banner\">\n <div class=\"ic\">⬆</div>\n <div style=\"flex:1;min-width:0\">\n <div style=\"font-size:14.5px;font-weight:600\">上傳你的 App</div>\n <div style=\"font-size:12.5px;color:rgba(var(--ink-rgb),.55);margin-top:2px\">打包成一份宣告,讓其他人也能安裝——<b style=\"color:var(--ink)\">尚未接後端</b>,先佔位</div>\n </div>\n </div>\n <div class=\"sechead\" style=\"margin-top:22px\">已安裝</div>\n <div class=\"listcol\" id=\"market-installed\"><div class=\"muted\">載入中…</div></div>\n <div class=\"sechead\">可安裝</div>\n <!-- 🔴 底部留白不是排版偏好,是為了讓「安裝/移除」按得到:\n 「還差 1 步」那張安裝清單卡是 `position:fixed; right:20px; bottom:20px; z-index:60`\n 而本頁每一列的動作鍵都靠右 ⇒ 最後幾列的按鈕**整顆被蓋在那張卡下面,點不到**\n 2026-08-25 youlin 實撞:滑鼠按在按鈕上,elementFromPoint 回的是 setup-checklist)。\n 留一段空白 ⇒ 清單永遠捲得上來、按得到。卡片本身不動(它是別條線的東西)。 -->\n <div class=\"listcol\" id=\"market-catalog\" style=\"padding-bottom:240px\"><div class=\"muted\">載入中…</div></div>\n </div>\n </div>\n\n <!-- 上傳(portal-demo-suiteupload bindings 齊全才顯示 nav——/portal/session 的\n upload_enabled;藏只是 UX,真閘在 /portal/data/upload 路由層 404-->\n <div class=\"view page narrow\" id=\"v-upload\">\n <div class=\"pagehead\"><span class=\"t\">上傳</span><span class=\"m\">Markdown / 純文字</span></div>\n <div style=\"margin-top:16px;padding:13px 16px;border-radius:11px;background:rgba(var(--amber-rgb),.06);border:1px dashed rgba(var(--amber-rgb),.35);font-size:14px;line-height:1.7;color:rgba(var(--ink-rgb),.65)\">\n 上傳的文件會進入知識庫收件管線:<b style=\"color:var(--ink)\">約 1 分鐘後可在搜尋頁找到</b>;AI 整理後會以 wiki 卡形式出現。支援 .md / .txt(一律以 .md 收件)。\n </div>\n <div id=\"up-drop\" style=\"margin-top:16px;padding:44px 20px;border-radius:13px;border:2px dashed rgba(var(--amber-rgb),.4);background:rgba(var(--amber-rgb),.04);text-align:center;cursor:pointer\">\n <div style=\"font-size:16px;color:rgba(var(--ink-rgb),.7)\">把 .md / .txt 檔案拖放到這裡</div>\n <div class=\"muted\" style=\"margin-top:8px;font-size:14px\">或</div>\n <button class=\"btn2\" id=\"up-pick\" style=\"margin-top:10px;padding:11px 22px;font-size:15px\">選擇檔案(可多選)</button>\n <input type=\"file\" id=\"up-file\" accept=\".md,.txt\" multiple style=\"display:none\">\n </div>\n <div class=\"listcol\" id=\"up-list\"></div>\n </div>\n\n <!-- 工作流(D-8:預設 admin 才看得到;唯讀,不開 trigger-->\n <!-- App 開發(Arcrun#152):工作環境入口。Workflows/上傳資料是既有功能,收攏成清單;\n 零件/RecipeCredential 現在活在另一套 console owner session(不同認證模型,\n design §四已裁「不新造」),Portal 這裡老實標「尚未接進 Portal」,不假裝能點。\n 「叫 AI 幫你做一個 App」同理——沒有後端,先佔位不假裝能用。 -->\n <div class=\"view page narrow\" id=\"v-dev\">\n <div class=\"pagehead\"><span class=\"t\">App 開發</span><span class=\"m\">Workflows/零件/RecipeCredential</span></div>\n <div style=\"padding-top:16px\">\n <div class=\"promorow\" id=\"dev-ai-banner\">\n <div class=\"ic\">✦</div>\n <div style=\"flex:1;min-width:0\">\n <div style=\"font-size:15px;font-weight:600\">叫 AI 幫你做一個 App</div>\n <div style=\"font-size:13px;color:rgba(var(--ink-rgb),.55);margin-top:2px\">用一句話描述你要什麼——<b style=\"color:var(--ink)\">尚未接後端</b>,先佔位</div>\n </div>\n </div>\n <div class=\"sechead\" style=\"margin-top:20px\">工作環境</div>\n <div class=\"listcol\">\n <div class=\"card-item hide\" id=\"nav-workflows\" data-nav=\"workflows\" style=\"cursor:pointer;display:flex;align-items:center;justify-content:space-between\">\n <span style=\"font-weight:600\">Workflows</span><span class=\"dim\"></span>\n </div>\n <div class=\"card-item hide\" id=\"nav-upload\" data-nav=\"upload\" style=\"cursor:pointer;display:flex;align-items:center;justify-content:space-between\">\n <span style=\"font-weight:600\">資料上傳</span><span class=\"dim\"></span>\n </div>\n <div class=\"card-item\" style=\"opacity:.6\"><div style=\"display:flex;align-items:center;justify-content:space-between\"><span>零件</span><span class=\"tag dim\">尚未接進 Portal</span></div></div>\n <div class=\"card-item\" style=\"opacity:.6\"><div style=\"display:flex;align-items:center;justify-content:space-between\"><span>Recipe</span><span class=\"tag dim\">尚未接進 Portal</span></div></div>\n <div class=\"card-item\" style=\"opacity:.6\"><div style=\"display:flex;align-items:center;justify-content:space-between\"><span>Credential</span><span class=\"tag dim\">尚未接進 Portal</span></div></div>\n </div>\n </div>\n </div>\n\n <div class=\"view page narrow\" id=\"v-workflows\">\n <div class=\"pagehead\"><span class=\"t\">工作流</span><span class=\"m\">唯讀・系統狀態</span></div>\n <div style=\"margin-top:16px;padding:13px 16px;border-radius:11px;background:rgba(var(--amber-rgb),.06);border:1px dashed rgba(var(--amber-rgb),.35);font-size:14px;line-height:1.7;color:rgba(var(--ink-rgb),.65)\">\n 此頁只顯示系統裡的工作流與最近執行狀態,<b style=\"color:var(--ink)\">不能觸發執行</b>(觸發屬系統擁有者權限)。\n </div>\n <div class=\"listcol\" id=\"wf-list\"><div class=\"muted\">載入中…</div></div>\n </div>\n\n <!-- Leo/Arcrun#82 App 系統 v0(K5):泛用畫面容器——所有已安裝的 App 共用這一個\n view,內容由 loadApp()/renderAppView() 依 App id 動態換掉。 -->\n <div class=\"view page\" id=\"v-app\">\n <div class=\"pagehead\">\n <!-- Arcrun#152:返回鍵**不寫在這裡**。leo 2026-08-24 第二輪:「只有筆記有 nav bar,\n 所有的 App 都要顯示,不然他要怎麼回 home?」——第一輪只給 App 頁補了一顆,\n 而九宮格點出去的還有搜尋/總圖/卡片等內建 view,它們一顆都沒有。\n ⇒ 出口改成協定層的東西,由 ensureBackControls() 對**每一個非首頁 view** 統一塞,\n 新增 view 不必記得補。這裡刻意留空,別再手寫第二顆。 -->\n <span class=\"t\" id=\"app-title\">App</span>\n <button class=\"btn3 hide\" id=\"app-remove-btn\" style=\"margin-left:auto;color:var(--err,#c0392b)\">移除這個 App</button>\n </div>\n <div id=\"app-body\"><div class=\"muted\">載入中…</div></div>\n </div>\n\n <!-- 設定 -->\n <div class=\"view page narrow\" id=\"v-settings\">\n <div class=\"pagehead\"><span class=\"t\">設定</span></div>\n <!-- AR 設定頁簽的次層導覽(Arcrun#152):帳號設定/管理原地不動,這裡只加一列切換。\n 「管理」chip 沿用既有 id=\"nav-admin\" 的權限隱藏邏輯(showApp() 依 role 切 hide)。 -->\n <div class=\"subnav\">\n <div class=\"subchip on\" data-nav=\"settings\">帳號</div>\n <div class=\"subchip hide\" id=\"nav-admin\" data-nav=\"admin\">管理</div>\n </div>\n <div class=\"setcol\">\n <!-- 🆕 2026-08-02leo:「不顯示的話用戶不知道要不要更新」+「發現落後就按一下開啟 install」):\n 版本卡放設定頁第一張——用戶想「我是不是舊的」時第一眼就看到。\n 落後時直接給一顆帶 email 的更新按鈕(安裝器 t154 對既有實例免辨識碼),\n 不要求用戶理解版本號、找網址、翻辨識碼。 -->\n <div class=\"panel\" id=\"st-ver-panel\">\n <div style=\"display:flex;align-items:center;gap:12px;flex-wrap:wrap\">\n <div style=\"min-width:0;flex:1\">\n <div style=\"font-size:17px;font-weight:600;display:flex;align-items:center;gap:8px\">\n 版本\n <span id=\"st-ver-dot\" style=\"display:none;width:9px;height:9px;border-radius:50%;background:#C2492E\" title=\"有新版本\"></span>\n </div>\n <div id=\"st-ver-line\" style=\"margin-top:4px;font-size:14px;line-height:1.65;color:rgba(var(--ink-rgb),.55)\">查詢中…</div>\n </div>\n <button class=\"btn\" id=\"st-ver-update\" style=\"display:none\">立即更新</button>\n </div>\n </div>\n <div class=\"panel\">\n <div style=\"font-size:17px;font-weight:600;margin-bottom:10px\">我的帳號</div>\n <div id=\"st-me\"><div class=\"muted\">載入中…</div></div>\n </div>\n <div class=\"panel\">\n <div style=\"display:flex;align-items:center;gap:14px\">\n <div style=\"min-width:0\">\n <div style=\"font-size:17px;font-weight:600\">深色模式</div>\n <div style=\"margin-top:4px;font-size:14px;line-height:1.65;color:rgba(var(--ink-rgb),.55)\">預設淺色(紙感)。切換立即生效,選擇記在這台裝置。</div>\n </div>\n <div class=\"switch\" id=\"st-theme-switch\" data-themetoggle style=\"cursor:pointer\"><i></i></div>\n </div>\n </div>\n <!-- D62leo 2026-08-10):「改密碼與忘記密碼**這兩個機制其實是一個機制,可以簡化**。」\n ⇒ 這個表單是**整個站唯一一份**改密碼的表單。忘記密碼點連結進來時,\n 它會被原封不動搬到 #v-reset 那個殼裡(不是複製一份長得像的)——\n 差別只有「現有密碼」那一格顯不顯示。同一個畫面、同一條寫入路徑。 -->\n <div class=\"panel\" id=\"st-pw-panel\">\n <div style=\"font-size:17px;font-weight:600\" id=\"pw-title\">更改密碼</div>\n <div style=\"margin-top:4px;font-size:14px;color:rgba(var(--ink-rgb),.55)\" id=\"pw-sub\">需輸入舊密碼驗證身分;新密碼至少 8 碼</div>\n <div id=\"pw-form\" style=\"margin-top:14px;display:flex;flex-direction:column;gap:10px\">\n <input type=\"password\" id=\"st-pw-old\" class=\"txt\" placeholder=\"舊密碼\" autocomplete=\"current-password\">\n <input type=\"password\" id=\"st-pw-new\" class=\"txt\" placeholder=\"新密碼(至少 8 碼)\" autocomplete=\"new-password\">\n <input type=\"password\" id=\"st-pw-new2\" class=\"txt\" placeholder=\"再輸入一次新密碼\" autocomplete=\"new-password\">\n <button class=\"btn\" id=\"st-pw-save\">更新密碼</button>\n <div id=\"st-pw-status\" style=\"font-size:14px;min-height:1.2em\"></div>\n </div>\n </div>\n <!-- 07-27 leo:金鑰與下載原本只在一次性的「還差 N 步」卡片裡,按了「稍後再說」\n 或裝完就再也找不到。換金鑰/換電腦重新下載都需要常駐入口,故搬進設定頁。 -->\n <div class=\"panel\">\n <!-- t87 07-28 leo:乾淨網址(只有 origin,不含 /portal/# 後綴),供小幫手連線用 -->\n <div style=\"display:flex;align-items:center;gap:8px;margin-bottom:14px;font-size:13.5px\">\n <span style=\"color:rgba(var(--ink-rgb),.6);white-space:nowrap\">你的知識庫網址(小幫手連線用)</span>\n <code id=\"st-origin-url\" style=\"flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px;color:var(--ink)\"></code>\n <button class=\"btn3\" id=\"st-copy-url\" style=\"padding:5px 12px;font-size:13px;white-space:nowrap;flex:none\">複製</button>\n </div>\n <div style=\"font-size:17px;font-weight:600\">同步小幫手</div>\n <div style=\"margin-top:4px;font-size:14px;line-height:1.65;color:rgba(var(--ink-rgb),.55)\">把你電腦上的資料夾變成知識庫。換電腦或重裝時可以再下載一次。</div>\n <div style=\"margin-top:12px\">\n <a class=\"btn3\" id=\"st-daemon-dl\" href=\"#\" style=\"display:inline-block;padding:11px 18px;border-radius:10px;text-decoration:none\">下載 Mac 版</a>\n <div style=\"margin-top:8px;font-size:13px;line-height:1.7;color:rgba(var(--ink-rgb),.5)\">封測版未簽章,第一次請右鍵→打開。裝好第一次開啟時,貼上這個網址+你的帳號密碼就連上了。</div>\n </div>\n </div>\n <!-- 08-09arcrun-rag#7,封測者原話「說明叫我把 MCP 加進 claude.ai connector,但我找不到網址」):\n 文件一直寫「登入 portal 設定頁直接複製」,但畫面上從沒真的顯示過這串網址——用戶照著文件的\n 指示走到這裡,只會撲空。這裡補上:MCP 網址跟知識庫網址(apiBase)是同一顆自架帳號的\n workers.dev 子網域,只是 worker 名字從 arcrun-cypher-executor 換成 arcrun-mcp\n (CLI 部署當時就是這樣組出這兩個網址的,見 cli/src/lib/deploy.ts:386-392)——\n 純前端字串轉換,不需要後端新端點、不需要安裝器多寫一份設定。 -->\n <div class=\"panel\">\n <div style=\"display:flex;align-items:center;gap:8px;margin-bottom:14px;font-size:13.5px\">\n <span style=\"color:rgba(var(--ink-rgb),.6);white-space:nowrap\">你的 MCP 網址(給你的 AI 連線用)</span>\n <code id=\"st-mcp-url\" style=\"flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px;color:var(--ink)\">—</code>\n <button class=\"btn3\" id=\"st-copy-mcp-url\" style=\"padding:5px 12px;font-size:13px;white-space:nowrap;flex:none\">複製</button>\n </div>\n <div style=\"font-size:17px;font-weight:600\">接上你的 AIMCP</div>\n <div style=\"margin-top:4px;font-size:14px;line-height:1.65;color:rgba(var(--ink-rgb),.55)\">把上面這串網址貼到 Claude、ChatGPT 等 AI 的「新增自訂連接器」欄位,就能讓你的 AI 直接查這個知識庫。</div>\n </div>\n <!-- t176leo 08-03):AI 設定整塊移除。\n 雲端聊天問答走 Workers AI(用戶自己 CF 帳號內建,**免金鑰、裝好就能用**);\n 地端萃取用哪把金鑰改由「同步小幫手」自己設定(托盤選單「AI 設定…」)。\n 為什麼移除:雲端的 extractor 設定是全租戶共用一把 KV,任一處設了 claude\n 會讓所有沒裝 Claude Code 的機器萃取全滅,而這裡的 Claude 勾選框又恆為\n disableddaemon 從未回報 has_claude)⇒ 用戶自己解不開(08-03 封測實證)。\n leo:「搞不清楚設定 AI 是設雲端還是地端」——設定只留一處,就不會再搞混。 -->\n <div class=\"panel\">\n <div style=\"font-size:17px;font-weight:600\">AI 設定</div>\n <div style=\"margin-top:12px;font-size:13.5px;line-height:1.7;color:rgba(var(--ink-rgb),.55);background:rgba(var(--ink-rgb),.03);border-radius:9px;padding:11px 13px\">\n <b style=\"color:var(--ink)\">這裡不需要任何設定。</b>聊天問答用的是你自己 Cloudflare 帳號內建的 AI,裝好就能直接問。<br>\n 文件整理成知識卡的部分,請在<b style=\"color:var(--ink)\">同步小幫手</b>(電腦上的托盤圖示)的「AI 設定…」填一把 Gemini API Key。\n </div>\n </div>\n <!-- 檢修孔演進史:\n 2026-08-07 leo 直接指令「一顆按鈕在設定裡,按鈕下載一個檔案,把檔案發給我」\n →「疑難排解」面板+#st-diag-export 按鈕誕生,打 GET /portal/data/diagnostics。\n\n 2026-08-08t213InkStoneCo 總管交辦)發現這顆按鈕在**封測者的瀏覽器**裡執行,\n 跟他電腦上的 daemon 是兩個獨立行程,構不到本機資料(檔案總量/失敗分類/\n daemon 版本)——完整版改在 arcrun-app(同步小幫手)「版本與更新」頁本機端匯出\n (打新端點 GET /portal/daemon/diagnostics)。當時按鈕先保留當退路,文案改成\n 誠實講清楚自己只有一半、導去完整版。\n\n 2026-08-09leo 拍板拿掉):leo 08-08「雲端那個要刪掉?不刪用戶搞不清楚要去\n 哪裏下載」,封測者已被通知去更新到有地端匯出的版本後,08-09 追認「通知完畢\n 可以刪除」。⇒ 按鈕與 #st-diag-export/#st-diag-status 一併移除,面板改成純文字\n 指路(同步小幫手才是唯一還按得到、也答得出完整診斷的地方)。\n GET /portal/data/diagnostics 端點本身留著未刪(無害、未被任何 UI 呼叫,\n 純粹清路標,不動後端)。 -->\n <div class=\"panel\">\n <div style=\"font-size:17px;font-weight:600\">疑難排解</div>\n <div style=\"margin-top:4px;font-size:14px;line-height:1.65;color:rgba(var(--ink-rgb),.55)\">要回報問題,請到你電腦上的 <b style=\"color:var(--ink)\">Arcrun</b>(同步小幫手)「版本與更新」頁——那裡的「疑難排解」按一下就能匯出完整診斷檔給我們(只有統計數字,不含你的任何文件內容)。</div>\n </div>\n <button class=\"btn3\" id=\"st-logout\" style=\"padding:14px;font-size:16px;border-radius:11px\">登出</button>\n </div>\n </div>\n\n <!-- 管理(P4admin-onlynav 只有 admin 看得到;真閘在 /portal/admin/* role 閘 403-->\n <div class=\"view page\" id=\"v-admin\">\n <div class=\"pagehead\"><span class=\"t\">管理</span><span class=\"m\">帳號與知識庫授權</span></div>\n <div class=\"subnav\">\n <div class=\"subchip\" data-nav=\"settings\">帳號</div>\n <div class=\"subchip on\" data-nav=\"admin\">管理</div>\n </div>\n\n <div class=\"sechead\">執行紀錄保留期</div>\n <div class=\"panel\">\n <div style=\"font-size:16px;font-weight:600;margin-bottom:4px\">保留天數</div>\n <div style=\"font-size:13.5px;color:rgba(var(--ink-rgb),.55);margin-bottom:12px\">執行紀錄是稽核資料,超過保留天數會被每日自動清除;預設 90 天(3 個月),也可設為「不刪除」(企業稽核用途)。</div>\n <div class=\"formrow\">\n <input type=\"number\" id=\"ad-ret-days\" class=\"txt\" min=\"1\" step=\"1\" placeholder=\"天數(例:90\">\n <label style=\"display:flex;align-items:center;gap:7px;white-space:nowrap;font-size:15px;padding:0 4px\">\n <input type=\"checkbox\" id=\"ad-ret-never\"> 不刪除\n </label>\n <button class=\"btn\" id=\"ad-ret-save\" style=\"flex:none;padding:0 20px\">儲存</button>\n </div>\n <div id=\"ad-ret-status\" class=\"err\" style=\"font-size:14px;min-height:1.2em;margin-top:8px\"></div>\n <div id=\"ad-ret-current\" class=\"muted\" style=\"font-size:13px;margin-top:2px\"></div>\n </div>\n\n <div class=\"sechead\">帳號管理</div>\n <div class=\"panel\">\n <div style=\"font-size:16px;font-weight:600;margin-bottom:4px\">新增同仁帳號</div>\n <div style=\"font-size:13.5px;color:rgba(var(--ink-rgb),.55);margin-bottom:12px\">建立後會產生一組一次性密碼——只顯示這一次,請當場轉交同仁(同仁可在「設定」自行改密)。</div>\n <div class=\"formrow\">\n <input type=\"email\" id=\"ad-nu-email\" class=\"txt\" placeholder=\"Email\" autocomplete=\"off\">\n <input type=\"text\" id=\"ad-nu-name\" class=\"txt\" placeholder=\"顯示名(可留空=用 Email\" autocomplete=\"off\">\n <select id=\"ad-nu-role\"><option value=\"user\">一般用戶</option><option value=\"admin\">管理員</option></select>\n <button class=\"btn\" id=\"ad-nu-create\" style=\"flex:none;padding:0 20px\">建立</button>\n </div>\n <div id=\"ad-nu-status\" class=\"err\" style=\"font-size:14px;min-height:1.2em;margin-top:8px\"></div>\n </div>\n <div id=\"ad-otp\"></div>\n <div class=\"listcol\" id=\"ad-users\"><div class=\"muted\">載入中…</div></div>\n\n <div class=\"sechead\">庫目錄管理</div>\n <div style=\"display:flex;align-items:center;gap:8px;margin-bottom:10px;font-size:13.5px\">\n <span style=\"color:rgba(var(--ink-rgb),.6);white-space:nowrap\">你的知識庫網址(小幫手連線用)</span>\n <code id=\"ad-origin-url\" style=\"flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px;color:var(--ink)\"></code>\n <button class=\"btn3\" id=\"ad-copy-url\" style=\"padding:5px 12px;font-size:13px;white-space:nowrap;flex:none\">複製</button>\n </div>\n <div style=\"margin-bottom:12px;padding:12px 15px;border-radius:11px;background:rgba(var(--amber-rgb),.06);border:1px dashed rgba(var(--amber-rgb),.35);font-size:13.5px;line-height:1.7;color:rgba(var(--ink-rgb),.65)\">\n <!-- 07-27 leo:拿掉「登記新庫」——庫由「同步小幫手」看守資料夾時自動蓋章產生,\n 人工登記只會製造對不上的空庫。這裡只做「已存在的庫」的管理。 -->\n 裝好<b style=\"color:var(--ink)\">同步小幫手</b>並選好要看守的資料夾之後,每個資料夾會自動成為一個「庫」出現在下面——<b style=\"color:var(--ink)\">不需要人工新增</b>。下面還是空的,代表小幫手還沒裝好或還沒選資料夾。\n </div>\n <div class=\"listcol\" id=\"ad-libs\"><div class=\"muted\">載入中…</div></div>\n </div>\n\n </main>\n</div>\n\n<!-- 手機底部導覽 -->\n<div id=\"tabbar\">\n <div class=\"tab ostab\" data-ostab=\"apps\"><span class=\"os-ic\"><svg><use href=\"#i-apps\"/></svg></span><span>App 界面</span></div>\n <div class=\"tab ostab\" data-ostab=\"market\"><span class=\"os-ic\"><svg><use href=\"#i-market\"/></svg></span><span>App 市集</span></div>\n <div class=\"tab ostab\" data-ostab=\"settings\"><span class=\"os-ic\"><svg><use href=\"#i-settings\"/></svg></span><span>AR 設定</span></div>\n <div class=\"tab ostab\" data-ostab=\"dev\"><span class=\"os-ic\"><svg><use href=\"#i-dev\"/></svg></span><span>App 開發</span></div>\n</div>\n\n<div id=\"toast\"></div>\n\n<script>\n(function () {\n var API_BASE = window.ARCRUN_API_BASE || '';\n 'use strict';\n // 台北時間 helperlib/taipei-time.ts 注入,console 同套——顯示不隨裝置時區漂移)\n var TAIPEI_OFFSET_MS = 28800000; // UTC+8,台北無 DST\nfunction tpePad(n) { n = String(n); return n.length < 2 ? '0' + n : n; }\nfunction taipeiDayKey(ms) { return new Date(ms + TAIPEI_OFFSET_MS).toISOString().slice(0, 10); }\nfunction taipeiDateStr(ms) { return taipeiDayKey(ms); }\nfunction taipeiDateTimeStr(ms) { var d = new Date(ms + TAIPEI_OFFSET_MS); return taipeiDayKey(ms) + ' ' + tpePad(d.getUTCHours()) + ':' + tpePad(d.getUTCMinutes()); }\nfunction taipeiTimeStr(ms) { var d = new Date(ms + TAIPEI_OFFSET_MS); return tpePad(d.getUTCHours()) + ':' + tpePad(d.getUTCMinutes()) + ':' + tpePad(d.getUTCSeconds()); }\nfunction taipeiMonthDay(ms) { var d = new Date(ms + TAIPEI_OFFSET_MS); return { month: d.getUTCMonth() + 1, day: d.getUTCDate() }; }\n var $ = function (id) { return document.getElementById(id); };\n\n // ── 狀態:只有 session token**沒有租戶字串、沒有 API key**design §3.3)──\n var S = {\n token: localStorage.getItem('arcrun_portal_session') || '',\n profile: null, // /portal/session 回應(display_name/role/libraries/graph_allowed/workflows_visible\n mode: 'keyword',\n cardId: '',\n appId: '' // Leo/Arcrun#82:目前打開的 App id#/app/{id} 路由用)\n };\n\n function esc(s) {\n return String(s == null ? '' : s).replace(/[&<>\"']/g, function (c) {\n return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' }[c];\n });\n }\n function toast(msg) {\n var el = $('toast');\n el.textContent = msg;\n el.style.display = 'block';\n clearTimeout(toast._t);\n toast._t = setTimeout(function () { el.style.display = 'none'; }, 2000);\n }\n // safeJson:把回應當 JSON 解析,**解析不了就回空物件而不是拋例外**(t75 ①,2026-07-28)。\n //\n // 為什麼需要:原本各處都直接 r.json(),但伺服器不一定回 JSON——404 頁、Cloudflare 錯誤頁、\n // 反向代理的 HTML 都是純文字。JSON.parse 一爆,錯誤就沿著 .catch 走到 friendlyErr\n // **技術訊息原文被噴到畫面上**。leo 同事實測看到的就是:\n // 「Unexpected non-whitespace character after JSON at position 4」\n // 真正的原因其實是 `/portal/admin/chat-key` 回 404(實例的 cypher 是舊版沒這端點),\n // 但使用者只看得到一句看不懂的英文 ⇒ 無從判斷是自己打錯還是系統壞了。\n function safeJson(r) {\n return r.text().then(function (t) {\n if (!t) return {};\n try { return JSON.parse(t); } catch (e) { return {}; }\n });\n }\n\n // friendlyErr:給使用者看的訊息,**不外洩技術細節**(t75 ①)。\n // 原本最後一行是 `return m` =把任何例外訊息原樣顯示,包含 JSON parse 錯誤、\n // stack 片段這種對使用者毫無意義、只會嚇到人的東西。\n function friendlyErr(e) {\n var m = e && e.message ? String(e.message) : String(e);\n if (/failed to fetch|load failed|networkerror|network request failed/i.test(m)) return '連線中斷——請檢查網路後重試';\n // JSON 解析類=伺服器回了非預期內容(多半是 404/代理錯誤頁),對使用者說人話。\n if (/json|unexpected token|unexpected non-whitespace/i.test(m)) return '伺服器回應異常,請稍後再試一次(若持續發生請回報)';\n // 其餘:只在含中文(=我們自己寫的訊息)時原樣顯示;純英文技術訊息一律收斂。\n if (/[\\u4e00-\\u9fff]/.test(m)) return m;\n return '操作失敗,請稍後再試一次';\n }\n function authHeaders() { return S.token ? { 'Authorization': 'Bearer ' + S.token } : {}; }\n\n // ── 主題(console 同款,key 獨立)──\n function getTheme() { return document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light'; }\n function setTheme(t) {\n document.documentElement.setAttribute('data-theme', t);\n try { localStorage.setItem('arcrun_portal_theme', t); } catch (e) { /* 私密模式存不了 */ }\n syncThemeUI();\n }\n function syncThemeUI() {\n var dark = getTheme() === 'dark';\n document.querySelectorAll('.themelabel').forEach(function (el) { el.textContent = dark ? '☀ 切淺色' : '☾ 切深色'; });\n var sw = $('st-theme-switch');\n if (sw) sw.classList.toggle('on', dark);\n }\n document.addEventListener('click', function (ev) {\n var t = ev.target.closest('[data-themetoggle]');\n if (t) setTheme(getTheme() === 'dark' ? 'light' : 'dark');\n });\n syncThemeUI();\n\n // created_at 容錯(epoch 秒/毫秒/ISO),顯示一律台北時間(console 同款)\n function parseAtMs(v) {\n if (v == null || v === '') return null;\n if (typeof v === 'number') return v < 1e12 ? v * 1000 : v;\n if (/^\\d+$/.test(v)) { var n = Number(v); return n < 1e12 ? n * 1000 : n; }\n var s = /T/.test(v) ? v : String(v).replace(' ', 'T') + 'Z';\n var ms = Date.parse(s);\n return isNaN(ms) ? null : ms;\n }\n function fmtDate(v) { var ms = parseAtMs(v); return ms == null ? '' : taipeiDateStr(ms); }\n function fmtDateTime(v) { var ms = parseAtMs(v); return ms == null ? '' : taipeiDateTimeStr(ms); }\n\n // ── 極簡 Markdown 渲染(先全 escape 再上格式,防 XSSconsole 同款)──\n function mdInline(s) {\n return s\n .replace(/\\*\\*([^*]+)\\*\\*/g, '<b>$1</b>')\n .replace(/(^|[^\\\\])\\x60([^\\x60]+)\\x60/g, '$1<code>$2</code>');\n }\n function mdRender(src) {\n var lines = String(src || '').split(/\\r?\\n/);\n var out = [], inCode = false, listMode = '';\n function closeList() { if (listMode) { out.push(listMode === 'ul' ? '</ul>' : '</ol>'); listMode = ''; } }\n for (var i = 0; i < lines.length; i++) {\n var raw = lines[i];\n if (/^\\s*\\x60\\x60\\x60/.test(raw)) {\n closeList();\n if (inCode) { out.push('</code></pre>'); inCode = false; }\n else { out.push('<pre><code>'); inCode = true; }\n continue;\n }\n if (inCode) { out.push(esc(raw) + '\\n'); continue; }\n var line = esc(raw);\n var h = raw.match(/^(#{1,4})\\s+(.*)$/);\n if (h) { closeList(); out.push('<h' + h[1].length + '>' + mdInline(esc(h[2])) + '</h' + h[1].length + '>'); continue; }\n if (/^\\s*&gt;\\s?/.test(line)) { closeList(); out.push('<blockquote>' + mdInline(line.replace(/^\\s*&gt;\\s?/, '')) + '</blockquote>'); continue; }\n var li = raw.match(/^\\s*[-*+]\\s+(.*)$/);\n if (li) { if (listMode !== 'ul') { closeList(); out.push('<ul>'); listMode = 'ul'; } out.push('<li>' + mdInline(esc(li[1])) + '</li>'); continue; }\n var oli = raw.match(/^\\s*\\d+[.)]\\s+(.*)$/);\n if (oli) { if (listMode !== 'ol') { closeList(); out.push('<ol>'); listMode = 'ol'; } out.push('<li>' + mdInline(esc(oli[1])) + '</li>'); continue; }\n if (/^\\s*$/.test(raw)) { closeList(); continue; }\n closeList();\n out.push('<p>' + mdInline(line) + '</p>');\n }\n closeList();\n if (inCode) out.push('</code></pre>');\n return out.join('');\n }\n\n // ── entry 顯示 helperssource/library 從 metadata_json 取——server 已 enforce 過權限)──\n function entryMeta(e) {\n try { var m = JSON.parse(e.metadata_json || 'null'); return m && typeof m === 'object' ? m : {}; } catch (er) { return {}; }\n }\n function entrySource(e) { var m = entryMeta(e); return typeof m.source === 'string' ? m.source : ''; }\n // 來源回溯超連結:PORTAL_SOURCE_WEB_BASE 有設且 source 是 gitea:// 才給 href\n // 其餘回空字串=維持純文字(行為與未設時一字不變)。chunk 錨點(#n)捨棄。\n var SOURCE_WEB_BASE = \"\";\n function encSrcPath(p) { return p.split('/').map(encodeURIComponent).join('/'); }\n // 🔴 t21(移植自已刪分支 fix/portal-source-scheme-t212026-08-05 分支整理救回):\n // 新 ingest 鏈(rag_ingest_cardrag_ingest_direct)寫的 metadata.source 是 **kb://<path>**\n // 但這裡原本只認 gitea:// ⇒ 收卡上雲後溯源連結一律失效(B4 部好溯源後一經重灌即再斷鏈)。\n // 三種 scheme 各自的正解:\n // gitea://<path> (舊 rag_ingest v2)→ {base}/<path>,行為一字不變\n // gitea:<org/repo>@<path> km-wiki-ingest 實形)→ {base}/<org/repo>/src/branch/main/<path>\n // kb://<path> (新 ingest 鏈實形)→ **雲端沒有對應網頁,回空字串=維持純文字,不造死鏈**\n function srcHref(src) {\n src = String(src);\n if (!SOURCE_WEB_BASE) return '';\n var base = SOURCE_WEB_BASE.replace(/\\/+$/, '');\n if (src.indexOf('gitea://') === 0) {\n return base + '/' + encSrcPath(src.slice(8).replace(/#\\d+$/, ''));\n }\n if (src.indexOf('gitea:') === 0) {\n var rest = src.slice(6).replace(/#[^#]*$/, '');\n var at = rest.indexOf('@');\n if (at <= 0 || at >= rest.length - 1) return '';\n return base + '/' + encSrcPath(rest.slice(0, at)) + '/src/branch/main/' + encSrcPath(rest.slice(at + 1));\n }\n return '';\n }\n // kb:// 來源的本地相對路徑(去 scheme、去錨點);非 kb:// 回空字串。\n function srcLocalPath(src) {\n src = String(src);\n if (src.indexOf('kb://') !== 0) return '';\n return src.slice(5).replace(/#[^#]*$/, '');\n }\n function entryLib(e) { var m = entryMeta(e); return (typeof m.library === 'string' && m.library) ? m.library : 'general'; }\n // 內部型別 → 人話標籤(2026-08-07entry_type 原始值如 wiki_card / block / execution_log\n // 是資料庫內部分類,不是用戶該懂的詞——尤其 wiki_card 直接違背上傳頁自己講的「AI 整理後\n // 會以 wiki 卡形式出現」,若卡片上貼的標籤是英文 snake_case「wiki_card」,等於自打嘴巴。\n // 未知型別一律落地成中性的「筆記」,不吐原始英文字串給使用者。\n var ENTRY_TYPE_LABEL = {\n wiki_card: '知識卡', block: '知識卡', value: '記錄', workflow: '工作流',\n execution_log: '執行紀錄', todo: '待辦', inbox: '收件', user_template: '範本',\n recipe_submission: '投稿', agent_feedback: '回饋'\n };\n function entryTypeLabel(t) { return ENTRY_TYPE_LABEL[t] || '筆記'; }\n // 搜尋模式的原始值(keyword/semantic)是 API 參數,不是用戶詞彙——一律轉中文再顯示。\n var SEARCH_MODE_LABEL = { keyword: '關鍵字', semantic: '語意', graph: '圖譜' };\n function searchModeLabel(m) { return SEARCH_MODE_LABEL[m] || m; }\n function entryTitle(e) {\n if (e.page_name) return e.page_name;\n var first = String(e.content || '').split(/\\r?\\n/).find(function (l) { return l.trim(); }) || '';\n first = first.replace(/^#+\\s*/, '').replace(/^[-*>]\\s*/, '').trim();\n if (first.length > 60) first = first.slice(0, 60) + '…';\n return first || '(無標題・' + entryTypeLabel(e.entry_type) + '';\n }\n function entrySnippet(e) {\n var lines = String(e.content || '').split(/\\r?\\n/).filter(function (l) { return l.trim(); });\n var body = lines.slice(1).join(' ').replace(/\\s+/g, ' ').trim();\n if (!body) body = lines.join(' ');\n if (body.length > 140) body = body.slice(0, 140) + '…';\n return body;\n }\n\n // ── 路由 ──\n // Leo/Arcrun#82 App 系統 v0K5):'app' 是**唯一**代表「隨便哪個已安裝 App」的 view——\n // 具體是哪一個由 S.appIdroute 的 arg)決定,同 'card' 用 S.cardId 的既有模式。\n // 這樣往後裝第 N 個 App 不必再幫它加一個新的 view/route,本檔維持 0 行改動(K5 驗收)。\n var VIEWS = ['launcher', 'search', 'map', 'card', 'market', 'upload', 'dev', 'workflows', 'admin', 'app', 'settings'];\n var HOME = 'launcher';\n // Arcrun#152:四頁簽 OS 級導覽——每個 view 歸屬哪一個頁簽(用來高亮 #sidenav/#tabbar\n // 的四個 data-ostab 按鈕),以及每個頁簽按鈕點下去要落在哪個 view(其餘子頁一律靠\n // 頁內的磚塊/subnav chip 進入,不需要每個子頁都在頁簽列出現)。\n var OS_TAB_OF_VIEW = {\n launcher: 'apps', search: 'apps', map: 'apps', card: 'apps', app: 'apps',\n market: 'market',\n settings: 'settings', admin: 'settings',\n dev: 'dev', workflows: 'dev', upload: 'dev',\n };\n var OS_TAB_HOME = { apps: 'launcher', market: 'market', settings: 'settings', dev: 'dev' };\n function allowedViews() {\n // 工作流/管理/上傳頁按 session 能力顯示(真閘在 server/portal/data/workflows 403/404、\n // /portal/admin/* role 閘 403、/portal/data/upload 未啟用 404——前端藏只是 UX,curl 直打也繞不過)\n return VIEWS.filter(function (v) {\n if (v === 'workflows') return !!(S.profile && S.profile.workflows_visible);\n if (v === 'admin') return !!(S.profile && S.profile.role === 'admin');\n if (v === 'upload') return !!(S.profile && S.profile.upload_enabled);\n return true;\n });\n }\n function currentRoute() {\n var h = location.hash.replace(/^#\\/?/, '');\n var seg = h.split('/');\n // App 頁的網址是 #/app/{id}——id 是動態的,不在 allowedViews() 的固定清單裡,\n // 所以在一般判斷之前先攔下來(同 'card' 用 arg 帶 cardId 的既有模式)。\n if (seg[0] === 'app') return { raw: 'app', view: 'app', arg: seg.slice(1).join('/') };\n var ok = allowedViews();\n return { raw: seg[0] || '', view: ok.indexOf(seg[0]) >= 0 ? seg[0] : HOME, arg: seg.slice(1).join('/') };\n }\n function nav(view, arg) {\n location.hash = '#/' + view + (arg ? '/' + encodeURIComponent(arg) : '');\n }\n function showView(name) {\n VIEWS.forEach(function (v) { $('v-' + v).classList.toggle('on', v === name); });\n // Arcrun#152:離開 App 頁就把 App 的畫面整個卸下來(見 unmountAppUi 的說明)。\n // `name === 'app'` 時不動——renderAppsNav() 會為了補高亮再叫一次 showView('app')\n // 那一次刻意「不重新整理內容」。\n if (name !== 'app') { try { unmountAppUi(); } catch (e) { /* 卸不掉不擋切頁 */ } }\n // 'card' 借用 'search' 的高亮(既有慣例);'app' 借用動態塞進去的\n // `data-nav=\"app:{id}\"` 那一格——同一時刻只會有一個 App 頁在看,不需要每個 App\n // 各自維護一個 view 容器(同一份 v-app,內容由 renderAppView 換掉)。\n // 🔴 2026-08-24Arcrun#152):選取器從 `#sidenav .nav, #tabbar .tab` 放寬成全文件\n // `[data-nav]`——subnav chip(設定/管理)與 App 開發頁的清單卡片現在活在 `main` 內容\n // 裡,不再只活在側欄/tabbar 兩個容器裡,範圍要跟著放寬,否則這些新位置永遠不會高亮。\n var activeKey = name === 'card' ? 'search' : (name === 'app' ? ('app:' + S.appId) : name);\n document.querySelectorAll('[data-nav]').forEach(function (el) {\n el.classList.toggle('on', el.getAttribute('data-nav') === activeKey);\n });\n var osTab = OS_TAB_OF_VIEW[name] || 'apps';\n document.querySelectorAll('[data-ostab]').forEach(function (el) {\n el.classList.toggle('on', el.getAttribute('data-ostab') === osTab);\n });\n window.scrollTo(0, 0);\n }\n var LOADERS = {\n card: loadCard, map: loadMap, workflows: loadWorkflows, admin: loadAdmin, app: loadApp, settings: loadSettings,\n launcher: renderAppsNav, market: renderAppsNav,\n };\n function route() {\n // 🔴 D62`#/reset?token=…` **不是站內的一個 view**,是「還沒登入的人拿著連結進來」。\n // 少了這一段,下面那行正規化會把不認得的 `reset` 換成 HOME ⇒ **連 token 一起丟掉**,\n // 使用者點信裡的連結會落在搜尋頁、而且再也回不去(連結一次有效,已經耗掉了)。\n // 實測(2026-08-10 stage,瀏覽器):網址被改寫成 `#/search`、修改密碼畫面根本沒出現。\n var rt = resetTokenFromUrl();\n if (rt) { showReset(rt); return; }\n var r = currentRoute();\n if (r.raw && r.raw !== r.view) { location.hash = '#/' + r.view; return; }\n if (r.view === 'card' && r.arg) S.cardId = decodeURIComponent(r.arg);\n if (r.view === 'app' && r.arg) S.appId = decodeURIComponent(r.arg);\n showView(r.view);\n if (LOADERS[r.view]) LOADERS[r.view]();\n }\n window.addEventListener('hashchange', route);\n document.addEventListener('click', function (ev) {\n // OS 頁簽按鈕(#sidenav/#tabbar 的四個 data-ostab):點下去落在該頁簽的落地頁。\n var ot = ev.target.closest('[data-ostab]');\n if (ot) { nav(OS_TAB_HOME[ot.getAttribute('data-ostab')] || 'launcher'); return; }\n var t = ev.target.closest('[data-nav]');\n if (!t) return;\n var dn = t.getAttribute('data-nav');\n // App 磚塊/清單項目用 \"app:{id}\" 帶身分(K5:動態塞進來的,不是固定 view 清單裡的一員)。\n if (dn && dn.indexOf('app:') === 0) { nav('app', dn.slice(4)); return; }\n nav(dn);\n });\n // ── 出口(Arcrun#152leo 2026-08-24 第二輪)────────────────────────────────\n // 「**只有筆記有 nav bar,所有的 App 都要顯示,不然他要怎麼回 home?**」\n //\n // 第一輪的修法只在 App 頁(`#v-app`)手寫了一顆返回鍵——而使用者從九宮格點出去的\n // **不只是 App**:搜尋、知識總圖、卡片、市集⋯⋯全都是「我從首頁點開的東西」,\n // 而它們一顆出口都沒有。leo 就是打開總圖之後卡在那裡。\n // 🔴 病根不是「漏了總圖」,是**出口被做成個案**。所以這裡改成一條規則:\n // **凡不是首頁的 view,頁首第一格一律是同一顆「← 返回」**,由這支統一塞。\n // 新增 view 只要有 `.pagehead` 就自動有出口,不必有人記得補——\n // 「下一個人不需要知道任何事就會做對」跟樣式那件事是同一個判準。\n function ensureBackControls() {\n VIEWS.forEach(function (v) {\n if (v === HOME) return; // 首頁自己就是目的地\n var head = document.querySelector('#v-' + v + ' .pagehead');\n if (!head || head.querySelector('[data-portal-back]')) return; // 冪等,重複呼叫不會長出第二顆\n var b = document.createElement('button');\n b.className = 'btn3 backbtn';\n b.setAttribute('data-portal-back', v);\n b.setAttribute('title', '回首頁(App 界面)');\n b.textContent = '← 返回';\n head.insertBefore(b, head.firstChild); // 位置固定=永遠是頁首第一格\n });\n }\n ensureBackControls();\n // 走 nav() ⇒ 同時留一筆瀏覽器歷史,手機的系統「上一頁」也有效。\n document.addEventListener('click', function (ev) {\n if (ev.target.closest('[data-portal-back]')) nav(HOME);\n });\n\n // Arcrun#152:「上傳你的 App」「叫 AI 幫你做一個 App」兩個佔位入口——刻意不掛\n // data-nav(沒有目的地可去),點下去老實說「尚未接後端」,不假裝能用。\n ['market-upload-banner', 'dev-ai-banner'].forEach(function (id) {\n var el = $(id);\n if (el) el.addEventListener('click', function () { toast('尚未接後端,先佔位'); });\n });\n\n // ── 認證流 ──\n function showAuth() {\n $('v-firstsetup').classList.remove('on');\n $('v-login').classList.add('on');\n $('shell').classList.remove('on');\n $('tabbar').classList.remove('on');\n // t49:全新實例(還沒有任何帳號)→ 換顯示「首次設定」,不讓用戶對著登入殼發呆。\n // 探測走 console/auth-statusconfigured 布林,console 首設同一顆;失敗就保持登入殼=誠實降級)。\n fetch(API_BASE + '/console/auth-status')\n .then(function (r) { return safeJson(r); })\n .then(function (d) {\n if (d && d.configured === false) {\n $('v-login').classList.remove('on');\n $('v-firstsetup').classList.add('on');\n }\n })\n .catch(function () { /* 探測不到就維持登入殼 */ });\n }\n function showApp() {\n $('v-login').classList.remove('on');\n $('v-firstsetup').classList.remove('on');\n $('shell').classList.add('on');\n $('tabbar').classList.add('on');\n // t53leo 07-25:「進站要做的事——給金鑰、下載 daemon——不然這個安裝沒完成」):\n // 常駐「完成安裝」清單卡,三件做完才消失(localStorage 記進度;admin 才看得到——\n // 金鑰與 daemon 設定是裝機者的事,同事帳號不顯示)。\n try { renderSetupChecklist(); } catch (e) { /* 清單卡失敗不擋主流程 */ }\n var p = S.profile || {};\n $('side-foot').innerHTML = esc(p.display_name || '') + '<br>' + esc(location.host);\n // Arcrun#152:原本每個能力在側欄與 tabbar 各佔一格(nav-Xtab-X 各一份要同步 hide),\n // 現在子頁的清單卡片/subnav chip 活在 `main` 內容裡,桌機/手機共用同一份 DOM\n // (由既有的 700px/1024px CSS 斷點決定要不要顯示 #sidenav/#tabbar,不是各自複製一份)\n // ⇒ 每個能力只剩一顆元素要切 hide,tab-* 那份不再存在。\n $('nav-workflows').classList.toggle('hide', !p.workflows_visible);\n // 上傳:一般用戶可見,但只在實例啟用上傳(bindings 齊全)時顯示(未啟用的實例零影響)\n $('nav-upload').classList.toggle('hide', !p.upload_enabled);\n $('nav-admin').classList.toggle('hide', p.role !== 'admin');\n $('mode-graph').classList.toggle('hide', !p.graph_allowed);\n var libs = p.libraries || [];\n $('se-scope').textContent = libs.indexOf('*') >= 0 ? '範圍:全部知識庫' : ('範圍:' + libs.join('・'));\n // Leo/Arcrun#82 App 系統 v0(K5):清單一律從這裡動態撈,不再有第二份硬編清單。\n // Arcrun#152:渲染目標從側欄/tabbar 換成「App 界面」磚塊格與「App 市集」已安裝清單。\n try { renderAppsNav(); } catch (e) { /* 清單讀不到不擋主流程(同 setup checklist 慣例) */ }\n if (!location.hash) location.hash = '#/' + HOME;\n route();\n }\n // t161leo 07-31 實撞:「實際上根本沒連上任何庫,清單空白」):session 過期時\n // 舊行為=靜默清 token 跳回登入頁,**畫面不說任何原因** ⇒ 用戶以為「庫不見了/系統壞了」。\n // 友善=前端:踢回登入頁時一定要說「為什麼」,用戶才知道下一步做什麼(重新登入即可,資料都在)。\n function dropSession(reason) {\n S.token = '';\n S.profile = null;\n try { localStorage.removeItem('arcrun_portal_session'); } catch (e) { /* noop */ }\n showAuth();\n var msg = reason || '你的登入已過期,請重新登入(你的資料都還在,不會遺失)。';\n try {\n var el = $('login-status');\n if (el) el.textContent = msg;\n } catch (e) { /* 登入殼還沒渲染就算了 */ }\n }\n function boot() {\n // D62:信裡的「修改密碼」連結最優先——這個人**就是進不去才收到這封信的**,\n // 不可以因為瀏覽器裡剛好還留著一個舊 token 就把他丟去別的畫面。\n var rt = (typeof resetTokenFromUrl === 'function') ? resetTokenFromUrl() : '';\n if (rt) { showReset(rt); return; }\n if (!S.token) { showAuth(); return; }\n fetch(API_BASE + '/portal/session', { headers: authHeaders() })\n .then(function (r) { return safeJson(r).then(function (d) { return { ok: r.ok, status: r.status, d: d }; }); })\n .then(function (x) {\n // 🔴 arcrun-rag#66**只有 401 才算「你被登出了」**。\n // 舊版是 `if (!x.ok) dropSession()` 任何非 2xx 都清掉 token——\n // 包含改完密碼後那幾十秒的 503(認證 secret 正在鋪開)與 502(KBDB 暫時不可達)。\n // 那正是 leo 08-10「改完密碼、重新整理就回不去」的最後一哩:\n // 後端就算不刪 KV,前端自己把鑰匙丟了,結果一樣。\n if (x.status === 401) { dropSession(); return; }\n if (!x.ok) {\n // 暫時性故障:留著 session,告訴他這是暫時的、下一步做什麼。\n showAuth();\n $('login-status').textContent = (x.d && x.d.code === 'auth_store_propagating')\n ? '認證資料正在更新中(通常幾十秒),請稍候重新整理——你並沒有被登出。'\n : '服務暫時不可用,請稍後重新整理(你的登入沒有失效)。';\n return;\n }\n S.profile = x.d;\n showApp();\n })\n .catch(function () {\n // 斷網時不清 session(誠實:連不上 ≠ session 失效),顯示登入殼並提示\n showAuth();\n $('login-status').textContent = '連線中斷——請檢查網路後重新整理';\n });\n }\n $('login-submit').addEventListener('click', doLogin);\n $('login-password').addEventListener('keydown', function (ev) { if (ev.key === 'Enter') doLogin(); });\n function doLogin() {\n var email = $('login-email').value.trim();\n var password = $('login-password').value;\n if (!email || !password) { $('login-status').textContent = '請輸入 Email 與密碼'; return; }\n $('login-submit').disabled = true;\n $('login-status').textContent = '';\n fetch(API_BASE + '/portal/login', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email: email, password: password })\n })\n .then(function (r) { return safeJson(r).then(function (d) { return { ok: r.ok, status: r.status, d: d }; }); })\n .then(function (x) {\n $('login-submit').disabled = false;\n if (!x.ok) { $('login-status').textContent = x.d.error || '登入失敗'; return; }\n S.token = x.d.session_token;\n try { localStorage.setItem('arcrun_portal_session', S.token); } catch (e) { /* 私密模式只活本次 */ }\n $('login-password').value = '';\n boot();\n })\n .catch(function (e) { $('login-submit').disabled = false; $('login-status').textContent = friendlyErr(e); });\n }\n // t72 OS 分流(2026-07-27leo:「客戶是用 windows 的」)——在此之前四處寫死「下載 Mac 版」,\n // Windows 客戶按下去會拿到 Mac 的 .app=按了連到錯的東西(leo 判準:那不算友善)。\n // 判不出 OS 時**兩個都給**,不替用戶猜;且無論判成哪個,頁面都留「不是這個系統?」的另一版連結\n // ——UA 會判錯,判錯時用戶要有路可走(施工圖 §3 注意事項 1、3)。\n var DAEMON_BASE_DEFAULT = 'https://raw.githubusercontent.com/youlinhsieh/arcrun-rag-bundles/main/daemon/';\n // 🔴 2026-08-05 leo:「Mac 強調要包裝成 application + dmg 的格式,拖進去就會放到\n // application,**解決之前直接在下載資料夾啟動造成更新問題**」\n // ⇒ Mac 一律給 **DMG**(開啟後是「把 Arcrun 拖進 Applications」的標準畫面),\n // 不再給 zip——zip 解開就是 .app,使用者很可能直接在「下載」資料夾雙擊啟動,\n // 而自更新會蓋錯位置(t184 Oscar 的病)。\n // ⚠️ 用**固定檔名**(不帶版號),否則每出一版都要改這裡的 code。\n //\n // 🔴 2026-08-06 升級(leo:「Portal 和 rag.arcrun.dev 應該顯示同步器的版本⋯⋯\n // **連我都沒辦法確認**,所以用戶到底是否最新版他自己也不知道」):\n // 下面兩個常數**降級為退路**,正常情況改向 `/api/latest` 取\n // `daemon.version` 與 `daemon.downloads`(真相源=bundles 的 manifest)。\n // ⚠️ 這**沒有違背**上面那條「不要每出一版就改 code」——網址現在是**取來的**,\n // 一樣不用改 code;而且順便解掉固定別名的兩個老問題:\n // ① 別名指向 @main,會吃到 CDN/ref 快取拿到舊檔(08-04 撞過)\n // ② 檔名不帶版號 ⇒ 頁面上無從顯示「這是哪一版」=leo 這次抱怨的正題\n // 取不到就退回這兩個固定檔名,按鈕不會變死連結。\n var DAEMON_MAC = 'ArcrunRAG-mac.dmg';\n var DAEMON_WIN = 'ArcrunRAG-win-unsigned.zip';\n // 由 /api/latest 填入(見下方 loadDaemonLatest);null=還沒取到或取不到。\n var DAEMON_LATEST = null;\n // Mac 那顆 > jsDelivr 單檔 20MB 上限(實測回 \"File size exceeded...\")→ 一律走 raw\n // Windows 同走 raw 保持單一來源、少一個會壞的地方。\n function daemonBase() {\n var cfg = (window.ARCRUN_CONFIG || {});\n if (cfg.daemonBase) return String(cfg.daemonBase).replace(/\\/?$/, '/');\n // 舊 key 相容(施工圖 §3 注意事項 2):daemonDownload 是「單一檔案網址」,\n // 有設就尊重它當 Mac 版網址,並由它推出目錄給 Windows 版用。\n if (cfg.daemonDownload) {\n var s = String(cfg.daemonDownload);\n return s.slice(0, s.lastIndexOf('/') + 1) || DAEMON_BASE_DEFAULT;\n }\n return DAEMON_BASE_DEFAULT;\n }\n function daemonPick() {\n var base = daemonBase();\n var ua = navigator.userAgent || '';\n // 手機/平板先排除:iOS 的 UA 含 \"Mac OS X\",不排除會把 iPhone 判成 Mac,\n // 讓手機用戶下載一個裝不起來的桌面 app(測到才發現,2026-07-27)。\n // 手機=判不出桌面 OS → 落到「兩個都給」,用戶回桌機再選。\n var isMobile = /iPhone|iPad|iPod|Android|Mobile/i.test(ua);\n var isWin = !isMobile && /Windows NT/i.test(ua);\n var isMac = !isMobile && /Macintosh|Mac OS X/i.test(ua) && !/Windows/i.test(ua);\n // 有取到真相源就用它的網址(帶版號、指向釘點 sha),否則退回固定別名。\n var dlm = (DAEMON_LATEST && DAEMON_LATEST.downloads && DAEMON_LATEST.downloads.mac) || (base + DAEMON_MAC);\n var dlw = (DAEMON_LATEST && DAEMON_LATEST.downloads && DAEMON_LATEST.downloads.win) || (base + DAEMON_WIN);\n var mac = { os: 'mac', label: '下載 Mac 版', url: dlm };\n var win = { os: 'win', label: '下載 Windows 版', url: dlw };\n if (isWin) return { pick: win, other: mac, sure: true };\n if (isMac) return { pick: mac, other: win, sure: true };\n return { pick: null, other: null, sure: false, mac: mac, win: win };\n }\n // 封測期第一次開啟的擋關提示(未簽章)——Mac/Windows 攔法不同,話術也不同。\n function daemonHint(os) {\n if (os === 'win') return '(封測版未簽章,Windows 第一次會跳藍色視窗擋下來——點「更多資訊」→「仍要執行」就好)';\n // DMG 版的步驟與 zip 不同:先拖進「應用程式」再從那裡開,才不會在下載資料夾啟動。\n return '(開啟後把 Arcrun 拖進「應用程式」,再從啟動台開啟;封測版未簽章,第一次請右鍵→打開)';\n }\n // 07-27:設定頁的常駐入口(下載小幫手/換 AI 金鑰)——與一次性卡片同一組 API\n // 🔴 2026-08-06 改成「先用退路畫、取到真相源再重畫」:\n // fetch 是非同步的,若等它回來才畫,網路慢時使用者會看到一顆沒有網址的按鈕。\n // ⇒ 先用固定別名畫出可用的按鈕,取到 /api/latest 後再重畫成帶版號的網址+版本行。\n // renderDaemonDownload 必須**可重複呼叫**(第二次要清掉第一次插進去的兄弟節點),\n // 否則重畫會疊出兩份「不是這個系統?」。\n function renderDaemonDownload() {\n var dl = $('st-daemon-dl');\n if (!dl) return;\n // 清掉上一輪插入的節點(用 id 標記,才不會誤刪別人的東西)\n ['st-daemon-alt', 'st-daemon-ver'].forEach(function (id) {\n var old = $(id); if (old && old.parentNode) old.parentNode.removeChild(old);\n });\n var d = daemonPick();\n var alt = document.createElement('span');\n alt.id = 'st-daemon-alt';\n alt.className = 'muted';\n alt.style.cssText = 'font-size:12.5px;margin-left:8px';\n if (d.sure) {\n dl.setAttribute('href', d.pick.url);\n dl.textContent = d.pick.label;\n // 判對了也要留另一版的路(UA 會判錯)\n alt.innerHTML = '不是這個系統?<a href=\"' + d.other.url + '\">' + d.other.label + '</a>';\n } else {\n // 判不出來=兩個都給,不預設 Mac\n dl.setAttribute('href', d.mac.url);\n dl.textContent = d.mac.label;\n alt.innerHTML = '或 <a href=\"' + d.win.url + '\">' + d.win.label + '</a>';\n }\n if (dl.parentNode) dl.parentNode.insertBefore(alt, dl.nextSibling);\n\n // 版本行:leo 要的「用戶看得出自己是不是最新版」。\n // 取不到就**不顯示**,不要編一個數字(同 landing 的原則:寧可空著也不說謊)。\n if (DAEMON_LATEST && DAEMON_LATEST.version) {\n var ver = document.createElement('div');\n ver.id = 'st-daemon-ver';\n ver.className = 'muted';\n ver.style.cssText = 'font-size:12.5px;margin-top:6px';\n ver.innerHTML = '最新的同步器版本是 <strong>' + esc(DAEMON_LATEST.version) + '</strong>'\n + '(你手上那支的版本,在同步器視窗左下角)'\n + ' · <a href=\"https://rag.arcrun.dev/docs/help/changelog/\" target=\"_blank\" rel=\"noopener\">這一版改了什麼</a>';\n if (alt.parentNode) alt.parentNode.insertBefore(ver, alt.nextSibling);\n }\n }\n\n function loadDaemonLatest() {\n // 不用 INSTALLER_ORIGIN:它宣告在本區塊之後(var 提升 ⇒ 這裡是 undefined)。\n fetch('https://install.arcrun.dev/api/latest')\n .then(function (r) { return r.ok ? r.json() : null; })\n .then(function (j) {\n if (j && j.daemon && j.daemon.version) {\n DAEMON_LATEST = j.daemon;\n renderDaemonDownload(); // 取到了才重畫\n }\n })\n .catch(function () { /* 取不到就維持退路的固定別名,按鈕仍可用 */ });\n }\n\n renderDaemonDownload();\n loadDaemonLatest();\n\n // t176leo 08-03):AI 設定的前端邏輯整段移除。\n // 雲端聊天走 Workers AI(免金鑰);地端萃取金鑰改由同步小幫手托盤「AI 設定…」自己設。\n // 原本這裡有 Claude 勾選框的 enable/disable 邏輯——它依賴 daemon 回報 has_claude\n // 而 daemon 從未實作該回報 ⇒ 勾選框恆為 disabled(leo 實測「hover 變可點但點擊沒反應」)。\n\n $('st-logout').addEventListener('click', function () {\n fetch(API_BASE + '/portal/logout', { method: 'POST', headers: authHeaders() }).catch(function () { /* 盡力而為 */ });\n dropSession();\n });\n\n // 檢修孔前端已於 2026-08-09 移除(t213,leo 拍板「通知完畢可以刪除」)——\n // #st-diag-export 元素不再存在,匯出診斷檔改在 arcrun-app(同步小幫手)\n // 「版本與更新」頁本機端做。GET /portal/data/diagnostics 端點本身未刪(無害、\n // 已無任何 UI 呼叫),只是這裡不再掛按鈕去打它。\n\n // t87 07-28 leo:複製任意網址到剪貼簿的共用 helper08-09 從 copyOriginUrl 拆出\n // copyText,讓 MCP 網址這種「不是 location.origin」的字串也能共用同一套按鈕行為)。\n function copyText(btn, url) {\n var orig = btn.textContent;\n if (!navigator.clipboard || !navigator.clipboard.writeText) {\n alert('請手動選取並複製:' + url);\n return;\n }\n navigator.clipboard.writeText(url).then(function () {\n btn.textContent = '已複製';\n setTimeout(function () { btn.textContent = orig; }, 1500);\n }).catch(function () {\n alert('請手動選取並複製:' + url);\n });\n }\n function copyOriginUrl(btn) { copyText(btn, location.origin); }\n (function () {\n ['st-origin-url', 'ad-origin-url'].forEach(function (id) {\n var el = $(id); if (el) el.textContent = location.origin;\n });\n ['st-copy-url', 'ad-copy-url'].forEach(function (id) {\n var el = $(id); if (el) el.addEventListener('click', function () { copyOriginUrl(this); });\n });\n })();\n\n // 08-09arcrun-rag#7):MCP 網址=apiBase 換一個 worker 名字(arcrun-cypher-executor →\n // arcrun-mcp),同一顆自架帳號的 workers.dev 子網域(deploy.ts:386-392 部署時就是這樣組的)。\n // 不是這個形狀(例如官方多租戶自訂網域)就誠實留空,不亂猜一個貼上去會連錯的網址。\n function mcpUrlFromApiBase() {\n try {\n var u = new URL(window.ARCRUN_API_BASE);\n if (u.hostname.indexOf('arcrun-cypher-executor.') === 0) {\n u.hostname = u.hostname.replace('arcrun-cypher-executor.', 'arcrun-mcp.');\n return u.origin + '/mcp';\n }\n } catch (e) { /* apiBase 空值或格式不符時不猜 */ }\n return '';\n }\n (function () {\n var mcpUrl = mcpUrlFromApiBase();\n var el = $('st-mcp-url');\n var btn = $('st-copy-mcp-url');\n if (el) el.textContent = mcpUrl || '(尚未偵測到,請確認安裝已完成)';\n if (btn) {\n if (mcpUrl) {\n btn.addEventListener('click', function () { copyText(this, mcpUrl); });\n } else {\n btn.disabled = true;\n }\n }\n })();\n\n // ── t53 完成安裝清單(進站必見,做完才消失)───────────────────────────────\n // 件數演進:t53 三件 → t54 兩件(設定檔改由小幫手憑帳密自取)\n // → arcrun-rag#81 一件(AI 問答改走 Workers AI,不再要用戶自備金鑰)。\n function setupSteps() {\n try { return JSON.parse(localStorage.getItem('arcrun_setup_steps') || '{}'); } catch (e) { return {}; }\n }\n function markStep(k) {\n var s = setupSteps(); s[k] = 1;\n try { localStorage.setItem('arcrun_setup_steps', JSON.stringify(s)); } catch (e) { /* noop */ }\n renderSetupChecklist();\n }\n function renderSetupChecklist() {\n var old = document.getElementById('setup-checklist');\n if (old) old.remove();\n var p = S.profile || {};\n if (p.role !== 'admin') return;\n var s = setupSteps();\n // arcrun-rag#81leo 08-12:「已經改用 workers AI,刪掉」):只剩「下載小幫手」一件。\n // 舊的 s.key(貼 Google AI 金鑰)已整條移除,見下方 innerHTML 處的說明。\n // 相容:舊瀏覽器 localStorage 裡殘留的 s.key 不再被讀 —— 沒設過 key 的人也不會被卡住。\n if (s.daemon) return; // t54 起設定改由小幫手輸入帳密自取,不再下載檔案\n var cfg = window.ARCRUN_CONFIG || {};\n var dpick = daemonPick(); // t72 OS 分流(同一組判定,見上面 daemonPick\n var daemonUrl = dpick.sure ? dpick.pick.url : dpick.mac.url;\n var row = function (done, id, html) {\n return '<div style=\"display:flex;gap:10px;align-items:baseline;margin-top:10px\">'\n + '<span>' + (done ? '✅' : '⬜') + '</span><div style=\"flex:1\">' + html + '</div></div>';\n };\n var el = document.createElement('div');\n el.id = 'setup-checklist';\n el.style.cssText = 'position:fixed;right:20px;bottom:20px;z-index:60;max-width:400px;width:calc(100% - 40px);padding:18px 20px;border-radius:14px;background:rgba(var(--amber-rgb),.10);border:1px solid rgba(var(--amber-rgb),.45);backdrop-filter:blur(8px);font-size:14px;line-height:1.65';\n // 🔴 arcrun-rag#81leo 08-12):第二項「啟用 AI 問答(貼 Google AI 金鑰)」整條刪除。\n // 為什麼不是「一個沒用的欄位」而已:它長在**安裝完成清單裡而且是勾選項**\n // ⇒ 用戶會以為不做這步就沒裝完,而它要人離開流程、去第三方網站申請帳號、\n // 把金鑰貼進表單——整條安裝路徑上最重的一個動作,而且是白做的。\n // 真相:雲端問答走 t18108-04)改好的 Workers AI`env.AI` binding,免金鑰)——\n // /portal/data/chat → tenant 的 rag_chat workflow → `workers_ai_chat` recipe\n // api-recipe-seeds.ts:150endpoint `@cf/meta/llama-4-scout-17b-16e-instruct`)。\n // 這裡貼的金鑰是打 POST /portal/admin/ai 存一筆雲端 gemini_api_key credential\n // **現行問答鏈路一個地方都沒有讀它**。\n // 後端 route 本身不動(同 08-09 拿掉檢修孔按鈕的處置:端點無害、已無任何 UI 呼叫,\n // 純粹清路標);已經存過金鑰的人那筆 credential 也原封不動,不做刪除。\n // ⚠️ 別把這個跟設定頁「AI 設定」面板講的地端萃取金鑰搞混——那把是填在\n // **同步小幫手**托盤裡的,從來不經過這個清單。\n el.innerHTML = '<b>還差 1 步,安裝就真的完成了</b>'\n + row(s.daemon, 'daemon',\n '<b>下載同步小幫手</b>(把資料夾變成知識庫)<br>'\n + (daemonUrl\n // t72:按鈕字樣+擋關話術都跟著 OS 走;並且一律附「另一個系統」的連結\n //(UA 判錯時用戶要有路走;判不出來時=兩個平等並列,不預設 Mac)\n ? '<a href=\"' + esc(daemonUrl) + '\" id=\"sc-daemon\">'\n + esc(dpick.sure ? dpick.pick.label : dpick.mac.label) + '</a>'\n + '<span class=\"muted\" style=\"font-size:12.5px\">'\n + esc(daemonHint(dpick.sure ? dpick.pick.os : 'mac')) + '</span>'\n + '<div class=\"muted\" style=\"font-size:12.5px\">'\n + (dpick.sure\n ? '不是這個系統?<a href=\"' + esc(dpick.other.url) + '\">' + esc(dpick.other.label) + '</a>'\n : '或 <a href=\"' + esc(dpick.win.url) + '\">' + esc(dpick.win.label) + '</a>')\n + '</div>'\n // 誠實降級(leo 判準:按了連到錯的機制=不友善):沒有可用下載點時\n // 不放死連結,說明現況並讓這步可手動打勾,不卡住清單。\n : '<span class=\"muted\" style=\"font-size:13px\">封測期由我們直接寄給你安裝檔;'\n + '收到後回來按 <a href=\"#\" id=\"sc-daemon\">我已經裝好了</a>。</span>')\n // t54(leo:「最好的就是把它的帳密直接輸入」):設定不再是一個要下載的檔案——\n // 小幫手第一次開啟會問網址+帳密,自己去換設定。\n + '<div class=\"muted\" style=\"font-size:12.5px;margin-top:4px\">裝好第一次開啟時,貼上這個網址+你的帳號密碼就連上了,不用下載設定檔。</div>')\n + '<div style=\"margin-top:10px;text-align:right\"><button id=\"sc-later\" style=\"border:none;background:none;color:inherit;cursor:pointer;font-size:12.5px;text-decoration:underline;opacity:.65\">稍後再說</button></div>';\n document.body.appendChild(el);\n var dl = document.getElementById('sc-daemon');\n if (dl) dl.addEventListener('click', function () { markStep('daemon'); });\n // t54config.json 下載鈕已移除(設定由小幫手憑帳密自取)\n // arcrun-rag#81:金鑰輸入框的送出邏輯(POST /portal/admin/ai)一併移除——\n // 只藏畫面留著那條路,等於這個要求還在,只是變得更難發現。\n var later = document.getElementById('sc-later');\n if (later) later.addEventListener('click', function () { el.remove(); }); // 只藏本次,下次進站再提醒\n }\n\n // ── t49 首次設定(leo 07-25):console/setup → portal/admin/bootstrap → 預設庫登記 → portal/login\n // 四發全是既有端點,一顆按鈕做完;用戶感受=「建一組帳密就進來了」。\n $('fs-submit').addEventListener('click', doFirstSetup);\n $('fs-password2').addEventListener('keydown', function (ev) { if (ev.key === 'Enter') doFirstSetup(); });\n $('fs-tologin').addEventListener('click', function () {\n $('v-firstsetup').classList.remove('on');\n $('v-login').classList.add('on');\n });\n function doFirstSetup() {\n var email = $('fs-email').value.trim();\n var pw = $('fs-password').value;\n var st = $('fs-status');\n if (!email || pw.length < 8) { st.textContent = '請填 Email,密碼至少 8 碼'; return; }\n if (pw !== $('fs-password2').value) { st.textContent = '兩次密碼不一樣'; return; }\n $('fs-submit').disabled = true; st.textContent = '';\n var post = function (path, body, hdrs) {\n return fetch(API_BASE + path, {\n method: 'POST',\n headers: Object.assign({ 'Content-Type': 'application/json' }, hdrs || {}),\n body: JSON.stringify(body)\n }).then(function (r) { return r.json().catch(function () { return {}; }).then(function (d) { return { ok: r.ok, status: r.status, d: d }; }); });\n };\n post('/console/setup', { email: email, password: pw })\n .then(function (x) {\n // 已設定過(409)=這實例其實有人建過了——自動帶去登入,別把用戶困在死路(leo 實撞)\n if (x.status === 409) {\n $('fs-submit').disabled = false;\n $('v-firstsetup').classList.remove('on');\n $('v-login').classList.add('on');\n $('login-email').value = email;\n $('login-status').textContent = '這個知識庫已經設定過帳號了,直接登入即可。';\n throw { handled: true };\n }\n if (!x.ok || !x.d.session_token) throw new Error(x.d.error || '設定沒有成功,請再試一次');\n var ownerTok = x.d.session_token;\n return post('/portal/admin/bootstrap', { email: email, password: pw, display_name: email.split('@')[0] }, { Authorization: 'Bearer ' + ownerTok })\n .then(function (b) {\n // 409=已 bootstrap 過(冪等視為就緒);其餘失敗誠實丟出\n if (!b.ok && b.status !== 409) throw new Error(b.d.error || '初始化沒有成功,請再試一次');\n return post('/portal/login', { email: email, password: pw });\n });\n })\n .then(function (l) {\n if (!l.ok || !l.d.session_token) throw new Error(l.d.error || '帳號建好了,但自動登入沒成功——請用剛設定的帳密登入');\n S.token = l.d.session_token;\n try { localStorage.setItem('arcrun_portal_session', S.token); } catch (e) { /* noop */ }\n })\n .then(function () {\n $('fs-submit').disabled = false;\n try { localStorage.setItem('arcrun_onboarding', '1'); } catch (e) { /* noop */ }\n boot();\n })\n .catch(function (e) {\n if (e && e.handled) return; // 409 已自動切登入,不再顯示錯誤\n $('fs-submit').disabled = false;\n st.textContent = (e && e.message) || friendlyErr(e);\n });\n }\n\n // 任何 data 請求收到 401 → session 失效 → 回登入殼\n //\n // 🔴 arcrun-rag#66 的前端那一半:後端在「認證資料正在鋪開」時改回 503\n // `auth_store_propagating`(不再回 401、也不再刪 KV 那筆 session)。\n // 這裡**必須跟著只認 401**——若前端把任何錯誤都當登出,後端不刪也沒用:\n // 使用者手上的 token 會被自己的瀏覽器丟掉,症狀跟被踢出去一模一樣。\n // (503 由各呼叫點自己顯示錯誤訊息,session 原封不動。)\n function guard401(status) {\n if (status === 401) { dropSession(); return true; }\n return false;\n }\n\n // ── 搜尋 ──\n document.querySelectorAll('.modebtn').forEach(function (b) {\n b.addEventListener('click', function () {\n S.mode = b.getAttribute('data-mode');\n document.querySelectorAll('.modebtn').forEach(function (x) { x.classList.toggle('on', x === b); });\n if ($('se-q').value.trim()) doSearch();\n });\n });\n $('se-go').addEventListener('click', doSearch);\n $('se-q').addEventListener('keydown', function (ev) { if (ev.key === 'Enter') doSearch(); });\n function doSearch() {\n var q = $('se-q').value.trim();\n if (!q) { $('se-count').textContent = '請輸入查詢字'; return; }\n $('se-banner').innerHTML = '';\n if (S.mode === 'graph') { doGraphSearch(q); return; }\n $('se-graphout').style.display = 'none';\n $('se-results').style.display = '';\n $('se-count').textContent = '查詢中…';\n $('se-results').innerHTML = '';\n var url = API_BASE + '/portal/data/search?q=' + encodeURIComponent(q) + '&mode=' + (S.mode === 'semantic' ? 'semantic' : 'keyword');\n fetch(url, { headers: authHeaders() })\n .then(function (r) { return safeJson(r).then(function (d) { return { ok: r.ok, status: r.status, d: d }; }); })\n .then(function (x) {\n if (guard401(x.status)) return;\n if (!x.ok) { $('se-count').innerHTML = '<span class=\"err\">' + esc(x.d.error || ('查詢失敗(HTTP ' + x.status + '')) + '</span>'; return; }\n var d = x.d;\n if (S.mode === 'semantic' && d.mode === 'keyword') {\n // 🔴 2026-08-09 leo:「語義搜尋已經確定是一安裝就提供的功能⋯⋯我沒有不開通這個\n // 功能,是壞了,沒有人會把 bug 美化成沒提供沒開通。」\n // 走到這裡=這台實例的語意搜尋壞了(缺 binding 或向量化失敗),照實說是故障、\n // 是我們的問題,不要求使用者做任何事。文案優先用後端 capability_hint(已是人話,\n // 能分「暫時故障/部署故障」),舊版後端沒有就用底下的通用故障文案。\n var bhint = (d.capability_hint && !/開通|尚未啟用/.test(d.capability_hint))\n ? d.capability_hint\n : '語意搜尋目前故障,先用關鍵字幫你找了下面的結果。這是我們系統的問題,不是你的操作問題,你不需要做任何事,我們會修好它。';\n $('se-banner').innerHTML = '<div class=\"honest\" style=\"margin-top:18px\"><div class=\"h\">語意搜尋目前故障</div><div class=\"b\">' + esc(bhint) + '</div></div>';\n }\n var entries = d.entries || [];\n $('se-count').textContent = '命中 ' + entries.length + ' 筆・模式 ' + searchModeLabel(d.mode || 'keyword') + (d.note ? '・' + d.note : '');\n if (!entries.length) {\n // 空結果不一律怪查詢字:語意模式的空結果,後端 capability_hint 會分\n // 「真的沒命中(換字)」與「索引故障/還沒有資料(不是用戶的問題)」,照實顯示。\n // 降級(mode=keyword)時故障說明已在上方橫幅,這裡不重複。\n var emptyMsg = (d.capability_hint && d.mode === 'semantic')\n ? esc(d.capability_hint)\n : '找不到「' + esc(q) + '」——換個關鍵字試試。';\n $('se-results').innerHTML = '<div class=\"muted\" style=\"padding:30px 10px;text-align:center;grid-column:1/-1\">' + emptyMsg + '</div>';\n return;\n }\n $('se-results').innerHTML = entries.map(function (e) {\n var src = entrySource(e);\n return '<div class=\"kcard\" data-card=\"' + esc(e.id) + '\">' +\n '<div class=\"kt\">' + esc(entryTitle(e)) + '</div>' +\n '<div class=\"ks\">' + esc(entrySnippet(e)) + '</div>' +\n '<div class=\"km\">' +\n '<span class=\"tag\">' + esc(entryTypeLabel(e.entry_type)) + '</span>' +\n '<span class=\"tag green\">' + esc(entryLib(e)) + '</span>' +\n (src ? '<span class=\"dim\" style=\"word-break:break-all\">' + esc(src) + '</span>' : '') +\n '<span class=\"dim mono\" style=\"margin-left:auto\">' + esc(fmtDate(e.created_at)) + '</span></div></div>';\n }).join('');\n })\n .catch(function (e) { $('se-count').innerHTML = '<span class=\"err\">請求失敗:' + esc(friendlyErr(e)) + '</span>'; });\n }\n $('se-results').addEventListener('click', function (ev) {\n var t = ev.target.closest('[data-card]');\n if (t) nav('card', t.getAttribute('data-card'));\n });\n\n // ── AI 檢索過程(Arcrun#44)──\n // leo 原話:「在 AI 搜尋格子應看到我輸入的內容從 graph 找到幾個子庫、從子庫的 index\n // 讀到的內容⋯⋯會看到他的參照原文位置檔名,而不是簡單向量搜尋的結果。」\n // 後端契約見 issue #44answer/sources 之外多一個可選的 retrieval 物件,欄位全部視為\n // 「可能不存在」——舊實例的 workflow 不會回它,缺了要優雅降級(不爆錯、不顯示 undefined)。\n function retrievalTraceHtml(retrieval) {\n if (!retrieval || typeof retrieval !== 'object') return '';\n var route = retrieval.route || '';\n var vectorUsed = retrieval.vector_used;\n var considered = retrieval.libraries_considered;\n var libs = Array.isArray(retrieval.libraries) ? retrieval.libraries : [];\n var idxs = Array.isArray(retrieval.indexes_read) ? retrieval.indexes_read : [];\n var pages = Array.isArray(retrieval.pages_read) ? retrieval.pages_read : [];\n\n var ROUTE_META = {\n graph: { label: '圖譜命中子庫', cls: 'tag green' },\n index: { label: '索引退回選庫', cls: 'tag' },\n all: { label: '全庫讀取(未命中圖譜)', cls: 'tag dim' }\n };\n var rm = ROUTE_META[route];\n var routeTag = rm ? ('<span class=\"' + rm.cls + '\">' + esc(rm.label) + '</span>')\n : (route ? '<span class=\"tag dim\">' + esc(route) + '</span>' : '');\n var vecTag = vectorUsed === false ? '<span class=\"tag green\">🚫 非向量搜尋</span>'\n : (vectorUsed === true ? '<span class=\"tag\">已使用向量搜尋</span>' : '');\n var considerTxt = (typeof considered === 'number')\n ? '<span class=\"dim mono\" style=\"font-size:12.5px\">考慮 ' + considered + ' 個子庫</span>' : '';\n\n var head = (routeTag || vecTag || considerTxt)\n ? ('<div class=\"tracehead\">' + routeTag + vecTag + considerTxt + '</div>') : '';\n\n // 沒有任何細節可展開時,只顯示徽章列,不生一個空的收合框\n if (!libs.length && !idxs.length && !pages.length && route !== 'all') return head;\n\n // 🌳 2026-08-18 leo:「希望以樹狀圖來展示⋯⋯就像現有的 graph search 一樣 render」。\n // 平鋪的 ①②③ 三個區塊資訊都在,但「哪個原文片段是從哪個子庫、經哪段索引敘事讀進來的」\n // 要用戶自己腦補 → 改成一棵樹,層級關係由畫面直接說出來。\n // 樹的**資料**在 retrievalTreeData()(唯一一份),畫法有兩種:markmap(正常)/\n // 巢狀清單(markmap 沒載進來時的退路)。兩者吃同一份資料,不會各自漂移。\n return head + '<details class=\"trace\" open><summary>檢視檢索過程</summary>' +\n '<div class=\"trace-body\"><div class=\"tracetree\" id=\"tracetree\"></div></div></details>';\n }\n\n // 檢索過程 → 一棵樹(markmap 的 IPureNode{ content: HTML 字串, children: [] })。\n // 形狀=leo 畫的那張:搜尋詞 ├ 命中子庫 ├ 讀到的子庫索引敘事 └ 讀入的原文片段。\n function retrievalTreeData(question, r) {\n var libs = Array.isArray(r.libraries) ? r.libraries : [];\n var idxs = Array.isArray(r.indexes_read) ? r.indexes_read : [];\n var pages = Array.isArray(r.pages_read) ? r.pages_read : [];\n var pagesByLib = {}, idxByLib = {}, mounted = {};\n var labels = machineLabelMap(pages);\n pages.forEach(function (p) { var k = p.library || ''; (pagesByLib[k] = pagesByLib[k] || []).push(p); });\n idxs.forEach(function (ix) { var k = ix.library || ''; (idxByLib[k] = idxByLib[k] || []).push(ix); });\n\n function node(content, children, fold) {\n var n = { content: content, children: children || [] };\n if (fold) n.payload = { fold: 1 };\n return n;\n }\n function idxNode(ix) {\n var ents = Array.isArray(ix.top_entities) ? ix.top_entities : [];\n var counts = [];\n if (typeof ix.triplet_count === 'number') counts.push(ix.triplet_count + ' 三元組');\n if (typeof ix.entry_count === 'number') counts.push(ix.entry_count + ' 筆條目');\n // narrative 常常是空字串(ingest 還沒補寫)——不假裝有,改說「索引沒有敘事」並把\n // 這個庫實際被讀到的東西(重點實體/規模)擺出來,讓這一層仍然說得出讀到了什麼。\n var main = ix.narrative\n ? esc(String(ix.narrative).slice(0, 160)) + (String(ix.narrative).length > 160 ? '…' : '')\n : '<span class=\"tt-dim\">(索引沒有敘事)</span>';\n return main +\n (counts.length ? '<br><span class=\"tt-sub\">' + esc(counts.join('・')) + '</span>' : '') +\n (ents.length ? '<br><span class=\"tt-sub\">重點實體:' + esc(ents.slice(0, 3).join('、')) + '</span>' : '');\n }\n function pageNode(p) {\n var c = srcCrumbs(p.source, p.library, p, labels);\n var trail = c.dirs.concat(c.file ? [c.file] : []).join(' ');\n return node('<b>' + esc(p.page || '(無頁名)') + '</b>' +\n (typeof p.chars === 'number' ? ' <span class=\"tt-sub\">' + esc(p.chars) + ' 字</span>' : '') +\n (c.machineLabel\n ? '<br><span class=\"tt-machine\" title=\"' + esc('比對鍵:' + c.machine) + '\">' + esc(c.machineLabel) + '</span>'\n : '<br><span class=\"tt-machine tt-unknown\">未知來源</span>') +\n (trail ? '<br><span class=\"tt-path\">' + esc(trail) + (c.frag ? ' #' + esc(c.frag) : '') + '</span>' : ''), []);\n }\n function libBranch(name, meta) {\n var mine = idxByLib[name] || [];\n var myPages = (pagesByLib[name] || []).map(pageNode);\n var kids;\n if (mine.length) {\n // 原文片段掛在該庫的索引敘事底下(leo 的層級);同一庫有多筆索引時掛第一筆,其餘平列。\n kids = mine.map(function (ix, i) { return node(idxNode(ix), i === 0 ? myPages : []); });\n } else {\n // 沒有索引敘事就不要生一個假的中間層——原文片段直接掛在子庫底下。\n kids = myPages;\n }\n var ents = Array.isArray(meta.matched_entities) ? meta.matched_entities : [];\n var sub = [];\n if (typeof meta.score === 'number') sub.push('score ' + meta.score);\n if (meta.via) sub.push(String(meta.via));\n return node('<b>' + esc(name || '(無名子庫)') + '</b>' +\n (sub.length ? ' <span class=\"tt-sub\">' + esc(sub.join('・')) + '</span>' : '') +\n (ents.length ? '<br><span class=\"tt-sub\">命中實體:' + esc(ents.slice(0, 3).join('、')) + '</span>' : ''), kids);\n }\n\n var branches = [];\n libs.forEach(function (l) { var n = l.library || ''; mounted[n] = 1; branches.push(libBranch(n, l)); });\n // 有讀原文、但沒出現在 libraries[] 的子庫(route=all、或後端沒回 libraries)也要長出來,不能吞掉\n Object.keys(pagesByLib).forEach(function (n) {\n if (mounted[n]) return;\n mounted[n] = 1;\n branches.push(libBranch(n, { via: r.route === 'all' ? '全庫讀取' : '' }));\n });\n // 其餘只被讀了索引、沒被選用的子庫:收在一個預設收合的節點底下(它們確實被讀過,不隱瞞,\n // 但也不能讓 7 個沒選用的庫把真正命中的那條路徑擠掉)\n var rest = idxs.filter(function (ix) { return !mounted[ix.library || '']; });\n if (rest.length) {\n branches.push(node('<span class=\"tt-dim\">考慮過但沒讀原文(' + rest.length + ' 個子庫)</span>',\n rest.map(function (ix) {\n return node('<span class=\"tt-dim\">' + esc(ix.library || '') + '</span><br>' + idxNode(ix), []);\n }), true));\n }\n if (!branches.length) {\n branches.push(node('<span class=\"tt-dim\">' +\n (r.route === 'all' ? '沒有子庫命中圖譜實體,已改讀全庫作答。' : '這次沒有回報任何子庫。') +\n '</span>', []));\n }\n return node('<b>' + esc(question || '(無搜尋詞)') + '</b>' +\n '<br><span class=\"tt-sub\">' + esc(SEARCH_ROUTE_LABEL[r.route] || r.route || '檢索') +\n (typeof r.libraries_considered === 'number' ? '・考慮 ' + r.libraries_considered + ' 個子庫' : '') +\n '</span>', branches);\n }\n var SEARCH_ROUTE_LABEL = { graph: '圖譜命中子庫', index: '索引退回選庫', all: '全庫讀取' };\n\n // 🌲 renderTree — **這個軟體裡唯一的樹狀渲染入口**D97leo 2026-08-18)。\n // leo 原話:「所有樹狀表達都可以用 markmap 類似的現成機制 render,不要自己做一個,\n // 在整個軟體內都一致⋯⋯markmap 可以展開,自己做的那套不行,如果它不能展開、\n // 不能顯示下一層,就只有展示用途,還不如用現成成熟的。」\n // ⇒ 之後的資料夾樹、任何階層呈現,一律呼叫這支,不准再長第二套樹狀渲染。\n // 要餵的資料形狀就是 markmap 的 IPureNode\n // { content: HTML 字串, children: [], payload?: { fold: 1 } }。\n //\n // 這一支要同時服務三個入口(同一份 render,三種 root):\n // ① 同步庫總覽(四層):總庫 → 機器 → 資料夾 → 子資料夾/檔案\n // ② 單一資料夾樹:資料夾 → 子資料夾/檔案(節點右邊掛「同步/總數」)\n // ③ 檢索過程樹(本檔 retrievalTreeData):搜尋詞 → 子庫 → 索引敘事 → 原文片段\n // 三者的差別只在**資料怎麼組**,畫法沒有第二套。深度沒有上限(markmap 是遞迴佈局,\n // 每一層都有自己的圓圈可以摺疊),節點內容是 HTML ⇒ 機器/資料夾/檔案/未知\n // 可以長得不一樣(見上方 .tt-machine.tt-folder.tt-file.tt-unknown)。\n //\n // 🔴 拿不到值的那一層要顯示成「未知」,不准拿別的東西頂替。\n // 現況:機器那一層在資料上是空的(collector 沒有存 hostnamemachine id),\n // 所以檢索過程的出處麵包屑標「機器:未記錄」;同步庫總覽同理,\n // 資料補上之後那個節點會自然長出真名,畫面這端不需要再改。\n // 正路=markmap(互動摺疊/縮放/平移都是它自帶的);它沒載進來時退成巢狀清單\n // ——寧可醜也不要空白,而且兩條路吃同一份樹資料,不會各自漂移。\n //\n // 🌿 線型與顏色(leo 2026-08-18 第三輪):\n // 「它的線型可以改成類似 terminal tree 那樣往右、往下展開的 L 型折線,\n // 線的色彩不要花花綠綠,就是看起來就像他在電腦上看到的那樣?」\n // ⇒ 目標是**檔案總管/`tree` 指令**那個樣子:直角折線 + 單色。\n // 改的是「markmap 怎麼畫線」,**不是換掉 markmap**(D97 不要自造輪胎)——\n // 佈局、摺疊、縮放平移全部還是它的,我們只接手最後那條 path 的 `d`。\n function renderTree(box, data) {\n // 同一個框重畫時,先把上一次的線型觀察器關掉(不關=觀察器越疊越多)\n if (box.__ttLinkObserver) { try { box.__ttLinkObserver.disconnect(); } catch (e0) {} box.__ttLinkObserver = null; }\n // markmap 要求每個節點都有 children 陣列;少一個就在它內部炸掉\n // (實測:葉子寫成 { content: 'x' } 而不是 { content: 'x', children: [] }\n // 整棵樹會變成一個空框,console 才看得到 \"Cannot read properties of undefined\n // (reading 'map')\")。這裡先補齊,呼叫端不必記得這條規矩。\n data = normalizeTreeNode(data);\n var mk = window.markmap && window.markmap.Markmap;\n if (!mk) { box.classList.remove('tracetree'); box.innerHTML = treeListHtml(data); return false; }\n try {\n // 🔴 先把框高定下來、再把 svg 的 width/height **當屬性**寫上去,然後才 create。\n // 不寫屬性的話 svg 的寬高只有 CSS 的 100%,而 d3-zoom 取預設縮放範圍時會去讀\n // svg.width.baseVal.value ⇒ 百分比在那個時間點解不出絕對長度 ⇒ Chrome 丟\n // NotSupportedError: Could not resolve relative length(實測 2026-08-18 在\n // youlin stage 的 console 抓到;畫面看起來正常,所以只看畫面驗不出來)。\n // 上限分兩級:答案只命中一兩個子庫時樹很矮(240 就夠,不要留一大片空白);\n // 命中七八個子庫時樹會很高,卡在 430 會被 autoFit 縮到看不清字\n // 2026-08-18 stage 實看:14 片原文擠在 430 的框裡,字小到讀不出來)。\n // 手機那條沿用 CSS 的 340,不要讓一張圖吃掉整個畫面。\n var maxH = (window.innerWidth && window.innerWidth < 700) ? 340 : 620;\n var h = Math.max(240, Math.min(maxH, visibleLeaves(data) * 52 + 84));\n box.style.height = h + 'px';\n box.innerHTML = '<svg></svg><div class=\"tt-hint\">可捲動縮放・拖曳平移・點圓圈收合</div>';\n var svgEl = box.querySelector('svg');\n svgEl.setAttribute('width', String(box.clientWidth || 800));\n svgEl.setAttribute('height', String(h));\n var mm = mk.create(svgEl, {\n // maxWidthspacingHorizontal 壓小=樹變窄=autoFit 後的縮放比變大=字看得清楚。\n // (實測:maxWidth 300/間距 90 時整棵樹 1097px 寬,塞進 842px 的框只剩 0.71 倍。)\n autoFit: true, duration: 0, fitRatio: 0.94, maxWidth: 215,\n spacingVertical: 16, spacingHorizontal: 52, paddingX: 8, maxInitialScale: 1.15,\n // 單色(leo:「線的色彩不要花花綠綠」)。markmap 的 color 同時餵三個東西:\n // 連線、節點底線、摺疊圓圈(收起來時圓圈用它填實)——一律同一支淡墨,\n // 節點之間的差別交給 HTML 的 .tt-machine.tt-folder.tt-file 去表達,不靠線的顏色。\n color: function () { return treeLineColor(); },\n // 粗細也拉成定值:預設是 1+3/2^depth(越淺越粗),terminal tree 的線是一樣粗的。\n lineWidth: function () { return 1.2; }\n }, data);\n // 🔴 曲線 → L 型折線。放在 create 之後、fit 之前都可以(它只改 `d`,不改版面尺寸)。\n box.__ttLinkObserver = elbowifyLinks(svgEl);\n // 框高是**算**出來的(見上面 h),不去量 DOM:實測(2026-08-18Chrome)兩種量法\n // 都不可靠——`<g>.getBBox()` 同一頁一次回 1097×183、一次回 0;這版 `mm.state.rect`\n // 從頭到尾是 {0,0,0,0}。量到 0 就會把框壓扁成一條。算的比量的穩。\n // fit 之後再用 rAF 補一次:呼叫端在版面還沒算完就叫我畫時,svg 量到 0 會把樹縮到畫面外\n // (實測:把 renderTree 直接寫在 <script> 裡跑就會這樣)。\n if (mm && mm.fit) { mm.fit(); requestAnimationFrame(function () { try { mm.fit(); } catch (e3) {} }); }\n return true;\n } catch (e) {\n box.classList.remove('tracetree');\n box.innerHTML = '<div class=\"dim\" style=\"font-size:12.5px;margin-bottom:6px\">樹狀圖畫不出來(' + esc(friendlyErr(e)) + '),改用文字層級:</div>' + treeListHtml(data);\n return false;\n }\n }\n // 樹的線/圓圈/底線用的那一支色。取自 --ink-rgb(同一份色票,不另外寫死一個色碼),\n // 拿不到就退回本專案的墨色 43,39,35——退路存在是因為這支會在 demo 頁/測試裡被單獨叫到。\n function treeLineColor() {\n var rgb = '';\n try { rgb = getComputedStyle(document.documentElement).getPropertyValue('--ink-rgb').trim(); } catch (e) {}\n return 'rgba(' + (rgb || '43,39,35') + ',.42)';\n }\n // 一條連線的 L 型折線:從父節點右緣先往右一小段(TREE_ELBOW_INDENT),\n // 再垂直走到子節點那一列,最後往右接進子節點左緣——就是 `tree` 指令的 `├──`。\n // 同一個父節點的所有子節點共用同一條垂直幹線(起點 x 相同 ⇒ 轉折 x 也相同)。\n // 只有 M/L,沒有曲線指令:這同時是 elbowifyLinks 判斷「這條已經改過了」的依據。\n function elbowPath(sx, sy, tx, ty) {\n var INDENT = 12; // 垂直幹線離父節點右緣多遠(px,未縮放座標)\n var r = function (v) { return Math.round(v * 100) / 100; };\n // 同一列(父子等高)=一條直線就好,不要硬折出一個看不見的直角\n if (Math.abs(ty - sy) < 0.5) return 'M' + r(sx) + ',' + r(sy) + 'L' + r(tx) + ',' + r(ty);\n var mx = Math.min(sx + INDENT, tx); // 框窄到轉折會超過子節點時,把幹線收回來\n return 'M' + r(sx) + ',' + r(sy) + 'L' + r(mx) + ',' + r(sy) + 'L' + r(mx) + ',' + r(ty) + 'L' + r(tx) + ',' + r(ty);\n }\n // markmap 0.18 的連線產生器是 linkHorizontal(bumpX)**寫死在 bundle 裡、沒有開放選項**\n // options 只有 color/lineWidth/spacing…,沒有線型)。它每次 render 都會把最終的 `d`\n // 寫在 path.markmap-link 上 ⇒ 我們在那個屬性上接手,把三次貝茲換成折線。\n // 🔴 為什麼用 MutationObserver 而不是 setTimeoutrAFmarkmap 寫 `d` 是走 d3 transition\n // 什麼時候落地取決於 duration 與 frame 排程——猜時機遲早會漏(摺疊/展開會再寫一次)。\n // 觀察屬性變化就不必猜。改寫本身也會觸發觀察,但改完的 `d` 只有 M/L,第二輪直接跳過,\n // 所以不會無限迴圈。\n // `d` 長這樣:`M sx,sy C mx,sy mx,ty tx,ty`bumpX)⇒ 頭兩個數字是起點、末兩個是終點,\n // 中間的控制點不用管。回傳 null=這條不用動(已經是折線/格式不認得)。\n function elbowFromCurve(d) {\n if (!d || d.indexOf('C') < 0) return null; // 沒有 C=已經是我們畫的折線(只有 M/L\n var n = d.match(/-?\\d+(?:\\.\\d+)?(?:e-?\\d+)?/g);\n if (!n || n.length < 4) return null;\n return elbowPath(+n[0], +n[1], +n[n.length - 2], +n[n.length - 1]);\n }\n function elbowifyLinks(svgEl) {\n var apply = function () {\n var ps = svgEl.querySelectorAll('path.markmap-link');\n for (var i = 0; i < ps.length; i++) {\n var next = elbowFromCurve(ps[i].getAttribute('d'));\n if (next) ps[i].setAttribute('d', next);\n }\n };\n apply();\n if (typeof MutationObserver !== 'function') return null;\n var ob = new MutationObserver(apply);\n ob.observe(svgEl, { subtree: true, childList: true, attributes: true, attributeFilter: ['d'] });\n return ob;\n }\n function mountRetrievalTree(question, retrieval) {\n var box = $('tracetree');\n if (!box || !retrieval || typeof retrieval !== 'object') return;\n var data;\n try { data = retrievalTreeData(question, retrieval); }\n catch (e) { box.innerHTML = '<div class=\"dim\" style=\"font-size:13.5px;padding:10px\">檢索過程畫不出來:' + esc(friendlyErr(e)) + '</div>'; return; }\n renderTree(box, data);\n }\n function normalizeTreeNode(n) {\n var kids = (n && n.children) || [];\n var out = { content: (n && n.content) || '', children: [] };\n if (n && n.payload) out.payload = n.payload;\n for (var i = 0; i < kids.length; i++) out.children.push(normalizeTreeNode(kids[i]));\n return out;\n }\n // 這棵樹**一開始**會佔幾列=有幾個「展開狀態下的葉子」(收合的節點只算一列)。\n function visibleLeaves(n) {\n if (!n.children || !n.children.length) return 1;\n if (n.payload && n.payload.fold) return 1;\n var s = 0;\n for (var i = 0; i < n.children.length; i++) s += visibleLeaves(n.children[i]);\n return s;\n }\n function treeListHtml(n) {\n return '<ul class=\"tracelist\"><li>' + n.content +\n (n.children && n.children.length ? n.children.map(treeListHtml).join('') : '') + '</li></ul>';\n }\n\n // kb:// 來源 → 麵包屑(資料夾可以有很多層,全部拆開)。\n // leo 2026-08-18:「應該是讓他可以去本機資料夾找到原文,那應該帶上原機器的編號、\n // 資料夾名稱、檔名的麵包屑。如果是要讓他快速 locate 原文,不用再開搜尋框了。」\n // 🔴 machine 這一層現在**永遠是 null**:資料上傳時根本沒有記錄來源機器\n // collector 全 repo 沒有 hostnamemachine iddevice id),\n // 所以畫面上誠實標「未記錄」,不掰一個看起來像機器編號的字串。\n // 同一台機器(machine 比對鍵相同)在一次回答裡只該有**一個**顯示名。\n // 實況(youlin stage 2026-08-18 實測):同一把 `youlinhsieh@Leo-MBA` 有兩種 label——\n // 改名前灌的那筆 label 就等於 ID 本身,改名後那筆是「教育部 Leo 的 Mac」。\n // 照單全收會在畫面上長成**兩台機器**,而它們是同一台。\n // 判準:label 與比對鍵不同 = 有人真的取過名字 ⇒ 用它;都沒取過就退回顯示 ID。\n // (比對鍵永遠掛在 title 上,所以「它到底是哪一台」查得到。)\n function machineLabelMap(items) {\n var map = {};\n (items || []).forEach(function (it) {\n var k = it && it.machine ? String(it.machine) : '';\n if (!k) return;\n var l = it && it.machine_label ? String(it.machine_label) : '';\n if (!map[k] || (map[k] === k && l && l !== k)) map[k] = l || k;\n });\n return map;\n }\n function srcCrumbs(source, library, src, labels) {\n // machine =比對鍵(穩定,不隨改名變);machine_label =顯示名(使用者可改)。\n // 🔴 判準是「有沒有值」,不是「有沒有這個欄位」:舊資料**根本沒有這兩格**\n // (資料端刻意不 backfill、不猜),空字串也一律當沒有 ⇒ 顯示「未知來源」。\n var mk = (src && src.machine) ? String(src.machine) : '';\n var ml = (src && src.machine_label) ? String(src.machine_label) : '';\n if (mk && labels && labels[mk]) ml = labels[mk]; // 同一台機器全篇同一個名字\n var out = { machine: mk || null, machineLabel: ml || mk || null,\n library: library || '', dirs: [], file: '', frag: '', path: '', raw: String(source || '') };\n var p = srcLocalPath(source); // kb:// → 去 scheme、去錨點的相對路徑\n if (!p) return out;\n out.path = p;\n var m = /#([^#]*)$/.exec(String(source));\n if (m) out.frag = m[1];\n var seg = p.split('/').filter(Boolean);\n out.file = seg.pop() || '';\n out.dirs = seg;\n return out;\n }\n\n // ── AI 問答(portal-demo-suite)──\n // 設計哲學:AI 檢索=用戶手動搜尋同一套——同 session token、同 /portal/data/* enforce 面,\n // AI 只代查再作答;答案附 sourcesmodepage),點 page 帶回搜尋框讓用戶自己驗證。\n $('ai-go').addEventListener('click', doAsk);\n $('ai-q').addEventListener('keydown', function (ev) { if (ev.key === 'Enter') doAsk(); });\n function doAsk() {\n var q = $('ai-q').value.trim();\n if (!q) { toast('請先輸入問題'); return; }\n $('ai-go').disabled = true;\n $('ai-out').innerHTML = '<div class=\"muted\" style=\"margin-top:12px\">AI 查閱知識庫中…</div>';\n fetch(API_BASE + '/portal/data/chat?question=' + encodeURIComponent(q), { headers: authHeaders() })\n .then(function (r) { return safeJson(r).then(function (d) { return { ok: r.ok, status: r.status, d: d }; }); })\n .then(function (x) {\n $('ai-go').disabled = false;\n if (guard401(x.status)) return;\n if (!x.ok) {\n // 404=此實例未安裝問答 workflow(server 誠實回報,前端不假裝有 AI\n $('ai-out').innerHTML = '<div class=\"honest\" style=\"margin-top:12px\"><div class=\"h\">問不到</div><div class=\"b\">' + esc(x.d.error || ('問答失敗(HTTP ' + x.status + '')) + '</div></div>';\n return;\n }\n var srcs = x.d.sources || [];\n // answer 純文字渲染、保留換行(pre-wrapesc,不走 markdown、防 XSS\n var html = '<div class=\"panel\" style=\"margin-top:12px\">' +\n '<div style=\"white-space:pre-wrap;font-size:16px;line-height:1.85;word-break:break-word\">' + esc(x.d.answer || 'AI 沒有給出答案)') + '</div>';\n // 檢索過程(retrieval 整段可能不存在——舊實例的 workflow 不回它,見上方函式註解)\n html += retrievalTraceHtml(x.d.retrieval);\n if (srcs.length) {\n // 出處=「去你自己的資料夾把原檔找出來」的地址,不是「再搜一次」的入口\n // leo 2026-08-18:「如果是要讓他快速 locate 原文,不用再開搜尋框了。」)\n html += '<div style=\"margin-top:14px;font-size:13px;letter-spacing:.1em;color:rgba(var(--ink-rgb),.5)\">出處(在你的資料夾裡的位置)</div>' +\n '<div style=\"margin-top:7px;display:flex;flex-direction:column;gap:6px\">' +\n (function () { var lb = machineLabelMap(srcs); return srcs.map(function (s) { return srcCrumbRowHtml(s, lb); }).join(''); })() + '</div>';\n }\n html += '</div>';\n $('ai-out').innerHTML = html;\n mountRetrievalTree(q, x.d.retrieval);\n })\n .catch(function (e) { $('ai-go').disabled = false; $('ai-out').innerHTML = '<div class=\"err\" style=\"margin-top:12px\">請求失敗:' + esc(friendlyErr(e)) + '</div>'; });\n }\n // 一列出處=一條「機器 › 子庫 › 資料夾(可多層)› 檔名 › 片段」的麵包屑。\n // 資料夾那幾層一直都在(kb:// 後面就是相對路徑,多層的),只是以前整條當一個字串印出來;\n // 機器那一層則是**真的沒有被存下來**,畫面上標「未記錄」而不是湊一個。\n function srcCrumbRowHtml(s, labels) {\n var page = (s && (s.page || s.page_name)) || '';\n var src = (s && s.source) || '';\n var mode = (s && s.mode) || '';\n var isMode = !!SEARCH_MODE_LABEL[mode]; // keyword/semantic/graph=檢索模式\n var c = srcCrumbs(src, isMode ? '' : mode, s, labels); // 其餘情況下 mode 放的是子庫名\n var href = src ? srcHref(src) : '';\n var head = '<div class=\"crumbs\">' +\n (c.machineLabel\n // 顯示名是使用者可改的,比對鍵才是穩定的那個 ⇒ 真值掛在 title 上,兩個都看得到\n ? '<span class=\"crumb\" title=\"' + esc('這台機器的比對鍵:' + (c.machine || '')) + '\">' + esc(c.machineLabel) + '</span>'\n : '<span class=\"crumb unknown\" title=\"這筆資料沒有記錄來源機器(舊資料在收檔時還沒有這一格),所以看不出原稿在誰的電腦上。\">未知來源</span>');\n if (c.library) head += '<span class=\"sep\"></span><span class=\"crumb\">' + esc(c.library) + '</span>';\n c.dirs.forEach(function (d) { head += '<span class=\"sep\"></span><span class=\"crumb\">' + esc(d) + '</span>'; });\n if (c.file) head += '<span class=\"sep\"></span><span class=\"crumb file\">' + esc(c.file) + '</span>';\n if (!c.path) head += '<span class=\"sep\"></span><span class=\"crumb file\">' + esc(page || '(無頁名)') + '</span>';\n if (c.frag) head += '<span class=\"tag dim\">片段 #' + esc(c.frag) + '</span>';\n if (isMode) head += '<span class=\"tag\">' + esc(searchModeLabel(mode)) + '</span>';\n head += '</div>';\n var foot = '<div class=\"crumbfoot\">';\n if (c.path) {\n foot += '<button class=\"btn3\" data-copypath=\"' + esc(c.path) + '\">複製路徑</button>' +\n '<span class=\"p\">' + esc(c.path) + '</span>';\n } else if (src) {\n // 非 kb:// 的來源(例如 gitea:)沒有本機路徑可給——照實印原字串,不假裝拆得出資料夾\n foot += '<span class=\"p\">' + esc(src) + '</span>';\n }\n if (c.path && page) foot += '<span class=\"p tt-dim\">頁:' + esc(page) + '</span>';\n if (href) foot += '<a href=\"' + esc(href) + '\" target=\"_blank\" rel=\"noopener\" style=\"color:var(--amber);font-size:12.5px\">來源 ↗</a>';\n foot += '</div>';\n return '<div class=\"crumbrow\">' + head + foot + '</div>';\n }\n $('ai-out').addEventListener('click', function (ev) {\n var t = ev.target.closest('[data-copypath]');\n if (!t) return;\n var p = t.getAttribute('data-copypath');\n if (!p) return;\n if (navigator.clipboard && navigator.clipboard.writeText) {\n navigator.clipboard.writeText(p).then(function () { toast('已複製路徑:' + p); },\n function () { toast('複製失敗,請手動選取路徑'); });\n } else {\n toast('這個瀏覽器不給複製,請手動選取路徑');\n }\n });\n\n // ── graph 模式(D-4 粗閘:無權者按鈕根本不顯示;就算 curl 直打 API 也是 403)──\n function doGraphSearch(name) {\n $('se-results').style.display = 'none';\n $('se-graphout').style.display = '';\n $('se-count').textContent = '查詢關聯中…';\n renderGraphEmpty('查詢關聯中…');\n fetch(API_BASE + '/portal/data/graph/neighbors/' + encodeURIComponent(name), { headers: authHeaders() })\n .then(function (r) { return safeJson(r).then(function (d) { return { ok: r.ok, status: r.status, d: d }; }); })\n .then(function (x) {\n if (guard401(x.status)) return;\n if (!x.ok) { $('se-count').innerHTML = '<span class=\"err\">' + esc(x.d.error || ('關聯查詢失敗(HTTP ' + x.status + '')) + '</span>'; renderGraphEmpty(x.d.error || '關聯查詢失敗'); return; }\n var neighbors = x.d.neighbors || [];\n var edges = x.d.edges || [];\n // 形狀相容(Arcrun#57 家族):plugin 版 neighbors 是字串、workflow 版是\n // { node, predicate, from, depth } 物件——不正規化會渲染成 [object Object]。\n var names = neighbors.map(function (nb) {\n if (typeof nb === 'string') return nb;\n return (nb && (nb.node || nb.name)) || '';\n }).filter(Boolean);\n // workflow 版 edges 恆空,但 neighbor 物件本身就是一條邊(from --predicate--> node)→ 導出。\n if (!edges.length) {\n edges = neighbors.filter(function (nb) { return nb && typeof nb === 'object' && nb.predicate; })\n .map(function (nb) { return { subject: nb.from || name, predicate: nb.predicate, object: nb.node }; });\n }\n $('se-count').textContent = '節點「' + name + '」・鄰居 ' + names.length + '・關聯 ' + edges.length;\n if (!names.length) { renderGraphEmpty('尚無關聯資料——這個名字還沒有連進知識圖譜。'); return; }\n renderGraph(name, names.slice(0, 10));\n $('gr-edges').innerHTML = edges.slice(0, 12).map(function (t) {\n // 大小寫不敏感比對(graph 查詢已正規化:搜 rag 會命中節點 RAG\n var other = String(t.subject).toLowerCase() === String(name).toLowerCase() ? t.object : t.subject;\n return '<div class=\"nbrow\" data-gnode=\"' + esc(other) + '\">' +\n '<span class=\"tag green\" style=\"flex:none\">' + esc(t.predicate || '關聯') + '</span>' +\n '<span style=\"word-break:break-word\">' + esc(other) + '</span>' +\n '<span style=\"margin-left:auto;color:rgba(var(--amber-rgb),.6);flex:none\"></span></div>';\n }).join('');\n })\n .catch(function (e) { $('se-count').innerHTML = '<span class=\"err\">關聯服務不可達:' + esc(friendlyErr(e)) + '</span>'; renderGraphEmpty('關聯服務不可達'); });\n }\n function renderGraphEmpty(msg) {\n $('gr-box').innerHTML = '<div class=\"graphbox\" style=\"display:grid;place-items:center;height:160px\"><span class=\"muted\" style=\"font-size:14px;padding:0 20px;text-align:center\">' + esc(msg) + '</span></div>';\n $('gr-edges').innerHTML = '';\n }\n function renderGraph(center, nodes) {\n var n = nodes.length || 1;\n var lines = '', chips = '';\n for (var i = 0; i < n; i++) {\n var a = (-90 + i * (360 / n)) * Math.PI / 180;\n var x = 50 + 39 * Math.cos(a), y = 50 + 37 * Math.sin(a);\n lines += '<line x1=\"50\" y1=\"50\" x2=\"' + x.toFixed(2) + '\" y2=\"' + y.toFixed(2) + '\" stroke=\"rgba(var(--ok-rgb),.3)\" stroke-width=\"1\" vector-effect=\"non-scaling-stroke\" stroke-dasharray=\"4 4\"/>';\n chips += '<div class=\"gnode\" style=\"left:' + x.toFixed(2) + '%;top:' + y.toFixed(2) + '%\" data-gnode=\"' + esc(nodes[i]) + '\">' + esc(nodes[i]) + '</div>';\n }\n var shortCenter = center.length > 16 ? center.slice(0, 16) + '…' : center;\n $('gr-box').innerHTML = '<div class=\"graphbox\">' +\n '<svg viewBox=\"0 0 100 100\" preserveAspectRatio=\"none\" style=\"position:absolute;inset:0;width:100%;height:100%\">' + lines + '</svg>' +\n '<div class=\"gcenter\"><span>' + esc(shortCenter) + '</span></div>' + chips +\n '<div style=\"position:absolute;right:12px;bottom:10px;font-size:11.5px;color:rgba(var(--ink-rgb),.35)\">╌ 知識圖譜鄰居(點節點展開)</div></div>';\n }\n document.addEventListener('click', function (ev) {\n var t = ev.target.closest('[data-gnode]');\n if (!t) return;\n var name = t.getAttribute('data-gnode');\n $('se-q').value = name;\n doGraphSearch(name);\n });\n\n // ── 卡片詳頁 ──\n function loadCard() {\n if (!S.cardId) { $('cd-main').innerHTML = '<div class=\"muted\">沒有指定卡片——從「搜尋」點一張進來。</div>'; return; }\n $('cd-main').innerHTML = '<div class=\"muted\">載入中…</div>';\n fetch(API_BASE + '/portal/data/entries/' + encodeURIComponent(S.cardId), { headers: authHeaders() })\n .then(function (r) { return safeJson(r).then(function (d) { return { ok: r.ok, status: r.status, d: d }; }); })\n .then(function (x) {\n if (guard401(x.status)) return;\n if (!x.ok || !x.d.entry) { $('cd-main').innerHTML = '<div class=\"err\">' + esc(x.d.error || '讀不到這張卡片') + '</div>'; return; }\n var e = x.d.entry;\n var src = entrySource(e);\n $('cd-main').innerHTML = '<div class=\"cardtitle\">' + esc(entryTitle(e)) + '</div>' +\n '<div style=\"display:flex;gap:10px;align-items:center;margin-top:12px;font-size:13.5px;flex-wrap:wrap\">' +\n '<span class=\"tag\">' + esc(entryTypeLabel(e.entry_type)) + '</span>' +\n '<span class=\"tag green\">' + esc(entryLib(e)) + '</span>' +\n (e.page_name ? '<span class=\"tag dim\">' + esc(e.page_name) + '</span>' : '') +\n '<span class=\"muted mono\">' + esc(fmtDateTime(e.created_at)) + '</span></div>' +\n '<div class=\"md\">' + mdRender(e.content || '(此條目沒有內文)') + '</div>' +\n (src\n ? (function () {\n var href = srcHref(src);\n var body = href\n ? '<a class=\"mono\" style=\"font-size:14px;color:var(--amber);word-break:break-all\" href=\"' + esc(href) + '\" target=\"_blank\" rel=\"noopener\">' + esc(src) + ' ↗</a>'\n : '<span class=\"mono\" style=\"font-size:14px;color:var(--amber);word-break:break-all\">' + esc(src) + '</span>';\n return '<div class=\"srcline\"><span style=\"font-size:13px;letter-spacing:.14em;color:rgba(var(--ink-rgb),.5);flex:none\">來源回溯</span>' + body + '</div>';\n })()\n : '');\n })\n .catch(function (er) { $('cd-main').innerHTML = '<div class=\"err\">請求失敗:' + esc(friendlyErr(er)) + '</div>'; });\n }\n\n // ── 總圖(Arcrun#39 藏書地圖 GUI 切片)──\n // 全庫三元組一張網:/portal/data/graph/overview → 手刻力導向佈局(demo 量級,零外部套件)。\n // 佈局用固定種子的 PRNG=同一庫每次長一樣(客戶重整不會跳位)。\n function jumpToGraph(name) {\n S.mode = 'graph';\n document.querySelectorAll('.modebtn').forEach(function (x) { x.classList.toggle('on', x.getAttribute('data-mode') === 'graph'); });\n nav('search');\n $('se-q').value = name;\n doGraphSearch(name);\n }\n // 讀不到就明說「讀不到」——標題列**絕不**留著 0 或舊數字(Arcrun#100leo 看到\n // 「0 個實體・0 條關聯」以為要去上傳文件,其實庫裡有 1854 條,只是這支讀失敗了)。\n function mapUnavailable(html) {\n $('map-meta').textContent = '讀不到';\n $('map-box').innerHTML = '<div class=\"err\" style=\"padding:30px 10px\">' + html + '</div>';\n }\n function loadMap() {\n $('map-meta').textContent = '';\n $('map-box').innerHTML = '<div class=\"muted\" style=\"padding:30px 10px\">載入總圖中…</div>';\n $('map-md-link').innerHTML = SOURCE_WEB_BASE\n ? '<a href=\"' + esc(SOURCE_WEB_BASE + '/system-dev/wiki/00-MAP.md') + '\" target=\"_blank\" rel=\"noopener\" style=\"color:var(--amber)\">00-MAP.md ↗</a>'\n : '存在知識庫的 00-MAP.md';\n fetch(API_BASE + '/portal/data/graph/overview', { headers: authHeaders() })\n .then(function (r) { return safeJson(r).then(function (d) { return { ok: r.ok, status: r.status, d: d }; }); })\n .then(function (x) {\n if (guard401(x.status)) return;\n if (!x.ok) { mapUnavailable(esc(x.d.error || ('總圖載入失敗(HTTP ' + x.status + ''))); return; }\n // Arcrun#100:「0」只准在後端確認過真的是 0 的時候出現。\n // 形狀不對 → 讀不到(不是空庫);nodes 為空但 empty_confirmed 不成立 → 讀不到。\n if (!Array.isArray(x.d.nodes) || !Array.isArray(x.d.edges)) {\n mapUnavailable('總圖回應格式不對——沒有拿到關聯資料。這不代表知識庫是空的。');\n return;\n }\n var nodes = x.d.nodes, edges = x.d.edges;\n var total = typeof x.d.triplets_total === 'number' ? x.d.triplets_total : null;\n if (!nodes.length && x.d.empty_confirmed !== true) {\n mapUnavailable(x.d.empty_reason === 'scope_mismatch'\n ? '讀不到你這個帳號的關聯資料——知識庫裡有三元組'\n + (total ? '(本帳號範圍算到 ' + total.toLocaleString() + ' 條)' : '')\n + ',但這張圖一條都抽不出來。<br>'\n + '<b>這不是「還沒有關聯」,不用去上傳文件</b>;比較像資料的歸屬範圍對不上,請通知管理員。'\n : '讀不到知識庫的關聯資料,無法確認庫裡有沒有關聯。<br>'\n + '<b>這不是「還沒有關聯」,不用去上傳文件</b>——是這次讀取失敗,請稍後重整或通知管理員。');\n return;\n }\n $('map-meta').textContent = nodes.length + ' 個實體・' + edges.length + ' 條關聯'\n + (total !== null && x.d.truncated ? '(全庫共 ' + total.toLocaleString() + ' 條,已達單次上限)' : x.d.truncated ? '・已達上限截斷' : '');\n if (!nodes.length) { $('map-box').innerHTML = '<div class=\"muted\" style=\"padding:30px 10px\">知識庫還沒有任何關聯——上傳文件後 AI 會自動織網。</div>'; return; }\n renderMap(nodes, edges);\n })\n .catch(function (e) { mapUnavailable('請求失敗:' + esc(friendlyErr(e))); });\n }\n function renderMap(nodes, edges) {\n var N = nodes.length;\n var idx = {};\n nodes.forEach(function (n, i) { idx[n.name] = i; });\n var el = [];\n edges.forEach(function (e) {\n var a = idx[e.subject], b = idx[e.object];\n if (a == null || b == null || a === b) return;\n el.push([a, b, e.predicate || '']);\n });\n // 固定種子 PRNGmulberry32):確定性佈局\n var seed = 42;\n function rnd() {\n seed = (seed + 0x6D2B79F5) | 0;\n var t = Math.imul(seed ^ (seed >>> 15), 1 | seed);\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n }\n var W = 1000, H = Math.max(480, Math.min(760, 200 + N * 14));\n var px = [], py = [];\n for (var i = 0; i < N; i++) {\n var ang = 2 * Math.PI * i / N;\n var rad = Math.min(W, H) * (0.22 + 0.2 * rnd());\n px.push(W / 2 + rad * Math.cos(ang));\n py.push(H / 2 + rad * Math.sin(ang) * 0.75);\n }\n // 力導向:斥力(全對)+彈簧(邊)+向心,260 輪退火\n var K = Math.max(75, Math.sqrt(W * H / Math.max(N, 1)) * 0.9);\n for (var it = 0; it < 260; it++) {\n var cool = Math.max(0.06, 1 - it / 260);\n var fx = [], fy = [];\n for (var a1 = 0; a1 < N; a1++) { fx.push(0); fy.push(0); }\n for (var a2 = 0; a2 < N; a2++) {\n for (var b2 = a2 + 1; b2 < N; b2++) {\n var dx = px[a2] - px[b2], dy = py[a2] - py[b2];\n var d2 = dx * dx + dy * dy + 0.01;\n var f = Math.min(28, (K * K) / d2 * 2.2);\n var d = Math.sqrt(d2);\n fx[a2] += dx / d * f; fy[a2] += dy / d * f;\n fx[b2] -= dx / d * f; fy[b2] -= dy / d * f;\n }\n }\n el.forEach(function (e) {\n var dx = px[e[0]] - px[e[1]], dy = py[e[0]] - py[e[1]];\n var d = Math.sqrt(dx * dx + dy * dy) + 0.01;\n var f = (d - K) * 0.045;\n fx[e[0]] -= dx / d * f; fy[e[0]] -= dy / d * f;\n fx[e[1]] += dx / d * f; fy[e[1]] += dy / d * f;\n });\n for (var m = 0; m < N; m++) {\n fx[m] += (W / 2 - px[m]) * 0.012;\n fy[m] += (H / 2 - py[m]) * 0.012;\n px[m] += Math.max(-14, Math.min(14, fx[m])) * cool;\n py[m] += Math.max(-14, Math.min(14, fy[m])) * cool;\n }\n }\n // 視窗貼合\n var minX = 1e9, maxX = -1e9, minY = 1e9, maxY = -1e9;\n for (var q = 0; q < N; q++) {\n minX = Math.min(minX, px[q]); maxX = Math.max(maxX, px[q]);\n minY = Math.min(minY, py[q]); maxY = Math.max(maxY, py[q]);\n }\n var PAD = 70;\n var vb = (minX - PAD) + ' ' + (minY - PAD) + ' ' + (maxX - minX + PAD * 2) + ' ' + (maxY - minY + PAD * 2);\n var maxDeg = 1;\n nodes.forEach(function (n) { maxDeg = Math.max(maxDeg, n.degree || 1); });\n var svg = '<svg viewBox=\"' + vb + '\" preserveAspectRatio=\"xMidYMid meet\">';\n el.forEach(function (e) {\n svg += '<line class=\"mapedge\" x1=\"' + px[e[0]].toFixed(1) + '\" y1=\"' + py[e[0]].toFixed(1) +\n '\" x2=\"' + px[e[1]].toFixed(1) + '\" y2=\"' + py[e[1]].toFixed(1) + '\"><title>' +\n esc(nodes[e[0]].name + ' —' + (e[2] || '關聯') + '→ ' + nodes[e[1]].name) + '</title></line>';\n });\n nodes.forEach(function (n, i2) {\n var deg = n.degree || 1;\n var r = 9 + Math.sqrt(deg) * 5;\n var hub = deg >= Math.max(3, maxDeg * 0.6) ? ' hub' : '';\n svg += '<g class=\"mapnode' + hub + '\" data-mapnode=\"' + esc(n.name) + '\">' +\n '<circle cx=\"' + px[i2].toFixed(1) + '\" cy=\"' + py[i2].toFixed(1) + '\" r=\"' + r.toFixed(1) + '\"><title>' + esc(n.name + '・' + deg + ' 條關聯') + '</title></circle>' +\n '<text x=\"' + px[i2].toFixed(1) + '\" y=\"' + (py[i2] + r + 15).toFixed(1) + '\" text-anchor=\"middle\">' + esc(n.name.length > 14 ? n.name.slice(0, 14) + '…' : n.name) + '</text></g>';\n });\n svg += '</svg>';\n $('map-box').innerHTML = '<div class=\"mapbox\">' + svg +\n '<div style=\"position:absolute;right:12px;bottom:10px;font-size:11.5px;color:rgba(var(--ink-rgb),.35)\">╌ 知識庫總圖(點節點看鄰居)</div></div>';\n }\n document.addEventListener('click', function (ev) {\n var t = ev.target.closest('[data-mapnode]');\n if (!t) return;\n jumpToGraph(t.getAttribute('data-mapnode'));\n });\n\n // ── 工作流(唯讀)──\n function loadWorkflows() {\n $('wf-list').innerHTML = '<div class=\"muted\">載入中…</div>';\n fetch(API_BASE + '/portal/data/workflows', { headers: authHeaders() })\n .then(function (r) { return safeJson(r).then(function (d) { return { ok: r.ok, status: r.status, d: d }; }); })\n .then(function (x) {\n if (guard401(x.status)) return;\n if (!x.ok) { $('wf-list').innerHTML = '<div class=\"err\">' + esc(x.d.error || ('讀取失敗(HTTP ' + x.status + '')) + '</div>'; return; }\n var wfs = x.d.workflows || [];\n if (!wfs.length) { $('wf-list').innerHTML = '<div class=\"muted\" style=\"padding:20px 4px\">目前沒有任何工作流。</div>'; return; }\n $('wf-list').innerHTML = wfs.map(function (w) {\n var lastHtml = '<span class=\"dim\">尚無執行紀錄</span>';\n if (w.last_execution) {\n var v = w.last_execution.verdict || '';\n var cls = v === 'success' ? 'ok' : (v === 'failed' ? 'err' : 'muted');\n lastHtml = '<span class=\"' + cls + '\">' + esc(v || '(無 verdict') + '</span> <span class=\"dim mono\">' + esc(fmtDateTime(Number(w.last_execution.timestamp))) + '</span>';\n }\n return '<div class=\"card-item\">' +\n '<div style=\"display:flex;align-items:baseline;gap:10px;flex-wrap:wrap\">' +\n '<span class=\"serif\" style=\"font-size:17px;font-weight:600\">' + esc(w.name) + '</span>' +\n (w.cron_expr ? '<span class=\"tag dim mono\">' + esc(w.cron_expr) + '</span>' : '') +\n '<span style=\"margin-left:auto;font-size:13.5px\">' + lastHtml + '</span></div>' +\n (w.description ? '<div style=\"margin-top:8px;font-size:14.5px;line-height:1.65;color:rgba(var(--ink-rgb),.65)\">' + esc(w.description) + '</div>' : '<div class=\"dim\" style=\"margin-top:8px;font-size:13.5px\">(沒有描述)</div>') +\n '</div>';\n }).join('');\n })\n .catch(function (e) { $('wf-list').innerHTML = '<div class=\"err\">請求失敗:' + esc(friendlyErr(e)) + '</div>'; });\n }\n\n // ── Leo/Arcrun#82 App 系統 v0Portal 泛用 loaderK5)──\n //\n // 這是本卷唯一改動 Portal 原始碼的地方,且只改這一次——此後每裝一個新 App,\n // 「App 界面」磚塊格與「App 市集」已安裝清單自動多一格、點進去有畫面,這個檔案\n // 不需要再被碰(K5 驗收)。安裝/卸載走 /apps/install、DELETE /portal/data/apps/:id\n // 這裡只讀已安裝清單、渲染畫面、把使用者的動作轉成一支泛用端點的呼叫\n // (K6:前端永遠拿不到任何金鑰)。\n //\n // Arcrun#152:渲染目標從舊的側欄/tabbar 插槽(nav-apps-slot/tab-apps-slot,已隨四頁簽\n // 改版移除)換成 renderLaunchGrid()renderMarketInstalled()——同一份 fetch 結果餵給\n // 兩處呈現(K2 單一真相源:清單只讀一次,不是兩份各自 fetch)。\n\n function greetingText() {\n var h = new Date().getHours();\n var g = h < 5 ? '夜深了' : h < 12 ? '早安' : h < 18 ? '午安' : '晚安';\n var name = (S.profile && S.profile.display_name) || '';\n return name ? (g + '' + name) : g;\n }\n\n // ── IconArcrun#152):描邊式 inline SVG,不用 emoji ─────────────────────\n // 為什麼換掉 emoji:① emoji 是各作業系統自帶的彩色點陣字形,WindowsmacOS\n // Android 各長一套 ⇒ 設計稿保證不了;② 它吃不到 CIS 的 --ink--amber ⇒\n // 切深色模式時不會跟著變色。字形本體是 <body> 開頭那份 <symbol> sprite\n // 這裡只負責「挑哪一顆」。\n\n // 後端 app-system.ts 的 generateIcon() 會依 App 名字決定性發一顆 emoji,清單是\n // ICON_SET = ['📄','🗒️','🧩','📌','🔧','📦','🗂️','✅','💡','🔔','📊','🧭']。\n // 下面一對一換成同樣 12 顆描邊字形,**順序必須跟它一致**,同一個 App 才不會換臉。\n var APP_GLYPHS = ['doc', 'note', 'layers', 'pin', 'wrench', 'box', 'folder', 'check', 'bulb', 'bell', 'chart', 'compass'];\n var EMOJI_GLYPH = {\n '📄': 'doc', '🗒️': 'note', '🗒': 'note', '📝': 'note', '🧩': 'layers', '📌': 'pin',\n '🔧': 'wrench', '🛠️': 'wrench', '📦': 'box', '🗂️': 'folder', '🗂': 'folder', '📁': 'folder',\n '✅': 'check', '💡': 'bulb', '🔔': 'bell', '📊': 'chart', '📈': 'chart',\n '🧭': 'compass', '🔍': 'search', '🕸️': 'graph', '🏠': 'apps'\n };\n\n // 遇到不認得的 iconApp 宣告裡自己填的 emoji)就用跟後端同一條雜湊挑一顆——\n // 至少保證「同一個 App 每次都是同一顆」,不會每次重整就換臉。\n function appGlyph(icon, name) {\n if (icon && EMOJI_GLYPH[icon]) return EMOJI_GLYPH[icon];\n var seed = String(icon || name || '');\n var h = 0;\n for (var i = 0; i < seed.length; i++) h = (h * 31 + seed.charCodeAt(i)) >>> 0;\n return APP_GLYPHS[h % APP_GLYPHS.length];\n }\n\n // 白名單:只吐 sprite 裡真的有的 id ⇒ 這段 innerHTML 不可能被外部字串汙染\n // (後端來的 a.icon 一律先經過 appGlyph() 收斂成這張表裡的值)。\n var GLYPHS = APP_GLYPHS.concat(['apps', 'market', 'settings', 'dev', 'search', 'graph', 'plus']);\n function iconSvg(id) {\n return '<svg aria-hidden=\"true\" focusable=\"false\"><use href=\"#i-' + (GLYPHS.indexOf(id) >= 0 ? id : 'doc') + '\"/></svg>';\n }\n\n // 「App 界面」九宮格:知識庫搜尋/知識總圖是內建能力(本來就不是 app-system 安裝出來的\n // 那份清單),其餘磚塊來自已安裝 App;「加裝 App」磚塊固定放最後,導去「App 市集」。\n function renderLaunchGrid(apps) {\n var grid = $('launch-grid');\n if (!grid) return;\n var tiles = [{ gl: 'search', label: '知識庫搜尋', dn: 'search' }];\n if (S.profile && S.profile.graph_allowed) tiles.push({ gl: 'graph', label: '知識總圖', dn: 'map' });\n apps.forEach(function (a) {\n tiles.push({ gl: appGlyph(a.icon, a.name || a.id), label: a.name || a.id, dn: 'app:' + a.id, accent: true });\n });\n grid.innerHTML = tiles.map(function (t) {\n return '<div class=\"apptile' + (t.accent ? ' accent' : '') + '\" data-nav=\"' + esc(t.dn) + '\" title=\"' + esc(t.label) + '\">' +\n '<div class=\"ic\">' + iconSvg(t.gl) + '</div><div class=\"lbl\">' + esc(t.label) + '</div></div>';\n }).join('') + '<div class=\"apptile add\" data-nav=\"market\" title=\"App 市集\"><div class=\"ic\">' + iconSvg('plus') + '</div><div class=\"lbl muted\">加裝 App</div></div>';\n var g = $('lh-greet'); if (g) g.textContent = greetingText();\n var sub = $('lh-sub'); if (sub) sub.textContent = tiles.length + ' 個 App 可用・在「App 市集」找更多';\n }\n\n // 「App 市集」已安裝清單:知識庫搜尋(+知識總圖,若開放)標「內建」,其餘是真正\n // 走 /apps/install 裝進來的 App(K2:同一份資料,不是市集自己另存一份清單)。\n function renderMarketInstalled(apps) {\n var list = $('market-installed');\n if (!list) return;\n var items = [{ dn: 'search', name: '知識庫搜尋', gl: 'search', builtin: true, desc: 'RAG 語意搜尋,附出處與檢索過程' }];\n if (S.profile && S.profile.graph_allowed) items.push({ dn: 'map', name: '知識總圖', gl: 'graph', builtin: true, desc: '全庫三元組關聯圖' });\n apps.forEach(function (a) {\n items.push({ dn: 'app:' + a.id, name: a.name || a.id, gl: appGlyph(a.icon, a.name || a.id), builtin: false, desc: a.has_ui ? '自帶畫面的 App' : '工作流型 App(系統預設畫面)' });\n });\n var canManage = !!(S.profile && S.profile.role === 'admin');\n list.innerHTML = items.map(function (it) {\n // 卸載鍵只給裝上去的 App(內建能力沒得卸),且只給 admin——與後端\n // DELETE /portal/data/apps/:id 同一道閘。非 admin 看不到鍵,不是看到一顆按了才失敗的鍵。\n var removeBtn = (!it.builtin && canManage)\n ? '<button class=\"btn2 warn mk-remove\" data-app=\"' + esc(it.dn.slice(4)) + '\" data-name=\"' + esc(it.name) + '\">移除</button>'\n : '';\n return '<div class=\"card-item\" data-nav=\"' + esc(it.dn) + '\" style=\"cursor:pointer;display:flex;gap:14px;align-items:center\">' +\n '<div class=\"apptile-ic-sm\">' + iconSvg(it.gl) + '</div>' +\n '<div style=\"flex:1;min-width:0\">' +\n '<div style=\"display:flex;justify-content:space-between;gap:8px;align-items:baseline\"><span style=\"font-weight:600\">' + esc(it.name) + '</span><span class=\"tag green\">已安裝</span></div>' +\n '<div class=\"dim\" style=\"font-size:13px;margin-top:2px\">' + esc(it.desc) + (it.builtin ? ' · 內建' : '') + '</div>' +\n '</div>' + removeBtn + '</div>';\n }).join('');\n // stopPropagation:這顆鍵住在一張整張可點的卡片裡,不擋的話按「移除」會先被\n // 卡片的 data-nav 接走,變成「點了移除卻跳進那個 App」。\n list.querySelectorAll('.mk-remove').forEach(function (btn) {\n btn.addEventListener('click', function (ev) {\n ev.stopPropagation();\n removeAppFromMarket(btn.getAttribute('data-app'), btn.getAttribute('data-name'), btn);\n });\n });\n }\n\n // ── 「可安裝」清單(Arcrun#152)─────────────────────────────────────────────\n //\n // leo 2026-08-25:「**應該要讓每個人都可以顯示,按一下安裝**」。\n // 在這之前,portal 這一格寫的是「尚未接市集後端」,而真正裝一個 App 的路是\n // clone repo → 跑 node → 手動代換兩個佔位符 → curl POST 帶 API key。\n //\n // 清單來源=`/portal/data/apps/catalog`(隨引擎出貨的目錄,見 lib/app-catalog.ts)。\n // 🔴 前端只拿得到 id/name/summary/version/author/installed——**宣告本體、實例座標、\n // 任何金鑰都不會下發**(K6 同一條線)。\n function renderMarketCatalog(entries, canInstall) {\n var box = $('market-catalog');\n if (!box) return;\n if (!entries || entries.length === 0) {\n box.innerHTML = '<div class=\"honest\"><div class=\"h\">這一版沒有收錄可安裝的 App</div>' +\n '<div class=\"b\">市集內容跟著你這台實例的版本走。更新到新版本之後,這裡會多出東西。</div></div>';\n return;\n }\n box.innerHTML = entries.map(function (e) {\n var btn = e.installed\n ? '<button class=\"btn2 mk-install\" disabled data-app=\"' + esc(e.id) + '\">已安裝</button>'\n : (canInstall\n ? '<button class=\"btn2 mk-install\" data-app=\"' + esc(e.id) + '\" data-name=\"' + esc(e.name) + '\">安裝</button>'\n : '<button class=\"btn2\" disabled title=\"安裝 App 會影響這台實例的所有人,所以要管理員來裝\">要管理員才能裝</button>');\n return '<div class=\"card-item\" style=\"display:flex;gap:14px;align-items:center\">' +\n '<div class=\"apptile-ic-sm\">' + iconSvg(appGlyph(e.icon, e.name || e.id)) + '</div>' +\n '<div style=\"flex:1;min-width:0\">' +\n '<div style=\"display:flex;gap:8px;align-items:baseline;flex-wrap:wrap\"><span style=\"font-weight:600\">' + esc(e.name) + '</span>' +\n '<span class=\"tag dim mono\">v' + esc(e.version) + '</span><span class=\"dim\" style=\"font-size:12.5px\">' + esc(e.author) + '</span></div>' +\n '<div class=\"dim\" style=\"font-size:13px;margin-top:3px\">' + esc(e.summary) + '</div>' +\n '<div class=\"mk-msg\" style=\"font-size:13px;margin-top:8px;line-height:1.65\"></div>' +\n '</div>' + btn + '</div>';\n }).join('');\n box.querySelectorAll('.mk-install:not([disabled])').forEach(function (btn) {\n btn.addEventListener('click', function () {\n installAppFromMarket(btn.getAttribute('data-app'), btn.getAttribute('data-name'), btn);\n });\n });\n }\n\n /**\n * 把後端回的失敗攤成三句人話:**哪一步、為什麼、下一步做什麼**。\n * leo 的驗收條件之一——靜默失敗或丟一個錯誤代碼都算沒過。\n */\n function installFailureText(status, body) {\n var step = (body && body.step) || '';\n var why = (body && body.error) || ('伺服器回了 HTTP ' + status + ',沒有說明原因');\n var next = (body && body.hint) || '再按一次試試;一直失敗就把這段訊息回報給管理者。';\n return (step ? '卡在「' + step + '」:' : '') + why + '\\n下一步:' + next;\n }\n\n function installAppFromMarket(id, name, btn) {\n var card = btn.closest('.card-item');\n var msg = card ? card.querySelector('.mk-msg') : null;\n var original = btn.textContent;\n btn.disabled = true;\n btn.textContent = '安裝中…';\n if (msg) { msg.className = 'mk-msg dim'; msg.textContent = '正在把「' + name + '」裝到這台實例上…'; }\n fetch(API_BASE + '/portal/data/apps/catalog/' + encodeURIComponent(id) + '/install', {\n method: 'POST', headers: authHeaders(),\n })\n .then(function (r) { return safeJson(r).then(function (d) { return { ok: r.ok, status: r.status, d: d }; }); })\n .then(function (x) {\n if (guard401(x.status)) return;\n if (!x.ok) {\n btn.disabled = false;\n btn.textContent = original;\n if (msg) { msg.className = 'mk-msg err'; msg.style.whiteSpace = 'pre-line'; msg.textContent = '安裝沒有完成。' + installFailureText(x.status, x.d); }\n return;\n }\n btn.textContent = '已安裝';\n if (msg) { msg.className = 'mk-msg'; msg.style.whiteSpace = 'normal'; msg.innerHTML = '<span class=\"tag green\">裝好了</span> 回「App 界面」就看得到它。'; }\n toast('「' + name + '」已安裝');\n renderAppsNav(); // 九宮格與兩份清單一起重畫(同一份資料,不是各自 fetch)\n })\n .catch(function (e) {\n btn.disabled = false;\n btn.textContent = original;\n if (msg) { msg.className = 'mk-msg err'; msg.style.whiteSpace = 'pre-line'; msg.textContent = '安裝沒有完成。卡在「送出安裝要求」:' + friendlyErr(e) + '\\n下一步:確認網路,再按一次安裝。'; }\n });\n }\n\n /**\n * 兩段式確認:第一下把按鈕變成「再按一次確認」,第二下才真的做。\n *\n * 🔴 為什麼不用瀏覽器內建的 `confirm()`(原本就是那樣寫的,2026-08-25 實測撞到):\n * 有些內嵌/受管的瀏覽器環境**直接讓 confirm() 回 false 且不顯示任何東西**\n * ⇒ 使用者按了「移除」,畫面一動也不動,也沒有任何錯誤 ⇒ **靜默失敗**,\n * 而那正是本票明講不准出現的狀態。兩段式確認是同一道防呆,但它畫在頁面上,\n * 不依賴宿主環境願不願意開對話框。\n * 逾時自動復原(免得一顆「確認移除」永遠留在畫面上等著被誤觸)。窗口 30 秒——\n * 實測 6 秒太短:讀完提示再移到按鈕就過期了,那會變成「按兩次都只是重新武裝」,\n * 而使用者看到的是「按了兩下還是沒反應」——又是一種靜默失敗。\n */\n function armRemoveButton(btn, name, idleLabel) {\n btn.dataset.armed = '1';\n btn.dataset.idleLabel = idleLabel;\n btn.textContent = '確認移除';\n toast('再按一次「確認移除」:「' + name + '」的工作流會被撤掉,資料型別與資料本身保留。');\n clearTimeout(Number(btn.dataset.armTimer || 0));\n btn.dataset.armTimer = String(setTimeout(function () {\n btn.dataset.armed = '';\n btn.textContent = btn.dataset.idleLabel || idleLabel;\n }, 30000));\n }\n function disarmRemoveButton(btn) {\n clearTimeout(Number(btn.dataset.armTimer || 0));\n btn.dataset.armed = '';\n }\n\n function removeAppFromMarket(id, name, btn) {\n if (btn.dataset.armed !== '1') { armRemoveButton(btn, name, '移除'); return; }\n disarmRemoveButton(btn);\n btn.disabled = true;\n btn.textContent = '移除中…';\n fetch(API_BASE + '/portal/data/apps/' + encodeURIComponent(id), { method: 'DELETE', headers: authHeaders() })\n .then(function (r) { return safeJson(r).then(function (d) { return { ok: r.ok, status: r.status, d: d }; }); })\n .then(function (x) {\n if (guard401(x.status)) return;\n if (!x.ok) { btn.disabled = false; btn.textContent = '移除'; toast((x.d && x.d.error) || '移除失敗'); return; }\n toast('「' + name + '」已移除');\n renderAppsNav();\n })\n .catch(function (e) { btn.disabled = false; btn.textContent = '移除'; toast('請求失敗:' + friendlyErr(e)); });\n }\n\n // 讀不到就不顯示,不擋主流程(壞了不致命,同 setup checklist 慣例)。\n function renderAppsNav() {\n fetch(API_BASE + '/portal/data/apps', { headers: authHeaders() })\n .then(function (r) { return safeJson(r).then(function (d) { return { ok: r.ok, status: r.status, d: d }; }); })\n .then(function (x) {\n if (guard401(x.status)) return;\n if (!x.ok) return;\n var apps = (x.d && x.d.apps) || [];\n renderLaunchGrid(apps);\n renderMarketInstalled(apps);\n renderMarketCatalogFromServer(apps);\n // 非同步補回來的清單可能晚於 showView() 跑完——若使用者當下正停在某個 App 頁,\n // 重新套一次 highlight(不重新整理內容,只補樣式)。\n var v = currentRoute().view;\n if (v === 'app' || v === 'launcher' || v === 'market') showView(v);\n })\n .catch(function () { /* 讀不到清單=這個實例可能還沒裝任何 App,不是錯誤 */ });\n }\n\n // 目錄與已安裝清單是兩支端點(一個是「這版有哪些貨」,一個是「這台裝了什麼」)——\n // 但畫面上是同一頁的上下兩段,所以一起重畫,不讓使用者看到半新半舊。\n // 讀不到目錄就老實說讀不到(不是畫成「沒有可安裝的 App」——那是 #100 同一條)。\n function renderMarketCatalogFromServer(installedApps) {\n if (!$('market-catalog')) return;\n // 🔴「裝了沒」只認**一份**已安裝清單——就是上面那支 /portal/data/apps 的結果(K2)。\n // 目錄端點自己也會回一個 installed 旗標(給別的呼叫端用),但這裡不採信它:\n // 兩支端點是兩次獨立的 KV 讀取,而 KV 是最終一致的\n // ⇒ 剛按完「移除」的那一瞬間,兩邊可能一邊已更新、一邊還是舊的\n // ⇒ 畫面就會出現「已安裝清單裡沒有它,可安裝那格卻還寫著已安裝」。\n // 實際撞到過(2026-08-25 youlin)。同一份資料只讀一次,這種矛盾就不存在。\n var installedIds = {};\n (installedApps || []).forEach(function (a) { installedIds[a.id] = true; });\n fetch(API_BASE + '/portal/data/apps/catalog', { headers: authHeaders() })\n .then(function (r) { return safeJson(r).then(function (d) { return { ok: r.ok, status: r.status, d: d }; }); })\n .then(function (x) {\n if (guard401(x.status)) return;\n if (!x.ok) {\n $('market-catalog').innerHTML = '<div class=\"honest\"><div class=\"h\">讀不到可安裝清單</div>' +\n '<div class=\"b\">' + esc((x.d && x.d.error) || ('伺服器回了 HTTP ' + x.status)) +\n '<br>這不表示沒有 App 可裝,是這次沒問到。重新整理頁面再試一次。</div></div>';\n return;\n }\n var entries = ((x.d && x.d.apps) || []).map(function (e) {\n return {\n id: e.id, name: e.name, icon: e.icon, summary: e.summary,\n version: e.version, author: e.author,\n installed: !!installedIds[e.id], // ← 只認上面那一份,不認端點自己回的旗標\n };\n });\n renderMarketCatalog(entries, !!(x.d && x.d.can_install));\n })\n .catch(function (e) {\n $('market-catalog').innerHTML = '<div class=\"honest\"><div class=\"h\">讀不到可安裝清單</div>' +\n '<div class=\"b\">' + esc(friendlyErr(e)) + '<br>確認網路之後重新整理頁面。</div></div>';\n });\n }\n\n // 泛用動作端點(K6):App 的畫面/系統預設畫面都透過這支呼叫後端,前端沒有第二條路。\n function callAppAction(appId, action, payload) {\n return fetch(API_BASE + '/portal/data/apps/' + encodeURIComponent(appId) + '/action', {\n method: 'POST',\n headers: Object.assign({ 'Content-Type': 'application/json' }, authHeaders()),\n body: JSON.stringify({ action: action, payload: payload || {} }),\n }).then(function (r) { return safeJson(r).then(function (d) { return { ok: r.ok, status: r.status, d: d }; }); });\n }\n\n function loadApp() {\n var id = S.appId;\n var body = $('app-body');\n if (!id) { body.innerHTML = '<div class=\"err\">沒有指定 App</div>'; return; }\n $('app-title').textContent = id;\n $('app-remove-btn').classList.add('hide');\n body.innerHTML = '<div class=\"muted\">載入中…</div>';\n fetch(API_BASE + '/portal/data/apps/' + encodeURIComponent(id), { headers: authHeaders() })\n .then(function (r) { return safeJson(r).then(function (d) { return { ok: r.ok, status: r.status, d: d }; }); })\n .then(function (x) {\n if (guard401(x.status)) return;\n if (!x.ok) { body.innerHTML = '<div class=\"err\">' + esc((x.d && x.d.error) || '讀取失敗') + '</div>'; return; }\n renderAppView(x.d);\n })\n .catch(function (e) { body.innerHTML = '<div class=\"err\">請求失敗:' + esc(friendlyErr(e)) + '</div>'; });\n }\n\n // ── App 畫面的樣式隔離(Arcrun#152leo 2026-08-24 在 youlin stage 實測撞到)────────\n //\n // 舊做法是 `mount.innerHTML = app.ui_html`App 的 HTML **連同它的 `<style>`** 被貼進\n // Portal 這份文件裡。而 App 的畫面通常本來就是一份完整的 HTML 檔,帶著\n // :root { --bg: #0e0f12; --text: #eceef1; ... }\n // html, body { background: var(--bg); color: var(--text); }\n // 這種**針對整份文件**寫的規則 ⇒ 一點開 App,整個 Portal 就被它接管。\n // 實測(本機以 youlin 上那份真的「筆記」App 重現):`body` 的背景由紙紋變成\n // rgb(14,15,18)、文字色被翻成 rgb(236,238,241) ⇒ 側欄各分頁**按得到但看不見**。\n // 而且 `<style>` 會一直留在 `#v-app` 裡(切頁只是 toggle `.on` class,不是移除節點)\n // ⇒ **切回其他頁面畫面還是黑的**,只能重新整理才救得回來。\n //\n // 🔴 這不是「那個 App 的 CSS 寫壞了」,是協定允許任何 App 弄壞整個 Portal\n // ⇒ 未來市集上任何第三方 App 都能做到同一件事。所以修在 loader(K5 唯一那次改動),\n // 不是修在某個 App 身上。\n //\n // 修法=把 App 掛進 **Shadow DOM**shadow 內的樣式規則對外部文件不生效,這是瀏覽器\n // 層的保證,不靠「App 作者夠小心」也不靠我們的字串改寫夠周全。\n //\n // 🔴 **這一段只解掉了 leo 原則的後半(「不要影響整體」)。**\n // 當時還宣稱「把 CIS 樣式表複製一份進 shadow root ⇒ App 就跟著整體走」——\n // **那句話是錯的,leo 08-24 打開筆記 App 就抓到了**:那份副本裡的是\n // `--ink`/`--amber`,而 App 引用的是它自己 `:root` 裡的 `--accent`/`--bg`\n // 兩套沒有交集 ⇒ 複製進去對它一點作用都沒有。前半(「先採用整體的 styles」)\n // 整個沒做。真正的通道在下面「掛載協定 v0.2」那一段(cascade layers)。\n //\n // ⚠️ 誠實標明這個修法**不涵蓋**什麼:Shadow DOM 只隔離樣式與 DOM 查詢,App 的\n // `<script>` 仍然跑在 Portal 的 JS 環境裡(拿得到 `window``localStorage`)。\n // 要連腳本一起隔離得走 iframe sandbox postMessage,那是協定層的下一步(見 #82)。\n\n // ── 掛載協定 v0.2:兩種樣式模式(Arcrun#152#82leo 2026-08-24 拍板)──────────\n //\n // leo 逐字:「**App 應該可以選跟隨全局,或是堅持用自己的,但現在看起來是沒有連上全局\n // 的通道。如果用自己的,全局要給它多大的畫布也是全局決定的⋯⋯應該整個右側邊欄都是它的。**」\n //\n // 上一輪(Shadow DOM 隔離)只做到「App 弄不壞外面」。leo 08-24 打開筆記 App 之後\n // 連說四句——不吃全局的 style/按鈕藍色黑色/寬度字體不對——**每一句都是同一件事**:\n // 那條「跟隨全局」的通道從來沒有存在過。Portal 有 `--ink`/`--amber` 一套 token\n // 筆記 App 有 `--text`/`--panel`/`--accent` 另一套,**兩套沒有任何交集**\n // ⇒ 它不是被覆蓋,是從來沒接上。CIS 樣式表複製進 shadow 也沒用,App 引用的是自己那組。\n //\n // inherit**預設**)= 跟隨全局:配色、明暗主題、字體、畫布都由 Portal 決定,\n // App 只管自己的版面(間距、格線、它自己的 class)。\n // own = 堅持用自己的:App 自己畫,Portal 只保證它弄不壞外面。\n //\n // 🔴 **畫布大小兩種模式都由全局決定**——那是 `#app-ui-mount` 的 CSS(外部文件的規則\n // 對 host 元素勝過 shadow 內的 `:host`),App 在 shadow 裡寫什麼都改不動。\n //\n // 「跟隨全局」怎麼機械地成立(不是靠 App 作者自律)= **CSS Cascade Layers**\n // @layer arcrun-base, app, arcrun; ← 後宣告的層贏,且**與 specificity 無關**\n // · `arcrun-base`(最低):裸元素的預設版面(padding/圓角/大小)——App 可以蓋掉\n // · `app`(中):App 自己的規則——版面歸它\n // · `arcrun`(最高):Portal 的 CIS 樣式表 + 全局色票/字體——**配色歸 Portal**\n // 同一層內仍照 specificity ⇒ App 想要不一樣的按鈕,用 Portal 自己的 class\n // `.btn` / `.btn3`,它們在最高層且 specificity 較高)**而不是自己的顏色**。\n // 這就是那條「連上全局的通道」:它有名字、可查、而且不做也會自動吃到。\n var APP_DOC_SELECTORS = { ':root': 1, 'html': 1, 'body': 1 };\n\n // 走訪一份樣式表的每一條規則(含 @media / @layer / @supports 內部)。\n // 由後往前跑,因為 `inherit` 模式要邊走邊 deleteRule。\n function walkStyleRules(parent, fn) {\n var rules = parent.cssRules;\n if (!rules) return;\n for (var i = rules.length - 1; i >= 0; i--) {\n var r = rules[i];\n if (typeof r.selectorText === 'string') fn(parent, i, r);\n if (r.cssRules && r.cssRules.length) walkStyleRules(r, fn);\n }\n }\n\n // App 的 `<style>` 幾乎都是針對整份文件寫的(`:root` / `html` / `body`)。這兩種模式\n // 對它們的處置**刻意不同**,而那個差別就是「跟不跟隨全局」的實體:\n //\n // own → 改指向 `:host`(=App 自己那個容器)⇒ App 照它原本設計的樣子呈現,\n // 只是被關在自己的盒子裡。(這是上一輪就有的行為,一個字沒改。)\n // inherit → **整條丟掉**。文件層的長相在這個模式下屬於 Portal,不屬於 App\n // 丟掉之後 App 那組 `--accent`/`--bg` 不存在了,全局的 `--ink`/`--amber`\n // 沿繼承鏈穿過 shadow 邊界進來 ⇒ 連明暗主題切換都自動跟著走。\n // ⚠️ 誠實標明代價:App 若把 `--gap: 12px` 這種**非配色**的變數也寫在 `:root`\n // 在 inherit 模式下會一起消失。要留住它們的 App 宣告 `own`。\n // 兩種模式都只動「純文件層」那幾條;`body .card {…}` 這種後代選擇器一律改寫成\n // `:host .card`(那是 App 的版面,兩種模式都該留著)。\n function applyAppStyleMode(sheet, inherit) {\n walkStyleRules(sheet, function (parent, index, r) {\n var parts = r.selectorText.split(',');\n var kept = [];\n for (var i = 0; i < parts.length; i++) {\n var p = parts[i].trim();\n if (APP_DOC_SELECTORS[p]) { if (!inherit) kept.push(':host'); continue; }\n kept.push(p.replace(/^(?::root|html|body)(?=[\\s>+~])/, ':host'));\n }\n if (!kept.length) { try { parent.deleteRule(index); } catch (e) { /* 刪不掉不致命 */ } return; }\n var next = kept.join(', ');\n // 改寫失敗不致命(shadow 邊界已經把外洩擋住了),跳過即可。\n if (next !== r.selectorText) { try { r.selectorText = next; } catch (e) { /* noop */ } }\n });\n }\n\n // 最低層:裸元素的預設版面。**只放版面、不放顏色**——顏色在最高層,這樣 App 才「改得動\n // 自己的版面、改不動整體的配色」。沒有任何樣式的 App 放進來也長得像個 Arcrun 畫面。\n var APP_BASE_CSS = [\n ':host{display:block;width:100%;box-sizing:border-box;padding:20px}',\n '*{box-sizing:border-box}',\n 'button{padding:11px 16px;border-radius:10px;border:1px solid transparent;cursor:pointer}',\n 'input,textarea,select{padding:12px 14px;border-radius:10px;border:1px solid transparent;max-width:100%}',\n 'textarea{width:100%}',\n 'h1{font-size:23px;letter-spacing:.06em}h2{font-size:19px}h3{font-size:17px}',\n 'h1,h2,h3,h4,h5,h6{margin:1.1em 0 .5em;font-weight:600}',\n 'table{border-collapse:collapse;width:100%}th,td{padding:8px 10px;text-align:left}',\n 'pre{overflow:auto;padding:12px;border-radius:10px}',\n 'img,svg,video,canvas{max-width:100%}',\n ].join('');\n\n // 最高層:**這一層就是「全局」**。配色、明暗、字體、行高全在這裡,App 蓋不掉\n // (層比 specificity 大)。所有值一律用 CIS token ⇒ 切深色/淺色時整個 App 跟著變。\n var APP_INHERIT_CSS = [\n ':host{background:transparent;color:var(--ink);',\n 'font-family:-apple-system,\"IBM Plex Sans\",\"PingFang TC\",\"Noto Sans TC\",\"Microsoft JhengHei\",system-ui,sans-serif;',\n 'font-size:16px;line-height:1.6;-webkit-font-smoothing:antialiased}',\n 'button{background:var(--amber);color:#FDFCFB;border-color:transparent;font-family:inherit;font-size:15px;font-weight:600}',\n 'button:disabled{opacity:.45;cursor:default}',\n 'input,textarea,select{background:rgba(var(--ink-rgb),.05);color:var(--ink);',\n 'border-color:rgba(var(--ink-rgb),.2);font-family:inherit;font-size:16px}',\n '::placeholder{color:rgba(var(--ink-rgb),.35)}',\n 'input:focus,textarea:focus,select:focus{outline:2px solid rgba(var(--amber-rgb),.5);outline-offset:1px}',\n 'a{color:var(--amber)}',\n 'h1,h2,h3,h4,h5,h6{color:var(--ink);font-family:inherit}',\n 'hr{border:none;border-top:1px solid rgba(var(--ink-rgb),.12)}',\n 'th,td{border-bottom:1px solid rgba(var(--ink-rgb),.12);color:var(--ink)}',\n 'code,pre,kbd,samp{font-family:ui-monospace,Menlo,monospace;background:rgba(var(--ink-rgb),.06);color:var(--ink)}',\n ].join('');\n\n function styleEl(css) {\n var s = document.createElement('style');\n s.textContent = css;\n return s;\n }\n\n // App 的 script 幾乎都用 `document.getElementById` 抓自己的節點,而那些節點現在住在\n // shadow 裡——真 `document` 找不到它們(也不該找得到,那正是隔離的意思)。\n // 這個替身只把三支查詢方法改指向 App 自己的 shadow root,其餘一律轉給真 document。\n function appDocumentFor(root) {\n if (typeof Proxy !== 'function') return document; // 極舊瀏覽器:退回原行為,不擋人用\n return new Proxy(document, {\n get: function (target, key) {\n if (key === 'getElementById') return function (id) { return root.getElementById(id); };\n if (key === 'querySelector') return function (sel) { return root.querySelector(sel); };\n if (key === 'querySelectorAll') return function (sel) { return root.querySelectorAll(sel); };\n var v = target[key];\n return typeof v === 'function' ? v.bind(target) : v;\n },\n set: function (target, key, value) { target[key] = value; return true; },\n });\n }\n\n function mountAppUi(host, html, style) {\n var inherit = style !== 'own'; // 沒宣告=跟隨全局(舊 App 也一併被修好,見 detailApp\n var root = host.attachShadow({ mode: 'open' });\n var cis = $('portal-cis');\n // ① 層序先宣告——`@layer` 的順序由**第一次出現**決定,所以這一行必須在任何規則之前。\n // 後面三疊(arcrun-base / app / arcrun)都指名進層,誰蓋得掉誰就不再看 specificity。\n if (inherit) root.appendChild(styleEl('@layer arcrun-base, app, arcrun;'));\n // ② 最低層:裸元素的預設版面(App 蓋得掉)。\n root.appendChild(styleEl(inherit ? '@layer arcrun-base{' + APP_BASE_CSS + '}' : ':host{display:block;width:100%}'));\n if (inherit && cis) {\n // Portal 的 CIS 樣式表放**最高層**App 用 `.btn3``.muted``.panel` 這些既有 class\n // 時,它們的 specificity 比我下面那組裸元素規則高 ⇒ App 表達得出「這顆是次要按鈕」。\n root.appendChild(styleEl('@layer arcrun{' + cis.textContent + '}'));\n }\n if (inherit) {\n // 最高層的第二疊=全局色票/字體本身。放在 CIS 之後(同一層),所以 `.btn3` 這種\n // class 規則靠 specificity 仍然贏過我這組裸元素規則 ⇒ App 表達得出樣式意圖。\n root.appendChild(styleEl('@layer arcrun{' + APP_INHERIT_CSS + '}'));\n } else if (cis) {\n // own 模式:整體樣式一樣給(App 想用 `.btn3` 就用得到),但不設層 ⇒ App 自己的\n // 規則排在後面,照常蓋得過去。「堅持用自己的」就是這個意思。\n root.appendChild(cis.cloneNode(true));\n }\n // ③ App 自己的畫面。用 <template> 解析:`<!doctype>/<html>/<head>/<body>` 會被丟掉、\n // 內容留下,而且這一步**不會**執行內嵌 `<script>`(跟 innerHTML 同樣的特性)。\n var tpl = document.createElement('template');\n tpl.innerHTML = html;\n var styles = Array.prototype.slice.call(tpl.content.querySelectorAll('style'));\n var scripts = Array.prototype.slice.call(tpl.content.querySelectorAll('script'));\n // inherit 模式把 App 的每一份 <style> 包進 `app` 層。包在**掛進 shadow 之前**做,\n // 這樣它一被解析就已經在層裡,不會有「先以無層身分套用一幀」的閃色。\n if (inherit) styles.forEach(function (st) { st.textContent = '@layer app{' + st.textContent + '}'; });\n root.appendChild(tpl.content);\n // ④ 文件層選擇器的處置=兩種模式的實體差別(見 applyAppStyleMode 的說明)。\n // 只動 App 自己帶進來的 style;上面那份 CIS 副本不碰——它的 html/body 規則在\n // shadow 裡本來就不命中,改寫反而會把 Portal 的紙紋畫進 App 的盒子。\n styles.forEach(function (st) { if (st.sheet) applyAppStyleMode(st.sheet, inherit); });\n return { root: root, scripts: scripts };\n }\n\n function runAppScripts(root, scripts) {\n var appDocument = appDocumentFor(root);\n scripts.forEach(function (old) {\n if (old.src) {\n // 外部 script 換不掉它看到的 `document`(那是瀏覽器決定的)⇒ 照舊丟進文件執行。\n // 誠實標明:這種 App 的 script 抓不到自己 shadow 裡的畫面。v0 的 App 都是單檔內嵌。\n var s = document.createElement('script');\n s.src = old.src;\n old.parentNode.replaceChild(s, old);\n return;\n }\n try {\n (new Function('document', old.textContent)).call(window, appDocument);\n } catch (e) {\n // App 自己壞掉不該把 Portal 一起帶走——記進 console,畫面留著讓人看得出哪裡壞。\n console.error('[arcrun-app] App 的 script 執行失敗:', e);\n }\n });\n }\n\n // 離開 App 頁時把整個 shadow host 丟掉。Shadow DOM 已經擋住樣式外洩,這一步是為了\n // 不讓上一個 App 的畫面、計時器、監聽器留在文件裡(切頁只 toggle class,不會自己清)。\n function unmountAppUi() {\n var body = $('app-body');\n if (body) body.innerHTML = '';\n }\n\n function renderAppView(app) {\n var body = $('app-body');\n $('app-title').textContent = esc(app.icon || '') + ' ' + esc(app.name || app.id);\n if (app.has_ui && app.ui_html) {\n // 缺口①:畫面落地在本實例自己的資料層,執行期由 Portal 動態載入——不是編進出貨的 UI bundle。\n body.innerHTML = '';\n var host = document.createElement('div');\n host.id = 'app-ui-mount';\n body.appendChild(host);\n // 暴露給 App 自己畫面用的唯一通道(K6):只能呼叫白名單動作,拿不到任何金鑰/租戶字串。\n // 🔴 順序:**在跑 App 的 script 之前**就備妥——App 才不必為了「Portal 何時賦值」\n // 寫 setTimeout 之類的時序自保(舊版是先跑 script 才賦值)。\n window.arcrunApp = window.arcrunApp || {};\n window.arcrunApp.action = function (action, payload) { return callAppAction(app.id, action, payload); };\n // 掛載協定 v0.2:樣式模式由 App 的宣告決定(沒宣告=跟隨全局)。\n var mounted = mountAppUi(host, app.ui_html, app.ui_style);\n runAppScripts(mounted.root, mounted.scripts);\n } else {\n // K3/§2.1 系統預設畫面:沒有畫面的 App 一樣要有東西可點——這條工作流是什麼、\n // 上次跑得怎樣、要不要現在跑一次。\n var wfs = app.workflows || [];\n if (!wfs.length) {\n body.innerHTML = '<div class=\"muted\" style=\"padding:20px 4px\">這個 App 還沒有任何工作流。</div>';\n } else {\n body.innerHTML = wfs.map(function (w) {\n return '<div class=\"card-item\">' +\n '<div style=\"display:flex;align-items:baseline;gap:10px;flex-wrap:wrap\">' +\n '<span class=\"serif\" style=\"font-size:17px;font-weight:600\">' + esc(w.name) + '</span>' +\n '<button class=\"btn3\" style=\"margin-left:auto\" data-run-action=\"' + esc(w.name) + '\">現在執行</button></div>' +\n (w.description ? '<div style=\"margin-top:8px;font-size:14.5px;color:rgba(var(--ink-rgb),.65)\">' + esc(w.description) + '</div>' : '<div class=\"dim\" style=\"margin-top:8px;font-size:13.5px\">(沒有描述)</div>') +\n '<div class=\"dim mono\" data-run-status style=\"margin-top:6px;font-size:13px\"></div>' +\n '</div>';\n }).join('');\n Array.prototype.forEach.call(body.querySelectorAll('[data-run-action]'), function (btn) {\n btn.addEventListener('click', function () {\n var action = btn.getAttribute('data-run-action');\n var statusEl = btn.closest('.card-item').querySelector('[data-run-status]');\n // 這個動作是否在白名單內由 server 決定(前端只是顯示,藏不藏都繞不過)。\n statusEl.textContent = '執行中…';\n btn.disabled = true;\n callAppAction(app.id, action, {}).then(function (x) {\n btn.disabled = false;\n if (guard401(x.status)) return;\n if (x.ok && x.d && x.d.ok) {\n statusEl.textContent = '完成:' + JSON.stringify(x.d.result || {}).slice(0, 160);\n } else {\n statusEl.textContent = '失敗:' + ((x.d && x.d.error) || ('HTTP ' + x.status));\n }\n }).catch(function (e) {\n btn.disabled = false;\n statusEl.textContent = '請求失敗:' + friendlyErr(e);\n });\n });\n });\n }\n }\n // 卸載(design §四③:「刪 icon 就是刪 App」):admin-only,與 /portal/data/workflows 同一道閘。\n var canRemove = !!(S.profile && S.profile.role === 'admin');\n var removeBtn = $('app-remove-btn');\n removeBtn.classList.toggle('hide', !canRemove);\n // 兩段式確認,理由同 armRemoveButton():內建 confirm() 在某些內嵌瀏覽器會靜默回 false,\n // 那會讓「按了移除但什麼都沒發生」成為常態——本票明講不准有靜默失敗。\n removeBtn.onclick = function () {\n if (removeBtn.dataset.armed !== '1') { armRemoveButton(removeBtn, app.name || app.id, '移除這個 App'); return; }\n disarmRemoveButton(removeBtn);\n fetch(API_BASE + '/portal/data/apps/' + encodeURIComponent(app.id), { method: 'DELETE', headers: authHeaders() })\n .then(function (r) { return safeJson(r).then(function (d) { return { ok: r.ok, status: r.status, d: d }; }); })\n .then(function (x) {\n if (guard401(x.status)) return;\n if (!x.ok) { toast((x.d && x.d.error) || '移除失敗'); return; }\n toast('已移除');\n nav('launcher'); // Arcrun#152:回「App 界面」(原本回 search,四頁簽改版後首頁是啟動器)\n renderAppsNav(); // App 界面磚塊格/App 市集清單重新整理——這一格立刻消失,不用整頁重新整理\n })\n .catch(function (e) { toast('請求失敗:' + friendlyErr(e)); });\n };\n }\n\n // ── 上傳頁(portal-demo-suite)──\n // 前端只讀檔轉 base64 逐檔 POST /portal/data/uploadGitea 位置與 token 全在 server 側,\n // 這裡看不到任何 repo/token 字串。逐檔獨立狀態列(一檔失敗不拖累其他檔)。\n var UP_OK_MSG = '已收件,約 1 分鐘後可在搜尋頁找到;AI 整理後會以 wiki 卡形式出現。';\n function b64FromDataUrl(dataUrl) {\n var i = String(dataUrl).indexOf(',');\n return i >= 0 ? String(dataUrl).slice(i + 1) : '';\n }\n function uploadStatusRow(name) {\n var row = document.createElement('div');\n row.className = 'card-item';\n row.innerHTML = '<div style=\"display:flex;align-items:baseline;gap:10px;flex-wrap:wrap\">' +\n '<span class=\"mono\" style=\"font-size:14.5px;word-break:break-all\">' + esc(name) + '</span>' +\n '<span class=\"up-st muted\" style=\"margin-left:auto;font-size:14px;flex:none\">讀取中…</span></div>' +\n '<div class=\"up-msg\" style=\"margin-top:6px;font-size:13.5px;line-height:1.65;color:rgba(var(--ink-rgb),.6)\"></div>';\n $('up-list').prepend(row);\n return row;\n }\n function setRowStatus(row, ok, statusText, msg) {\n var st = row.querySelector('.up-st');\n st.textContent = statusText;\n st.className = 'up-st ' + (ok === true ? 'ok' : (ok === false ? 'err' : 'muted'));\n row.querySelector('.up-msg').textContent = msg || '';\n }\n function uploadOneFile(file) {\n var row = uploadStatusRow(file.name);\n if (!/\\.(md|txt)$/i.test(file.name)) {\n setRowStatus(row, false, '已略過', '只收 .md / .txt 檔。');\n return;\n }\n var reader = new FileReader();\n reader.onerror = function () { setRowStatus(row, false, '讀檔失敗', '瀏覽器讀不到這個檔案。'); };\n reader.onload = function () {\n setRowStatus(row, null, '上傳中…', '');\n fetch(API_BASE + '/portal/data/upload', {\n method: 'POST',\n headers: Object.assign({ 'Content-Type': 'application/json' }, authHeaders()),\n body: JSON.stringify({ filename: file.name, content_b64: b64FromDataUrl(reader.result) })\n })\n .then(function (r) { return safeJson(r).then(function (d) { return { ok: r.ok, status: r.status, d: d }; }); })\n .then(function (x) {\n if (guard401(x.status)) return;\n if (!x.ok) { setRowStatus(row, false, '失敗', x.d.error || ('HTTP ' + x.status)); return; }\n setRowStatus(row, true, '已收件', UP_OK_MSG + (x.d.path ? '' + x.d.path + '' : ''));\n })\n .catch(function (e) { setRowStatus(row, false, '失敗', friendlyErr(e)); });\n };\n reader.readAsDataURL(file); // dataURL 尾段即 base64unicode 安全,免手刻 btoa 編碼)\n }\n function handleUploadFiles(files) {\n for (var i = 0; i < files.length; i++) uploadOneFile(files[i]);\n }\n $('up-pick').addEventListener('click', function (ev) { ev.stopPropagation(); $('up-file').click(); });\n $('up-drop').addEventListener('click', function () { $('up-file').click(); });\n $('up-file').addEventListener('change', function () { handleUploadFiles(this.files); this.value = ''; });\n ['dragover', 'dragenter'].forEach(function (t) {\n $('up-drop').addEventListener(t, function (ev) { ev.preventDefault(); ev.currentTarget.style.background = 'rgba(var(--amber-rgb),.12)'; });\n });\n ['dragleave', 'drop'].forEach(function (t) {\n $('up-drop').addEventListener(t, function (ev) { ev.preventDefault(); ev.currentTarget.style.background = 'rgba(var(--amber-rgb),.04)'; });\n });\n $('up-drop').addEventListener('drop', function (ev) {\n if (ev.dataTransfer && ev.dataTransfer.files && ev.dataTransfer.files.length) handleUploadFiles(ev.dataTransfer.files);\n });\n\n // ── 管理頁(P4:帳號管理+庫目錄管理。全走 /portal/admin/*,前端零業務邏輯;\n // 一般用戶 nav 不顯示,且 server role 閘 403——藏只是 UX,真閘在後端)──\n var adminLibs = []; // 庫目錄快取(渲染每帳號的庫勾選用)\n\n function adminApi(method, path, body) {\n path = API_BASE + path;\n var opt = { method: method, headers: Object.assign({ 'Content-Type': 'application/json' }, authHeaders()) };\n if (body !== undefined) opt.body = JSON.stringify(body);\n return fetch(path, opt).then(function (r) {\n return safeJson(r).then(function (d) { return { ok: r.ok, status: r.status, d: d }; });\n });\n }\n\n // 執行紀錄保留期(P7):GET/PUT /portal/admin/execution-log-retentionrole=admin 閘(server 端)。\n // retention_days: number=自訂天數;null=「不刪除」(企業稽核,leo 08-07:「我願意花很多錢\n // 保存,不要刪除」);未設定過的租戶也會回一個值(KBDB 端退回預設 90 天)。\n function loadRetention() {\n $('ad-ret-current').textContent = '載入中…';\n adminApi('GET', '/portal/admin/execution-log-retention')\n .then(function (x) {\n if (guard401(x.status)) return;\n if (!x.ok) { $('ad-ret-current').textContent = ''; $('ad-ret-status').textContent = x.d.error || ('讀取失敗(HTTP ' + x.status + ''); return; }\n var days = x.d.retention_days;\n var def = x.d.default_days || 90;\n $('ad-ret-never').checked = (days === null);\n $('ad-ret-days').value = (days === null) ? '' : (days != null ? days : def);\n $('ad-ret-days').disabled = (days === null);\n $('ad-ret-current').textContent = (days === null)\n ? '目前設定:不刪除(企業稽核)'\n : '目前設定:保留 ' + (days != null ? days : def) + ' 天' + (days == null ? '(沿用預設值,尚未自訂)' : '');\n })\n .catch(function (e) { $('ad-ret-current').textContent = ''; $('ad-ret-status').textContent = friendlyErr(e); });\n }\n $('ad-ret-never').addEventListener('change', function () {\n $('ad-ret-days').disabled = this.checked;\n });\n $('ad-ret-save').addEventListener('click', function () {\n var st = $('ad-ret-status');\n st.textContent = '';\n var never = $('ad-ret-never').checked;\n var body;\n if (never) {\n body = { retention_days: null };\n } else {\n var n = parseInt($('ad-ret-days').value, 10);\n if (!n || n <= 0) { st.textContent = '請輸入大於 0 的天數,或勾「不刪除」'; return; }\n body = { retention_days: n };\n }\n $('ad-ret-save').disabled = true;\n adminApi('PUT', '/portal/admin/execution-log-retention', body)\n .then(function (x) {\n $('ad-ret-save').disabled = false;\n if (guard401(x.status)) return;\n if (!x.ok) { st.textContent = x.d.error || ('儲存失敗(HTTP ' + x.status + ''); return; }\n toast('保留期已更新');\n loadRetention();\n })\n .catch(function (e) { $('ad-ret-save').disabled = false; st.textContent = friendlyErr(e); });\n });\n\n function loadAdmin() {\n $('ad-users').innerHTML = '<div class=\"muted\">載入中…</div>';\n $('ad-libs').innerHTML = '<div class=\"muted\">載入中…</div>';\n loadRetention();\n adminApi('GET', '/portal/admin/libraries')\n .then(function (x) {\n if (guard401(x.status)) return;\n if (!x.ok) { $('ad-libs').innerHTML = '<div class=\"err\">' + esc(x.d.error || ('讀取失敗(HTTP ' + x.status + '')) + '</div>'; return; }\n adminLibs = x.d.libraries || [];\n renderAdminLibs();\n return adminApi('GET', '/portal/admin/users').then(function (y) {\n if (guard401(y.status)) return;\n if (!y.ok) { $('ad-users').innerHTML = '<div class=\"err\">' + esc(y.d.error || ('讀取失敗(HTTP ' + y.status + '')) + '</div>'; return; }\n renderAdminUsers(y.d.users || []);\n });\n })\n .catch(function (e) {\n $('ad-users').innerHTML = '<div class=\"err\">請求失敗:' + esc(friendlyErr(e)) + '</div>';\n $('ad-libs').innerHTML = '';\n });\n }\n\n // 帳號可勾選的庫=庫目錄啟用中的庫 ∪ general ∪ 該帳號已有的庫(目錄外的舊授權不憑空消失)\n function checkableLibs(userLibs) {\n var names = ['general'];\n adminLibs.forEach(function (l) { if (l.status !== 'disabled' && l.name && names.indexOf(l.name) < 0) names.push(l.name); });\n (userLibs || []).forEach(function (n) { if (n !== '*' && names.indexOf(n) < 0) names.push(n); });\n return names;\n }\n function libDisplay(name) {\n for (var i = 0; i < adminLibs.length; i++) { if (adminLibs[i].name === name) return adminLibs[i].display_name || name; }\n return name;\n }\n\n function renderAdminUsers(users) {\n if (!users.length) { $('ad-users').innerHTML = '<div class=\"muted\" style=\"padding:16px 4px\">還沒有任何同仁帳號——用上面的表單新增第一個。</div>'; return; }\n $('ad-users').innerHTML = users.map(function (u) {\n var star = (u.libraries || []).indexOf('*') >= 0;\n var disabled = u.status === 'disabled';\n var libChips = star\n ? '<span class=\"tag green\">全部知識庫</span>'\n : ((u.libraries || []).length\n ? (u.libraries || []).map(function (n) { return '<span class=\"tag green\">' + esc(libDisplay(n)) + '</span>'; }).join(' ')\n : '<span class=\"tag dim\">尚未授權任何庫</span>');\n var boxes = '<label><input type=\"checkbox\" data-star data-uid=\"' + esc(u.record_id) + '\"' + (star ? ' checked' : '') + '> 全部知識庫(*</label>' +\n checkableLibs(u.libraries).map(function (n) {\n var on = !star && (u.libraries || []).indexOf(n) >= 0;\n return '<label><input type=\"checkbox\" data-lib=\"' + esc(n) + '\" data-uid=\"' + esc(u.record_id) + '\"' + (on ? ' checked' : '') + (star ? ' disabled' : '') + '> ' + esc(libDisplay(n)) + ' <span class=\"dim mono\" style=\"font-size:12px\">' + esc(n) + '</span></label>';\n }).join('');\n return '<div class=\"card-item\"' + (disabled ? ' style=\"opacity:.6\"' : '') + '>' +\n '<div style=\"display:flex;align-items:baseline;gap:10px;flex-wrap:wrap\">' +\n '<span class=\"serif\" style=\"font-size:17px;font-weight:600\">' + esc(u.display_name || u.email) + '</span>' +\n '<span class=\"muted\" style=\"font-size:14px;word-break:break-all\">' + esc(u.email) + '</span>' +\n '<span class=\"tag' + (u.role === 'admin' ? '' : ' dim') + '\">' + (u.role === 'admin' ? '管理員' : '一般用戶') + '</span>' +\n '<span class=\"tag ' + (disabled ? 'dim' : 'green') + '\">' + (disabled ? '已停用' : '啟用中') + '</span></div>' +\n '<div style=\"margin-top:9px;display:flex;gap:6px;flex-wrap:wrap;align-items:center;font-size:13px\"><span class=\"muted\" style=\"flex:none\">可查庫</span>' + libChips + '</div>' +\n '<div class=\"btnrow\">' +\n '<button class=\"btn2\" data-act=\"edit-libs\" data-uid=\"' + esc(u.record_id) + '\">編輯可查庫</button>' +\n '<button class=\"btn2\" data-act=\"reset-pw\" data-uid=\"' + esc(u.record_id) + '\" data-email=\"' + esc(u.email) + '\">重設密碼</button>' +\n (disabled\n ? '<button class=\"btn2\" data-act=\"set-status\" data-next=\"active\" data-uid=\"' + esc(u.record_id) + '\">啟用</button>'\n : '<button class=\"btn2 warn\" data-act=\"set-status\" data-next=\"disabled\" data-uid=\"' + esc(u.record_id) + '\" data-email=\"' + esc(u.email) + '\">停用</button>') +\n '</div>' +\n '<div id=\"libed-' + esc(u.record_id) + '\" style=\"display:none\">' +\n '<div class=\"libgrid\">' + boxes + '</div>' +\n '<div class=\"btnrow\"><button class=\"btn2\" data-act=\"save-libs\" data-uid=\"' + esc(u.record_id) + '\">儲存庫權限</button>' +\n '<span class=\"dim\" style=\"font-size:13px;align-self:center\">勾「全部知識庫」=不限庫;否則至少勾一個。儲存後立即生效。</span></div></div>' +\n '</div>';\n }).join('');\n }\n\n function renderAdminLibs() {\n if (!adminLibs.length) { $('ad-libs').innerHTML = '<div class=\"muted\" style=\"padding:16px 4px\">同步小幫手還沒送來任何庫。裝好小幫手並選好資料夾後,庫會自動出現在這裡。</div>'; return; }\n $('ad-libs').innerHTML = adminLibs.map(function (l) {\n var disabled = l.status === 'disabled';\n var notWatching = l.daemon_watching === false; // daemon 有報告但此庫不在其中\n var removeBtn = l.auto\n ? '<button class=\"btn2\" style=\"color:#b03a26;border-color:#e58575;margin-left:auto\" data-act=\"lib-remove-auto\" data-name=\"' + esc(l.name) + '\">移除</button>'\n : '<button class=\"btn2\" style=\"color:#b03a26;border-color:#e58575;margin-left:auto\" data-act=\"lib-remove\" data-id=\"' + esc(l.record_id) + '\" data-name=\"' + esc(l.display_name || l.name) + '\">移除</button>';\n // t142:卡數+三元組數顯示(政府驗收用)。兩者皆 0 顯示「還沒有內容」,不顯示「0 張」。\n var cardCount = typeof l.card_count === 'number' ? l.card_count : undefined;\n var tripletCount = typeof l.triplet_count === 'number' ? l.triplet_count : undefined;\n var statsHtml = '';\n if (cardCount !== undefined || tripletCount !== undefined) {\n var parts = [];\n if (cardCount > 0) parts.push(cardCount + ' 張知識卡');\n if (tripletCount > 0) parts.push(tripletCount + ' 條關聯');\n statsHtml = '<div style=\"margin-top:5px;font-size:13px;color:rgba(var(--ink-rgb),.5)\">' +\n (parts.length ? parts.join('・') : '還沒有內容') + '</div>';\n }\n return '<div class=\"card-item\">' +\n '<div style=\"display:flex;align-items:baseline;gap:10px;flex-wrap:wrap\">' +\n '<span class=\"serif\" style=\"font-size:17px;font-weight:600\">' + esc(l.display_name || l.name) + '</span>' +\n '<span class=\"dim mono\" style=\"font-size:13px\">' + esc(l.name) + '</span>' +\n (l.auto\n ? '<span class=\"tag green\">啟用中</span><span class=\"tag\">同步自動出現</span>'\n : '<span class=\"tag ' + (disabled ? 'dim' : 'green') + '\">' + (disabled ? '已停用' : '啟用中') + '</span>') +\n removeBtn +\n '</div>' +\n statsHtml +\n (!l.auto && l.description ? '<div style=\"margin-top:8px;font-size:14.5px;line-height:1.65;color:rgba(var(--ink-rgb),.65)\">' + esc(l.description) + '</div>' : '') +\n (notWatching ? '<div style=\"margin-top:6px;font-size:13px;color:rgba(var(--ink-rgb),.45)\">小幫手目前沒有在同步這個資料夾</div>' : '') +\n '</div>';\n }).join('');\n }\n\n // 一次性密碼顯示(server 不留明碼——關掉就真的沒了,誠實跟 admin 說清楚)\n function showOtp(email, password) {\n $('ad-otp').innerHTML = '<div class=\"otpbox\">' +\n '<div style=\"font-size:15px;font-weight:600\">' + esc(email) + ' 的一次性密碼</div>' +\n '<div class=\"pw\">' + esc(password) + '</div>' +\n '<div style=\"font-size:13.5px;line-height:1.7;color:rgba(var(--ink-rgb),.65)\">只顯示這一次——關閉後再也調不出來(系統只存雜湊)。請當場轉交同仁,並提醒登入後到「設定」改成自己的密碼。</div>' +\n '<div class=\"btnrow\"><button class=\"btn2\" id=\"ad-otp-close\">我已轉交,關閉</button></div></div>';\n $('ad-otp').scrollIntoView({ block: 'nearest' });\n }\n\n // 新增帳號\n $('ad-nu-create').addEventListener('click', function () {\n var email = $('ad-nu-email').value.trim();\n var name = $('ad-nu-name').value.trim();\n var role = $('ad-nu-role').value === 'admin' ? 'admin' : 'user';\n var st = $('ad-nu-status');\n if (!email) { st.textContent = '請填 Email'; return; }\n st.textContent = '';\n $('ad-nu-create').disabled = true;\n var body = { email: email, role: role };\n if (name) body.display_name = name;\n adminApi('POST', '/portal/admin/users', body)\n .then(function (x) {\n $('ad-nu-create').disabled = false;\n if (guard401(x.status)) return;\n if (!x.ok) { st.textContent = x.d.error || ('建立失敗(HTTP ' + x.status + ''); return; }\n $('ad-nu-email').value = ''; $('ad-nu-name').value = ''; $('ad-nu-role').value = 'user';\n if (x.d.generated_password) showOtp(email, x.d.generated_password);\n toast('帳號已建立');\n loadAdmin();\n })\n .catch(function (e) { $('ad-nu-create').disabled = false; st.textContent = friendlyErr(e); });\n });\n\n\n // 「全部知識庫」勾選 → 其餘庫勾選框連動停用(存的就是 [\"*\"],個別勾選無意義)\n document.addEventListener('change', function (ev) {\n var t = ev.target;\n if (!t || !t.hasAttribute || !t.hasAttribute('data-star')) return;\n var uid = t.getAttribute('data-uid');\n document.querySelectorAll('#libed-' + uid + ' input[data-lib]').forEach(function (cb) {\n cb.disabled = t.checked;\n if (t.checked) cb.checked = false;\n });\n });\n\n // 管理頁動作(事件委派)\n $('v-admin').addEventListener('click', function (ev) {\n var t = ev.target.closest('[data-act]');\n if (!t) return;\n var act = t.getAttribute('data-act');\n var uid = t.getAttribute('data-uid');\n\n if (act === 'edit-libs') {\n var ed = $('libed-' + uid);\n ed.style.display = ed.style.display === 'none' ? '' : 'none';\n return;\n }\n if (act === 'save-libs') {\n var star = document.querySelector('#libed-' + uid + ' input[data-star]');\n var libs;\n if (star && star.checked) { libs = ['*']; }\n else {\n libs = [];\n document.querySelectorAll('#libed-' + uid + ' input[data-lib]').forEach(function (cb) {\n if (cb.checked) libs.push(cb.getAttribute('data-lib'));\n });\n if (!libs.length) { toast('至少勾一個庫,或勾「全部知識庫」'); return; }\n }\n t.disabled = true;\n adminApi('PATCH', '/portal/admin/users/' + encodeURIComponent(uid), { libraries: libs })\n .then(function (x) {\n t.disabled = false;\n if (guard401(x.status)) return;\n if (!x.ok) { toast(x.d.error || ('儲存失敗(HTTP ' + x.status + '')); return; }\n toast('庫權限已更新,立即生效');\n loadAdmin();\n })\n .catch(function (e) { t.disabled = false; toast(friendlyErr(e)); });\n return;\n }\n if (act === 'set-status') {\n var next = t.getAttribute('data-next');\n if (next === 'disabled' && !confirm('確定停用 ' + (t.getAttribute('data-email') || '這個帳號') + '?停用後其登入與既有 session 立即失效。')) return;\n t.disabled = true;\n adminApi('PATCH', '/portal/admin/users/' + encodeURIComponent(uid), { status: next })\n .then(function (x) {\n t.disabled = false;\n if (guard401(x.status)) return;\n if (!x.ok) { toast(x.d.error || ('更新失敗(HTTP ' + x.status + '')); return; } // 含最後一個 admin 的 409 訊息\n toast(next === 'disabled' ? '已停用' : '已啟用');\n loadAdmin();\n })\n .catch(function (e) { t.disabled = false; toast(friendlyErr(e)); });\n return;\n }\n if (act === 'reset-pw') {\n var email = t.getAttribute('data-email') || '';\n if (!confirm('確定重設 ' + email + ' 的密碼?舊密碼將立即失效,會產生一組新的一次性密碼。')) return;\n t.disabled = true;\n adminApi('POST', '/portal/admin/users/' + encodeURIComponent(uid) + '/reset-password')\n .then(function (x) {\n t.disabled = false;\n if (guard401(x.status)) return;\n if (!x.ok) { toast(x.d.error || ('重設失敗(HTTP ' + x.status + '')); return; }\n showOtp(email, x.d.password);\n toast('密碼已重設');\n })\n .catch(function (e) { t.disabled = false; toast(friendlyErr(e)); });\n return;\n }\n // 移除已登記庫(有 record_id\n if (act === 'lib-remove') {\n var libId = t.getAttribute('data-id') || '';\n var libName = t.getAttribute('data-name') || libId;\n if (!confirm('把「' + libName + '」從目錄移除?\\n\\n資料不會刪除,重新同步時會再出現。')) return;\n t.disabled = true;\n adminApi('DELETE', '/portal/admin/libraries/' + encodeURIComponent(libId))\n .then(function (x) {\n t.disabled = false;\n if (guard401(x.status)) return;\n if (!x.ok) { toast(x.d.error || ('移除失敗(HTTP ' + x.status + '')); return; }\n adminLibs = adminLibs.filter(function (l) { return l.record_id !== libId; });\n renderAdminLibs();\n toast('已從目錄移除');\n })\n .catch(function (e) { t.disabled = false; toast(friendlyErr(e)); });\n return;\n }\n // 移除 auto 庫(無 record_identries 標 deprecated\n if (act === 'lib-remove-auto') {\n var autoName = t.getAttribute('data-name') || '';\n var input = window.prompt('移除「' + autoName + '」會讓它的內容不再被搜尋到(資料保留可還原)。\\n\\n請輸入庫名確認:');\n if (input === null) return; // 取消\n if (input.trim() !== autoName) { toast('庫名輸入不符,取消移除'); return; }\n t.disabled = true;\n adminApi('DELETE', '/portal/admin/libraries/by-name/' + encodeURIComponent(autoName), { confirm: autoName })\n .then(function (x) {\n t.disabled = false;\n if (guard401(x.status)) return;\n if (!x.ok) { toast(x.d.error || ('移除失敗(HTTP ' + x.status + '')); return; }\n adminLibs = adminLibs.filter(function (l) { return l.name !== autoName; });\n renderAdminLibs();\n toast('已移除(' + (x.d.deprecated_count || 0) + ' 筆標為不可搜)');\n })\n .catch(function (e) { t.disabled = false; toast(friendlyErr(e)); });\n return;\n }\n });\n // 一次性密碼關閉鈕(otpbox 動態生成,掛在容器上)\n $('ad-otp').addEventListener('click', function (ev) {\n if (ev.target && ev.target.id === 'ad-otp-close') $('ad-otp').innerHTML = '';\n });\n\n // ── 版本檢查(2026-08-02)──────────────────────────────────────────────\n // leo 的兩個要求:\n // ②「不顯示的話用戶不知道要不要更新」→ 一定要有目前版本\n // ③「白癡化,發現落後就按一下開啟 install 直接帶它的 email 和辨識碼」\n // → 落後才出現按鈕,且自動帶 email;辨識碼不必帶(安裝器 t154 對既有實例免碼)\n //\n // 比法:自己的版本(cypher /health 的 bundle_versionvs 最新版(安裝器 /api/latest)。\n // 兩邊都是 semver(例 1.4.2),用數字逐段比,不用字串比('1.4.10' < '1.4.9' 會出錯)。\n var INSTALLER_ORIGIN = 'https://install.arcrun.dev';\n\n // Arcrun#106:版號後面可以帶 build metadata`1.4.41+d61`、`1.4.41+a1b2c3d`)——\n // 那是 semver 規格裡「比大小時要忽略」的那一段。舊寫法拿整串去比對正規式,\n // 一律落到「較舊版本」(youlin 實例就是這樣,明明有版號卻顯示不出來)。\n // 這裡只取前面的 `x.y.z` 當比較用的核心,顯示仍顯示完整原字串。\n function semverCore(v) {\n var m = String(v || '').match(/^(\\d+\\.\\d+\\.\\d+)/);\n return m ? m[1] : '';\n }\n\n function cmpSemver(a, b) {\n var x = String(a || '').split('.').map(Number);\n var y = String(b || '').split('.').map(Number);\n for (var i = 0; i < 3; i++) {\n var d = (x[i] || 0) - (y[i] || 0);\n if (d) return d < 0 ? -1 : 1;\n }\n return 0;\n }\n\n function loadVersion() {\n var line = $('st-ver-line');\n var dot = $('st-ver-dot');\n var btn = $('st-ver-update');\n if (!line) return;\n\n // #106:順便把 bundle_commit 帶回來(有注入才有)——版號是頻道編號,commit 才是「真的部了哪份碼」。\n var mineCommit = '';\n var mineP = fetch(window.ARCRUN_API_BASE + '/health', { cache: 'no-store' })\n .then(function (r) { return r.ok ? r.json() : null; })\n .then(function (j) {\n mineCommit = (j && j.bundle_commit) || '';\n return (j && j.bundle_version) || '';\n })\n .catch(function () { return ''; });\n var latestP = fetch(INSTALLER_ORIGIN + '/api/latest')\n .then(function (r) { return r.ok ? r.json() : null; })\n .then(function (j) { return (j && j.release) || ''; })\n .catch(function () { return ''; });\n\n Promise.all([mineP, latestP]).then(function (res) {\n var mine = res[0], latest = res[1];\n\n if (!mine) { line.textContent = '無法讀取目前版本(知識庫服務可能正在啟動)'; return; }\n // 舊實例的 bundle_version 是舊格式(2026-07-31+8e83589),比不了 semver。\n // 這種情況一律當成「落後」——因為新版才會寫 semver 進來。\n // #106`1.4.41+<commit>` 這種帶 build metadata 的**是** semver,取核心比即可。\n var mineCore = semverCore(mine);\n var mineIsSemver = !!mineCore;\n // commit 是輔助資訊(有才顯示):版號說「哪一版」,commit 說「真的是哪份碼」。\n var commitNote = mineCommit ? ' <span class=\"muted\">commit ' + esc(String(mineCommit).slice(0, 7)) + '</span>' : '';\n\n if (!latest) {\n line.innerHTML = '目前版本 <strong>' + esc(mine) + '</strong>(暫時查不到最新版,稍後再試)' + commitNote;\n return;\n }\n var behind = !mineIsSemver || cmpSemver(mineCore, latest) < 0;\n if (!behind) {\n line.innerHTML = '目前版本 <strong>' + esc(mine) + '</strong> 已是最新版' + commitNote;\n dot.style.display = 'none';\n btn.style.display = 'none';\n return;\n }\n line.innerHTML = '目前版本 <strong>' + esc(mineIsSemver ? mine : '較舊版本') + '</strong>'\n + ' → 最新版 <strong>' + esc(latest) + '</strong><br>'\n + '<span style=\"color:#C2492E\">有新版可以更新。按「立即更新」會開啟安裝頁,用你原本的 Cloudflare 帳號重新安裝一次即可,知識庫內容不會動到。</span>';\n dot.style.display = 'inline-block';\n btn.style.display = '';\n btn.onclick = function () {\n // 帶 email 讓安裝頁預填;既有實例更新免辨識碼(安裝器 t154)\n var email = (S.profile && S.profile.email) || '';\n var url = INSTALLER_ORIGIN + '/' + (email ? '?email=' + encodeURIComponent(email) : '');\n window.open(url, '_blank', 'noopener');\n };\n });\n }\n\n // ── 設定 ──\n function loadSettings() {\n var p = S.profile;\n if (!p) { $('st-me').innerHTML = '<div class=\"muted\">載入中…</div>'; return; }\n if (window._loadAiConfig) window._loadAiConfig();\n loadVersion();\n var libs = p.libraries || [];\n var libHtml = libs.indexOf('*') >= 0\n ? '<span class=\"tag green\">全部知識庫</span>'\n : (libs.length ? libs.map(function (l) { return '<span class=\"tag green\">' + esc(l) + '</span>'; }).join(' ') : '<span class=\"tag dim\">尚未授權任何庫</span>');\n $('st-me').innerHTML =\n '<div class=\"kvline\"><span class=\"muted\">名稱</span><span>' + esc(p.display_name || '') + '</span></div>' +\n '<div class=\"kvline\"><span class=\"muted\">角色</span><span>' + esc(p.role === 'admin' ? '管理員' : '一般用戶') + '</span></div>' +\n '<div class=\"kvline\" style=\"align-items:flex-start\"><span class=\"muted\" style=\"flex:none\">可查庫</span><span style=\"text-align:right;display:flex;gap:6px;flex-wrap:wrap;justify-content:flex-end\">' + libHtml + '</span></div>';\n }\n // ══════════ D62:改密碼與忘記密碼=同一個機制 ══════════\n //\n // leo 2026-08-10:「這兩個機制其實是一個機制,可以簡化。」\n // 修改密碼:輸入**現有的** → 輸入新的 → 覆蓋\n // 忘記密碼:收到**「修改密碼」連結** → **不輸入現有密碼(忽略)** → 輸入新的 → 覆蓋\n // ⇒ 底下只有**一個表單元素**(#pw-form)與**一支送出函式**,差別只有「現有密碼」那一格\n // 顯不顯示、以及帶 current 還是帶 reset_token。兩份長得像的東西必然漂移\n // (arcrun-rag#40「同一個事實兩份」)。\n // 🔴 不做一次性密碼(leo:「不要發一次性密碼太麻煩」)。\n\n var S_RESET_TOKEN = ''; // 非空=現在是「忘記密碼」模式\n\n /** 把那一份唯一的表單搬到指定容器,並決定「現有密碼」那一格出不出現。 */\n function mountPasswordForm(host, needCurrent) {\n var form = $('pw-form');\n if (form && form.parentNode !== host) host.appendChild(form);\n $('st-pw-old').classList.toggle('hide', !needCurrent);\n $('st-pw-save').textContent = needCurrent ? '更新密碼' : '設定新密碼';\n $('st-pw-old').value = ''; $('st-pw-new').value = ''; $('st-pw-new2').value = '';\n $('st-pw-status').textContent = '';\n }\n\n /** 送出:兩種模式共用。帶 reset_token 就走連結那一格,否則走現有密碼那一格。 */\n function submitPasswordChange() {\n var needCurrent = !S_RESET_TOKEN;\n var oldPw = $('st-pw-old').value;\n var newPw = $('st-pw-new').value;\n var newPw2 = $('st-pw-new2').value;\n var st = $('st-pw-status');\n st.className = 'err';\n if (needCurrent && !oldPw) { st.textContent = '請填現在的密碼'; return; }\n if (!newPw) { st.textContent = '請填新密碼'; return; }\n if (newPw.length < 8) { st.textContent = '新密碼至少 8 碼'; return; }\n if (newPw !== newPw2) { st.textContent = '兩次輸入的新密碼不一致'; return; }\n var body = { 'new': newPw };\n if (S_RESET_TOKEN) body.reset_token = S_RESET_TOKEN; else body.current = oldPw;\n $('st-pw-save').disabled = true;\n st.textContent = '處理中…';\n fetch(API_BASE + '/portal/password/change', {\n method: 'POST',\n headers: Object.assign({ 'Content-Type': 'application/json' }, needCurrent ? authHeaders() : {}),\n body: JSON.stringify(body)\n })\n .then(function (r) { return safeJson(r).then(function (d) { return { ok: r.ok, status: r.status, d: d }; }); })\n .then(function (x) {\n $('st-pw-save').disabled = false;\n // 忘記密碼模式沒有 session,401 不代表「你被登出」——別誤踢\n if (needCurrent && guard401(x.status)) return;\n if (!x.ok) { st.textContent = (x.d && x.d.error) || '更新失敗'; return; }\n st.className = 'ok';\n $('st-pw-old').value = ''; $('st-pw-new').value = ''; $('st-pw-new2').value = '';\n if (S_RESET_TOKEN) {\n st.textContent = '密碼已設定好了,正在帶你回登入頁…';\n var who = (x.d && x.d.email) || '';\n S_RESET_TOKEN = '';\n setTimeout(function () {\n history.replaceState(null, '', location.pathname);\n location.hash = '';\n $('v-reset').classList.remove('on');\n mountPasswordForm($('st-pw-panel'), true);\n showAuth();\n if (who) $('login-email').value = who;\n $('login-status').className = 'ok';\n $('login-status').textContent = '新密碼已生效,請用它登入。';\n }, 1200);\n } else {\n st.textContent = '密碼已更新(你不會被登出,可以繼續操作)';\n toast('密碼已更新');\n }\n })\n .catch(function (e) { $('st-pw-save').disabled = false; st.textContent = friendlyErr(e); });\n }\n $('st-pw-save').addEventListener('click', submitPasswordChange);\n\n // ── 登入頁的「忘記密碼」入口(**在 portal,不是 console**leo 2026-08-10)──\n $('login-forgot').addEventListener('click', function (ev) {\n ev.preventDefault();\n $('forgot-box').classList.remove('hide');\n $('forgot-email').value = $('login-email').value.trim();\n $('forgot-email').focus();\n });\n $('forgot-submit').addEventListener('click', function () {\n var email = $('forgot-email').value.trim();\n var st = $('forgot-status');\n st.className = 'err';\n if (!email) { st.textContent = '請填 Email'; return; }\n $('forgot-submit').disabled = true;\n st.textContent = '寄送中…';\n fetch(API_BASE + '/portal/password/forgot', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email: email })\n })\n .then(function (r) { return safeJson(r).then(function (d) { return { ok: r.ok, status: r.status, d: d }; }); })\n .then(function (x) {\n $('forgot-submit').disabled = false;\n if (!x.ok) { st.textContent = (x.d && x.d.error) || '寄送失敗'; return; }\n st.className = 'ok';\n st.textContent = (x.d && x.d.message) || '如果這個 email 有帳號,連結已經寄出了。';\n })\n .catch(function (e) { $('forgot-submit').disabled = false; st.textContent = friendlyErr(e); });\n });\n\n /** 點信裡的連結進來:`…/portal/#/reset?token=…`cypher 的 /portal/password/reset-link 導過來的)。 */\n function resetTokenFromUrl() {\n var m = String(location.hash || '').match(/[?&]token=([^&]+)/);\n if (m) return decodeURIComponent(m[1]);\n m = String(location.search || '').match(/[?&]token=([^&]+)/);\n return m ? decodeURIComponent(m[1]) : '';\n }\n function showReset(token) {\n $('v-login').classList.remove('on');\n $('v-firstsetup').classList.remove('on');\n $('shell').classList.remove('on');\n $('tabbar').classList.remove('on');\n $('v-reset').classList.add('on');\n $('reset-error').textContent = '';\n // 先問一次「這張票還有效嗎」——連結是一次有效、30 分鐘過期的,\n // 過期就要當場說清楚,不要讓人填完密碼才被打回票(#49:別把系統狀態講成用戶的錯)。\n fetch(API_BASE + '/portal/password/reset?token=' + encodeURIComponent(token))\n .then(function (r) { return safeJson(r).then(function (d) { return { ok: r.ok, d: d }; }); })\n .then(function (x) {\n if (!x.ok || !x.d || x.d.valid !== true) {\n $('reset-who').textContent = '';\n $('reset-error').textContent = (x.d && x.d.error) || '這條連結已經失效了。請回登入頁重新按一次「忘記密碼」。';\n return;\n }\n S_RESET_TOKEN = token;\n $('reset-who').innerHTML = '你正在為 <strong>' + esc(x.d.email) + '</strong> 設定新密碼。<br>這條連結只能用一次,<strong>不需要輸入現在的密碼</strong>。';\n mountPasswordForm($('reset-slot'), false); // ← 差別只有這一格\n })\n .catch(function (e) { $('reset-error').textContent = friendlyErr(e); });\n }\n $('reset-back').addEventListener('click', function (ev) {\n ev.preventDefault();\n S_RESET_TOKEN = '';\n history.replaceState(null, '', location.pathname);\n location.hash = '';\n $('v-reset').classList.remove('on');\n mountPasswordForm($('st-pw-panel'), true);\n showAuth();\n });\n\n boot();\n})();\n</script>\n</body>\n</html>"},"/portal/os-split.test.mjs":{"type":"application/javascript; charset=utf-8","b64":false,"data":"import fs from 'node:fs';\nconst html = fs.readFileSync(new URL('./index.html', import.meta.url).pathname,'utf8');\n// 抽出 daemonPick 相關函式(從 DAEMON_BASE_DEFAULT 到 daemonHint 結尾)\n//\n// 🔴 2026-08-05:結尾標記本來寫死 daemonHint 的**整句文案**,於是同日改 Mac 提示語\n// (zip→DMG 的步驟不同)就讓這支自測直接炸「抽不到函式區塊」,而且沒人發現。\n// ⇒ 改成錨定「函式結束」這個結構,不再綁文案——文案本來就會改,測試不該為此壞掉。\nconst start = html.indexOf('var DAEMON_BASE_DEFAULT');\nconst hintAt = html.indexOf('function daemonHint', start);\nconst endMark = '\\n }';\nconst end = hintAt < 0 ? -1 : html.indexOf(endMark, hintAt) + endMark.length;\nif (start < 0 || hintAt < 0 || end < start) throw new Error('抽不到函式區塊');\nconst src = html.slice(start, end);\n\nconst cases = [\n ['Windows', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120 Safari/537.36'],\n ['Mac', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 Safari/605.1.15'],\n ['iPhone', 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 Safari/604.1'],\n ['Linux', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/120 Safari/537.36'],\n];\nlet pass=0, fail=0;\nconst chk=(l,c,extra='')=>{ if(c){console.log('PASS:',l);pass++;} else {console.log('FAIL:',l,extra);fail++;} };\n\nfor (const [name, ua] of cases) {\n const fn = new Function('navigator','window', src + '; return {daemonPick:daemonPick, daemonHint:daemonHint, daemonBase:daemonBase};');\n const api = fn({userAgent: ua}, {});\n const d = api.daemonPick();\n const label = d.sure ? d.pick.label : '(兩個都給)';\n const url = d.sure ? d.pick.url : d.mac.url + ' + ' + d.win.url;\n console.log(`\\n[${name}] sure=${d.sure} → ${label}`);\n console.log(` url: ${url}`);\n if (name==='Windows') {\n chk('Windows 給 win zip', d.sure && d.pick.url.endsWith('ArcrunRAG-win-unsigned.zip'), d.pick&&d.pick.url);\n chk('Windows 另一版是 Mac', d.other && d.other.url.endsWith('ArcrunRAG-mac.dmg'));\n chk('Windows 話術提 藍色視窗', api.daemonHint('win').includes('仍要執行'));\n }\n if (name==='Mac') {\n // 2026-08-05Mac 一律給 DMG(拖進 Applications 的標準安裝畫面),不再給 zip\n // ——zip 解開就是一個裸 .app,使用者會直接在「下載」資料夾雙擊執行,自更新會蓋錯位置。\n chk('Mac 給 dmg(不是 zip', d.sure && d.pick.url.endsWith('ArcrunRAG-mac.dmg'));\n chk('Mac 另一版是 Windows', d.other && d.other.url.endsWith('win-unsigned.zip'));\n chk('Mac 話術提 右鍵打開', api.daemonHint('mac').includes('右鍵'));\n }\n if (name==='iPhone' || name==='Linux') {\n // iPhone 含 \"Mac OS X\" 但不是桌機 Mac;Linux 兩者皆非 → 都該落在「不確定=兩個都給」\n if (name==='Linux') chk('Linux 判不出來→兩個都給', d.sure===false);\n if (name==='iPhone') chk('iPhone 不該被判成 Mac(手機→兩個都給)', d.sure===false, 'sure='+d.sure);\n }\n}\n// 舊 key 相容\nconst fn2 = new Function('navigator','window', src + '; return daemonBase();');\nconsole.log('\\n[相容] daemonDownload 舊 key →', fn2({userAgent:''},{ARCRUN_CONFIG:{daemonDownload:'https://x.dev/d/ArcrunRAG-mac-unsigned.zip'}}));\nchk('舊 key 推得出目錄', fn2({userAgent:''},{ARCRUN_CONFIG:{daemonDownload:'https://x.dev/d/ArcrunRAG-mac-unsigned.zip'}})==='https://x.dev/d/');\nchk('daemonBase 新 key 優先', fn2({userAgent:''},{ARCRUN_CONFIG:{daemonBase:'https://y.dev/z'}})==='https://y.dev/z/');\nconsole.log(`\\n=== ${pass} passed, ${fail} failed ===`);\nprocess.exit(fail?1:0);\n"},"/portal/retrieval-tree.test.mjs":{"type":"application/javascript; charset=utf-8","b64":false,"data":"// 檢索過程樹(Arcrun#44 第二輪,leo 2026-08-18「希望以樹狀圖來展示」)的資料組裝測試。\n// 只測**樹的資料**,不測 markmap 怎麼畫——畫圖是現成函式庫的事(D97),\n// 我們自己要為之負責的是「層級對不對、有沒有把讀過的東西吞掉」。\n// 跑法:node console-ui/public/portal/retrieval-tree.test.mjs\nimport fs from 'node:fs';\nconst html = fs.readFileSync(new URL('./index.html', import.meta.url).pathname, 'utf8');\n\nconst grab = (name) => {\n const i = html.indexOf(`function ${name}(`);\n if (i < 0) throw new Error(`找不到 ${name}`);\n let d = 0, j = html.indexOf('{', i);\n for (let k = j; k < html.length; k++) { if (html[k] === '{') d++; if (html[k] === '}') { d--; if (!d) return html.slice(i, k + 1); } }\n throw new Error('括號不平衡');\n};\nconst src = ['esc', 'srcLocalPath', 'machineLabelMap', 'srcCrumbs', 'retrievalTreeData', 'visibleLeaves', 'treeListHtml'].map(grab).join('\\n');\nconst fn = new Function(src + '\\nvar SEARCH_ROUTE_LABEL = { graph: \"圖譜命中子庫\", index: \"索引退回選庫\", all: \"全庫讀取\" };'\n + '\\nreturn { srcCrumbs, machineLabelMap, retrievalTreeData, visibleLeaves, treeListHtml };')();\n\nlet pass = 0, fail = 0;\nconst t = (l, c, e = '') => { c ? (console.log('PASS:', l), pass++) : (console.log('FAIL:', l, e), fail++); };\nconst txt = (n) => String(n.content).replace(/<[^>]*>/g, '');\n\n// 2026-08-18 從 youlin stage 實跑 /portal/data/chat 抓下來的真回應形狀(narrative 真的是空字串)\nconst REAL = {\n route: 'graph', vector_used: false, libraries_considered: 8,\n libraries: [{ library: 'testkb', score: 1.69, via: 'graph', matched_entities: ['Arcrun124驗證卡'] }],\n indexes_read: [\n { library: 'general', narrative: '', selected: false, top_entities: [], triplet_count: 0, entry_count: 100 },\n { library: 'testkb', narrative: '', selected: true, top_entities: ['Arcrun124驗證卡'], triplet_count: 4, entry_count: 9 },\n { library: 'kb', narrative: '', selected: false, top_entities: ['knowledge-base'], triplet_count: 7, entry_count: 16 }\n ],\n pages_read: [{ page: 'Arcrun124驗證卡', library: 'testkb', chars: 231, source: 'kb://test/arcrun-124-verify.md#0' }]\n};\n\n// ① 層級=leo 畫的那張:搜尋詞 → 命中子庫 → 索引敘事 → 原文片段\nconst tree = fn.retrievalTreeData('Arcrun124驗證卡是什麼?', REAL);\nt('第 1 層是搜尋詞', txt(tree).indexOf('Arcrun124驗證卡是什麼?') === 0, txt(tree));\nconst lib = tree.children[0];\nt('第 2 層是命中子庫(帶分數與命中實體)', /testkb/.test(txt(lib)) && /1\\.69/.test(txt(lib)) && /命中實體/.test(txt(lib)), txt(lib));\nconst idx = lib.children[0];\nt('第 3 層是該子庫的索引敘事', /三元組/.test(txt(idx)) && /筆條目/.test(txt(idx)), txt(idx));\nconst page = idx.children[0];\nt('第 4 層是原文片段(掛在索引敘事底下)', /Arcrun124驗證卡/.test(txt(page)) && /231 字/.test(txt(page)), txt(page));\nt('原文片段帶資料夾麵包屑', /test arcrun-124-verify\\.md/.test(txt(page)), txt(page));\n\n// ② narrative 是空字串時不假裝有敘事(線上真資料就是這樣)\nt('沒有敘事就說沒有,不留空白', /索引沒有敘事/.test(txt(idx)), txt(idx));\n\n// ③ 沒被選用的子庫不可以被吞掉,但要收合起來不擠掉主線\nconst rest = tree.children[tree.children.length - 1];\nt('沒讀原文的子庫收在一個節點底下', /考慮過但沒讀原文(2 個子庫)/.test(txt(rest)), txt(rest));\nt('那個節點預設收合', rest.payload && rest.payload.fold === 1, JSON.stringify(rest.payload));\nt('主線只有命中的子庫', tree.children.length === 2, `實得 ${tree.children.length} 條分支`);\n\n// ④ 讀了原文、但沒出現在 libraries[] 的子庫(route=all)也要長出來\nconst allRoute = fn.retrievalTreeData('問句', {\n route: 'all', libraries: [], indexes_read: [],\n pages_read: [{ page: 'P', library: 'kb', chars: 10, source: 'kb://a/b/c.md#2' }]\n});\nt('route=all 時仍有子庫分支', allRoute.children.length === 1 && /kb/.test(txt(allRoute.children[0])), txt(allRoute.children[0]));\nt('沒有索引敘事時不生假的中間層', /^P/.test(txt(allRoute.children[0].children[0])), txt(allRoute.children[0].children[0]));\n\n// ⑤ 完全沒資料時不要生一棵空樹\nconst empty = fn.retrievalTreeData('問句', { route: 'all', libraries: [], indexes_read: [], pages_read: [] });\nt('沒有任何子庫時說明原因', /全庫作答|沒有回報/.test(txt(empty.children[0])), txt(empty.children[0]));\n\n// ⑥ 麵包屑:資料夾可以有很多層,全部拆開;機器那一層現在是「沒有」\nconst c = fn.srcCrumbs('kb://RFP/2026/design.md#3', 'kb');\nt('多層資料夾全部拆開', JSON.stringify(c.dirs) === '[\"RFP\",\"2026\"]', JSON.stringify(c.dirs));\nt('檔名拆得出來', c.file === 'design.md', c.file);\nt('片段編號拆得出來', c.frag === '3', c.frag);\nt('子庫帶得進來', c.library === 'kb', c.library);\nt('機器那一層是 null(資料裡真的沒有)', c.machine === null, String(c.machine));\nt('相對路徑原樣留著(複製給用戶去本機找)', c.path === 'RFP/2026/design.md', c.path);\n\nconst g = fn.srcCrumbs('gitea:Leo/InkStoneCo@wiki/x.md#1', 'kb');\nt('非 kb:// 來源不硬拆成假麵包屑', g.path === '' && g.file === '' && g.dirs.length === 0, JSON.stringify(g));\n\n// ⑦ markmap 載不進來時的退路:同一份樹資料畫成巢狀清單\nconst list = fn.treeListHtml(tree);\nt('退路是巢狀清單', /<ul class=\"tracelist\">/.test(list) && (list.match(/<ul/g) || []).length >= 3, String((list.match(/<ul/g) || []).length));\nt('退路裡看得到原文片段', /arcrun-124-verify\\.md/.test(list));\n\n// ⑧ 框高是「算」出來的(畫完再量 DOM 兩種量法都不可靠,見 renderTree 註解)\nt('收合的節點只算一列', fn.visibleLeaves(rest) === 1, String(fn.visibleLeaves(rest)));\nt('整棵樹的列數=展開狀態下的葉子數', fn.visibleLeaves(tree) === 2, String(fn.visibleLeaves(tree)));\nt('單一節點也算一列(不會回 0 把框壓扁)', fn.visibleLeaves({ content: 'x', children: [] }) === 1);\n\n// ⑨ 機器那一層(inkstone/mira#6 補上的兩格:machine=比對鍵、machine_label=顯示名)\nconst withM = fn.srcCrumbs('kb://RFP/daemon-真機驗收.md#0', 'mira6-watch',\n { machine: 'youlinhsieh@Leo-MBA', machine_label: '教育部 Leo 的 Mac' });\nt('有機器就拿顯示名', withM.machineLabel === '教育部 Leo 的 Mac', String(withM.machineLabel));\nt('比對鍵原樣留著(樹上分支要用它當 key', withM.machine === 'youlinhsieh@Leo-MBA', String(withM.machine));\nt('機器名沒有混進路徑', withM.path === 'RFP/daemon-真機驗收.md' && withM.dirs.join('/') === 'RFP', withM.path);\n\nconst onlyKey = fn.srcCrumbs('kb://a/b.md#0', 'lib', { machine: 'u@Host' });\nt('只有比對鍵沒有顯示名 → 顯示名退回比對鍵', onlyKey.machineLabel === 'u@Host', String(onlyKey.machineLabel));\n\nconst noM = fn.srcCrumbs('kb://a/b.md#0', 'lib', {});\nt('舊資料沒有這兩格 → machine 是 null(畫面顯示未知來源)', noM.machine === null && noM.machineLabel === null, JSON.stringify(noM.machine));\nconst emptyM = fn.srcCrumbs('kb://a/b.md#0', 'lib', { machine: '', machine_label: '' });\nt('空字串一律當沒有,不顯示成空白機器', emptyM.machine === null && emptyM.machineLabel === null, JSON.stringify(emptyM));\n\n// 同一個相對路徑來自兩台機器 → 樹上要是兩支,不可以被併成一支\nconst twoMachines = fn.retrievalTreeData('問句', { route: 'graph',\n libraries: [{ library: 'mira6-watch', score: 2.1, via: 'graph', matched_entities: ['x'] }],\n indexes_read: [{ library: 'mira6-watch', narrative: '', selected: true, triplet_count: 1, entry_count: 2 }],\n pages_read: [\n { page: 'P', library: 'mira6-watch', chars: 10, source: 'kb://RFP/same.md#0', machine: 'u@Leo-MBA', machine_label: 'Leo 的 Mac' },\n { page: 'P', library: 'mira6-watch', chars: 10, source: 'kb://RFP/same.md#0', machine: 'u@Leo-iMac', machine_label: 'Leo 的 iMac' } ] });\nconst pageNodes = twoMachines.children[0].children[0].children;\nt('同路徑不同機器=兩支,不被併掉', pageNodes.length === 2, String(pageNodes.length));\nt('兩支各自標出自己的機器',\n /Leo 的 Mac/.test(pageNodes[0].content) && /Leo 的 iMac/.test(pageNodes[1].content),\n txt(pageNodes[0]) + ' ' + txt(pageNodes[1]));\nconst noMachinePage = fn.retrievalTreeData('問句', { route: 'graph', libraries: [], indexes_read: [],\n pages_read: [{ page: 'P', library: 'kb', chars: 1, source: 'kb://a.md#0' }] });\nt('沒有機器的片段標「未知來源」,不留空', /未知來源/.test(noMachinePage.children[0].children[0].content));\n\n// ⑩ 同一台機器只能有一個顯示名(youlin stage 2026-08-18 實測到的真實情況:\n// 同一把 youlinhsieh@Leo-MBA,改名前那筆 label 就是 ID 本身,改名後是「教育部 Leo 的 Mac」)\nconst REALPAIR = [\n { page: '資料夾總覽:mira6-watch', library: 'mira6-watch', chars: 40, source: 'kb://x.md#0',\n machine: 'youlinhsieh@Leo-MBA', machine_label: 'youlinhsieh@Leo-MBA' },\n { page: 'daemon-真機驗收', library: 'mira6-watch', chars: 93, source: 'kb://RFP/daemon.md#0',\n machine: 'youlinhsieh@Leo-MBA', machine_label: '教育部 Leo 的 Mac' }\n];\nconst lb = fn.machineLabelMap(REALPAIR);\nt('有人取過名字就全篇用那個名字', lb['youlinhsieh@Leo-MBA'] === '教育部 Leo 的 Mac', JSON.stringify(lb));\nt('舊那筆也跟著顯示成新名字(同一台不會長成兩台)',\n fn.srcCrumbs('kb://x.md#0', 'mira6-watch', REALPAIR[0], lb).machineLabel === '教育部 Leo 的 Mac');\nt('比對鍵不受顯示名影響', fn.srcCrumbs('kb://x.md#0', 'mira6-watch', REALPAIR[0], lb).machine === 'youlinhsieh@Leo-MBA');\nt('誰都沒取過名字 → 退回顯示 ID', fn.machineLabelMap([{ machine: 'u@H', machine_label: 'u@H' }])['u@H'] === 'u@H');\nt('兩台不同機器不會被併成一個名字',\n Object.keys(fn.machineLabelMap([{ machine: 'a@X', machine_label: 'X 機' }, { machine: 'b@Y', machine_label: 'Y 機' }])).length === 2);\n\nconst treeReal = fn.retrievalTreeData('問句', { route: 'graph',\n libraries: [{ library: 'mira6-watch', score: 2.1, via: 'graph', matched_entities: ['x'] }],\n indexes_read: [{ library: 'mira6-watch', narrative: '', selected: true, triplet_count: 1, entry_count: 2 }],\n pages_read: REALPAIR });\nconst both = treeReal.children[0].children[0].children.map(n => n.content).join(' ');\nt('樹上兩個片段標的是同一個機器名', (both.match(/教育部 Leo 的 Mac/g) || []).length === 2, both.slice(0, 200));\n\nconsole.log(`\\n=== ${pass} passed, ${fail} failed ===`);\nprocess.exit(fail ? 1 : 0);\n"},"/portal/safejson.test.mjs":{"type":"application/javascript; charset=utf-8","b64":false,"data":"import fs from 'node:fs';\nconst html = fs.readFileSync(new URL('./index.html', import.meta.url).pathname,'utf8');\n\n// 抽出 safeJson 與 friendlyErr 求值\nconst grab = (name) => {\n const i = html.indexOf(`function ${name}(`);\n if (i < 0) throw new Error(`找不到 ${name}`);\n let d=0, j=html.indexOf('{', i);\n for (let k=j;k<html.length;k++){ if(html[k]==='{')d++; if(html[k]==='}'){d--; if(!d){ return html.slice(i,k+1);} } }\n throw new Error('括號不平衡');\n};\nconst fn = new Function(grab('safeJson') + '\\n' + grab('friendlyErr') + '\\nreturn {safeJson, friendlyErr};')();\n\nlet pass=0, fail=0;\nconst t=(l,c,e='')=>{c?(console.log('PASS:',l),pass++):(console.log('FAIL:',l,e),fail++)};\n\n// ① safeJson:非 JSON 不可拋例外(同事撞到的 404 HTML 頁)\nconst html404 = '<!DOCTYPE html><html><body>404 Not Found</body></html>';\nawait fn.safeJson({ text: () => Promise.resolve(html404) })\n .then(d => t('404 HTML → 回空物件不拋錯', typeof d === 'object' && d !== null))\n .catch(e => t('404 HTML → 不該拋錯', false, e.message));\n\nawait fn.safeJson({ text: () => Promise.resolve('') })\n .then(d => t('空回應 → 回空物件', JSON.stringify(d)==='{}'))\n .catch(() => t('空回應 → 不該拋錯', false));\n\nawait fn.safeJson({ text: () => Promise.resolve('{\"error\":\"帳號或密碼不對\"}') })\n .then(d => t('正常 JSON 仍要解析得出來', d.error === '帳號或密碼不對'), )\n .catch(() => t('正常 JSON 不該拋錯', false));\n\n// ② friendlyErr:不可把技術訊息噴給使用者\nconst leak = fn.friendlyErr(new Error('Unexpected non-whitespace character after JSON at position 4'));\nt('JSON 錯誤 → 不外洩原文', !/JSON|position/i.test(leak), `實得: ${leak}`);\nt('JSON 錯誤 → 說人話', /伺服器回應異常/.test(leak), `實得: ${leak}`);\n\nconst net = fn.friendlyErr(new Error('Failed to fetch'));\nt('網路錯誤 → 既有訊息保留', /連線中斷/.test(net), `實得: ${net}`);\n\nconst ours = fn.friendlyErr(new Error('帳號或密碼不對——用你在知識庫網站設定的那組'));\nt('我們自己的中文訊息 → 原樣顯示', /帳號或密碼不對/.test(ours), `實得: ${ours}`);\n\nconst stack = fn.friendlyErr(new Error('TypeError: Cannot read properties of undefined'));\nt('英文技術訊息 → 收斂不外洩', !/TypeError|undefined/.test(stack), `實得: ${stack}`);\n\nconsole.log(`\\n=== ${pass} passed, ${fail} failed ===`);\nprocess.exit(fail?1:0);\n"},"/portal/tree-links.test.mjs":{"type":"application/javascript; charset=utf-8","b64":false,"data":"// 樹狀圖的**線型**測試(InkStoneCo#44 第三輪,leo 2026-08-18\n// 「線型可以改成類似 terminal tree 那樣往右、往下展開的 L 型折線,線的色彩不要花花綠綠」)。\n//\n// 為什麼這個要測,而 markmap 的佈局不測(D97「畫圖是現成函式庫的事」):\n// 折線的座標換算是**我們自己寫的那一段**——markmap 交出曲線 `d`,我們把它改寫成 L 型。\n// 換算錯了畫面只會「線歪掉」,不會報錯,靠眼睛看很容易漏。\n// 跑法:node console-ui/public/portal/tree-links.test.mjs\nimport fs from 'node:fs';\nconst html = fs.readFileSync(new URL('./index.html', import.meta.url).pathname, 'utf8');\n\nconst grab = (name) => {\n const i = html.indexOf(`function ${name}(`);\n if (i < 0) throw new Error(`找不到 ${name}`);\n let d = 0;\n for (let k = html.indexOf('{', i); k < html.length; k++) { if (html[k] === '{') d++; if (html[k] === '}') { d--; if (!d) return html.slice(i, k + 1); } }\n throw new Error('括號不平衡');\n};\nconst fn = new Function(['elbowPath', 'elbowFromCurve'].map(grab).join('\\n')\n + '\\nreturn { elbowPath, elbowFromCurve };')();\n\nlet pass = 0, fail = 0;\nconst t = (l, c, e = '') => { c ? (console.log('PASS:', l), pass++) : (console.log('FAIL:', l, e), fail++); };\n\n// ① 折線只由 M/L 組成——沒有任何曲線指令。這同時是「已經改過了」的判斷依據,\n// 所以它壞掉不只是變醜,是會無限重寫。\nconst down = fn.elbowPath(100, 50, 152, 120);\nt('往下的連線是 L 型折線,只有 M/L', /^M[\\d.,-]+(L[\\d.,-]+){3}$/.test(down), down);\nt('折線不含任何曲線指令(C/S/Q/A', !/[CSQAcsqa]/.test(down), down);\n\n// ② 轉折點:先往右 12px、再垂直、最後水平接進子節點 ⇒ 兩個直角\nt('起點是父節點右緣', down.startsWith('M100,50'), down);\nt('第一段水平:往右 12px 到幹線', down.indexOf('L112,50') > 0, down);\nt('第二段垂直:幹線 x 不變、y 換到子節點那列', down.indexOf('L112,120') > 0, down);\nt('第三段水平:接進子節點左緣', down.endsWith('L152,120'), down);\n\n// ③ 同一個父節點的所有子節點共用同一條垂直幹線(起點相同 ⇒ 轉折 x 相同)\nconst up = fn.elbowPath(100, 50, 152, -20);\nt('往上的子節點用同一條幹線 x=112', up.indexOf('L112,50') > 0 && up.indexOf('L112,-20') > 0, up);\n\n// ④ 父子同一列時不要硬折一個看不見的直角,畫一條直線就好\nconst flat = fn.elbowPath(100, 50, 152, 50);\nt('同一列=一條直線(兩段)', flat === 'M100,50L152,50', flat);\n\n// ⑤ 框很窄/間距被壓縮時,幹線不可以跑到子節點右邊(會變成往回折的怪線)\nconst tight = fn.elbowPath(100, 50, 104, 120);\nt('間距 < 12 時幹線收回到子節點左緣', tight.indexOf('L104,50L104,120') > 0, tight);\n\n// ⑥ 吃得下 markmap 真的吐出來的 bumpX 字串(d3 linkHorizontal + bumpX 的格式)\nconst real = fn.elbowFromCurve('M100,50C126,50,126,120,152,120');\nt('bumpX 曲線 → 折線(只取頭尾兩點,控制點丟掉)', real === 'M100,50L112,50L112,120L152,120', real);\n\n// ⑦ 已經是折線的就不要再動——不然 observer 改寫→再觸發→再改寫,會轉不停\nt('已經是折線 ⇒ 回 null(不重寫)', fn.elbowFromCurve(real) === null, String(fn.elbowFromCurve(real)));\nt('空字串 ⇒ 回 null', fn.elbowFromCurve('') === null);\nt('認不得的 d ⇒ 回 null,不亂畫', fn.elbowFromCurve('C') === null);\n\n// ⑧ 小數座標(markmap 的佈局會給小數)不要吐出一長串尾數\nconst frac = fn.elbowPath(100.123456, 50.987654, 152.5, 120.25);\nt('座標四捨五入到小數兩位', frac === 'M100.12,50.99L112.12,50.99L112.12,120.25L152.5,120.25', frac);\n\nconsole.log(`\\n${fail ? '❌' : '✅'} ${pass} passed, ${fail} failed`);\nprocess.exit(fail ? 1 : 0);\n"},"/portal/vendor/markmap-view.min.js":{"type":"application/javascript; charset=utf-8","b64":false,"data":"(()=>{var ki=\"npm2url/dist/index.cjs\",Si={jsdelivr:t=>`https://cdn.jsdelivr.net/npm/${t}`,unpkg:t=>`https://unpkg.com/${t}`};async function Ei(t,e){let r=await fetch(t,{signal:e});if(!r.ok)throw r;await r.text()}var Ce=class{constructor(){this.providers={...Si},this.provider=\"jsdelivr\"}async getFastestProvider(e=5e3,r=ki){let n=new AbortController,i=0;try{return await new Promise((o,a)=>{Promise.all(Object.entries(this.providers).map(async([s,l])=>{try{await Ei(l(r),n.signal),o(s)}catch{}})).then(()=>a(new Error(\"All providers failed\"))),i=setTimeout(a,e,new Error(\"Timed out\"))})}finally{n.abort(),clearTimeout(i)}}async findFastestProvider(e,r){return this.provider=await this.getFastestProvider(e,r),this.provider}setProvider(e,r){r?this.providers[e]=r:delete this.providers[e]}getFullUrl(e,r=this.provider){if(e.includes(\"://\"))return e;let n=this.providers[r];if(!n)throw new Error(`Provider ${r} not found`);return n(e)}},Gs=new Ce,Vt=class{constructor(){this.listeners=[]}tap(e){return this.listeners.push(e),()=>this.revoke(e)}revoke(e){let r=this.listeners.indexOf(e);r>=0&&this.listeners.splice(r,1)}revokeAll(){this.listeners.splice(0)}call(...e){for(let r of this.listeners)r(...e)}};var Ci=Math.random().toString(36).slice(2,8),sr=0;function ur(){return sr+=1,`mm-${Ci}-${sr}`}function kt(){}function St(t,e){let r=(n,i)=>e(n,()=>{var o;return(o=n.children)==null?void 0:o.map(a=>r(a,n))},i);return r(t)}function fr(t,...e){let r=(t||\"\").split(\" \").filter(Boolean);return e.forEach(n=>{n&&r.indexOf(n)<0&&r.push(n)}),r.join(\" \")}function Ai(t){let e={};return function(...n){let i=`${n[0]}`,o=e[i];return o||(o={value:t(...n)},e[i]=o),o.value}}function cr(t,e){let r={timer:0};function n(){r.timer&&(window.clearTimeout(r.timer),r.timer=0)}function i(){n(),r.args&&(r.result=t(...r.args))}return function(...a){return n(),r.args=a,r.timer=window.setTimeout(i,e),r.result}}var hr=1,pr=2,zi=\"http://www.w3.org/2000/svg\",Ee=\"http://www.w3.org/1999/xlink\",$i={show:Ee,actuate:Ee,href:Ee},Ti=t=>typeof t==\"string\"||typeof t==\"number\",Oi=t=>(t==null?void 0:t.vtype)===hr,Mi=t=>(t==null?void 0:t.vtype)===pr;function Ii(t,e,...r){return e=Object.assign({},e,{children:r.length===1?r[0]:r}),Ri(t,e)}function Ri(t,e){let r;if(typeof t==\"string\")r=hr;else if(typeof t==\"function\")r=pr;else throw new Error(\"Invalid VNode type\");return{vtype:r,type:t,props:e}}function Ni(t){return t.children}var Pi={isSvg:!1};function lr(t,e){Array.isArray(e)||(e=[e]),e=e.filter(Boolean),e.length&&t.append(...e)}function Bi(t,e,r){for(let n in e)if(!(n===\"key\"||n===\"children\"||n===\"ref\"))if(n===\"dangerouslySetInnerHTML\")t.innerHTML=e[n].__html;else if(n===\"innerHTML\"||n===\"textContent\"||n===\"innerText\"||n===\"value\"&&[\"textarea\",\"select\"].includes(t.tagName)){let i=e[n];i!=null&&(t[n]=i)}else n.startsWith(\"on\")?t[n.toLowerCase()]=e[n]:Di(t,n,e[n],r.isSvg)}var Xi={className:\"class\",labelFor:\"for\"};function Di(t,e,r,n){if(e=Xi[e]||e,r===!0)t.setAttribute(e,\"\");else if(r===!1)t.removeAttribute(e);else{let i=n?$i[e]:void 0;i!==void 0?t.setAttributeNS(i,e,r):t.setAttribute(e,r)}}function qi(t){return t.reduce((e,r)=>e.concat(r),[])}function Ae(t,e){return Array.isArray(t)?qi(t.map(r=>Ae(r,e))):ze(t,e)}function ze(t,e=Pi){if(t==null||typeof t==\"boolean\")return null;if(t instanceof Node)return t;if(Mi(t)){let{type:r,props:n}=t;if(r===Ni){let o=document.createDocumentFragment();if(n.children){let a=Ae(n.children,e);lr(o,a)}return o}let i=r(n);return ze(i,e)}if(Ti(t))return document.createTextNode(`${t}`);if(Oi(t)){let r,{type:n,props:i}=t;if(!e.isSvg&&n===\"svg\"&&(e=Object.assign({},e,{isSvg:!0})),e.isSvg?r=document.createElementNS(zi,n):r=document.createElement(n),Bi(r,i,e),i.children){let a=e;e.isSvg&&n===\"foreignObject\"&&(a=Object.assign({},a,{isSvg:!1}));let s=Ae(i.children,a);s!=null&&lr(r,s)}let{ref:o}=i;return typeof o==\"function\"&&o(r),r}throw new Error(\"mount: Invalid Vnode!\")}function Li(t){return ze(t)}function Yi(...t){return Li(Ii(...t))}var Ws=Ai(t=>{document.head.append(Yi(\"link\",{rel:\"preload\",as:\"script\",href:t}))});var mt=class extends Map{constructor(e,r=Vi){if(super(),Object.defineProperties(this,{_intern:{value:new Map},_key:{value:r}}),e!=null)for(let[n,i]of e)this.set(n,i)}get(e){return super.get(dr(this,e))}has(e){return super.has(dr(this,e))}set(e,r){return super.set(Fi(this,e),r)}delete(e){return super.delete(Hi(this,e))}};function dr({_intern:t,_key:e},r){let n=e(r);return t.has(n)?t.get(n):r}function Fi({_intern:t,_key:e},r){let n=e(r);return t.has(n)?t.get(n):(t.set(n,r),r)}function Hi({_intern:t,_key:e},r){let n=e(r);return t.has(n)&&(r=t.get(n),t.delete(n)),r}function Vi(t){return t!==null&&typeof t==\"object\"?t.valueOf():t}function Et(t,e){let r;if(e===void 0)for(let n of t)n!=null&&(r<n||r===void 0&&n>=n)&&(r=n);else{let n=-1;for(let i of t)(i=e(i,++n,t))!=null&&(r<i||r===void 0&&i>=i)&&(r=i)}return r}function Ct(t,e){let r;if(e===void 0)for(let n of t)n!=null&&(r>n||r===void 0&&n>=n)&&(r=n);else{let n=-1;for(let i of t)(i=e(i,++n,t))!=null&&(r>i||r===void 0&&i>=i)&&(r=i)}return r}function Gt(t,e){let r,n=-1,i=-1;if(e===void 0)for(let o of t)++i,o!=null&&(r>o||r===void 0&&o>=o)&&(r=o,n=i);else for(let o of t)(o=e(o,++i,t))!=null&&(r>o||r===void 0&&o>=o)&&(r=o,n=i);return n}var Gi={value:()=>{}};function xr(){for(var t=0,e=arguments.length,r={},n;t<e;++t){if(!(n=arguments[t]+\"\")||n in r||/[\\s.]/.test(n))throw new Error(\"illegal type: \"+n);r[n]=[]}return new Wt(r)}function Wt(t){this._=t}function Wi(t,e){return t.trim().split(/^|\\s+/).map(function(r){var n=\"\",i=r.indexOf(\".\");if(i>=0&&(n=r.slice(i+1),r=r.slice(0,i)),r&&!e.hasOwnProperty(r))throw new Error(\"unknown type: \"+r);return{type:r,name:n}})}Wt.prototype=xr.prototype={constructor:Wt,on:function(t,e){var r=this._,n=Wi(t+\"\",r),i,o=-1,a=n.length;if(arguments.length<2){for(;++o<a;)if((i=(t=n[o]).type)&&(i=Ki(r[i],t.name)))return i;return}if(e!=null&&typeof e!=\"function\")throw new Error(\"invalid callback: \"+e);for(;++o<a;)if(i=(t=n[o]).type)r[i]=mr(r[i],t.name,e);else if(e==null)for(i in r)r[i]=mr(r[i],t.name,null);return this},copy:function(){var t={},e=this._;for(var r in e)t[r]=e[r].slice();return new Wt(t)},call:function(t,e){if((i=arguments.length-2)>0)for(var r=new Array(i),n=0,i,o;n<i;++n)r[n]=arguments[n+2];if(!this._.hasOwnProperty(t))throw new Error(\"unknown type: \"+t);for(o=this._[t],n=0,i=o.length;n<i;++n)o[n].value.apply(e,r)},apply:function(t,e,r){if(!this._.hasOwnProperty(t))throw new Error(\"unknown type: \"+t);for(var n=this._[t],i=0,o=n.length;i<o;++i)n[i].value.apply(e,r)}};function Ki(t,e){for(var r=0,n=t.length,i;r<n;++r)if((i=t[r]).name===e)return i.value}function mr(t,e,r){for(var n=0,i=t.length;n<i;++n)if(t[n].name===e){t[n]=Gi,t=t.slice(0,n).concat(t.slice(n+1));break}return r!=null&&t.push({name:e,value:r}),t}var At=xr;var Kt=\"http://www.w3.org/1999/xhtml\",$e={svg:\"http://www.w3.org/2000/svg\",xhtml:Kt,xlink:\"http://www.w3.org/1999/xlink\",xml:\"http://www.w3.org/XML/1998/namespace\",xmlns:\"http://www.w3.org/2000/xmlns/\"};function Q(t){var e=t+=\"\",r=e.indexOf(\":\");return r>=0&&(e=t.slice(0,r))!==\"xmlns\"&&(t=t.slice(r+1)),$e.hasOwnProperty(e)?{space:$e[e],local:t}:t}function Ui(t){return function(){var e=this.ownerDocument,r=this.namespaceURI;return r===Kt&&e.documentElement.namespaceURI===Kt?e.createElement(t):e.createElementNS(r,t)}}function Qi(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}function Ut(t){var e=Q(t);return(e.local?Qi:Ui)(e)}function Zi(){}function lt(t){return t==null?Zi:function(){return this.querySelector(t)}}function gr(t){typeof t!=\"function\"&&(t=lt(t));for(var e=this._groups,r=e.length,n=new Array(r),i=0;i<r;++i)for(var o=e[i],a=o.length,s=n[i]=new Array(a),l,u,f=0;f<a;++f)(l=o[f])&&(u=t.call(l,l.__data__,f,o))&&(\"__data__\"in l&&(u.__data__=l.__data__),s[f]=u);return new T(n,this._parents)}function Te(t){return t==null?[]:Array.isArray(t)?t:Array.from(t)}function Ji(){return[]}function zt(t){return t==null?Ji:function(){return this.querySelectorAll(t)}}function ji(t){return function(){return Te(t.apply(this,arguments))}}function yr(t){typeof t==\"function\"?t=ji(t):t=zt(t);for(var e=this._groups,r=e.length,n=[],i=[],o=0;o<r;++o)for(var a=e[o],s=a.length,l,u=0;u<s;++u)(l=a[u])&&(n.push(t.call(l,l.__data__,u,a)),i.push(l));return new T(n,i)}function $t(t){return function(){return this.matches(t)}}function Qt(t){return function(e){return e.matches(t)}}var to=Array.prototype.find;function eo(t){return function(){return to.call(this.children,t)}}function ro(){return this.firstElementChild}function vr(t){return this.select(t==null?ro:eo(typeof t==\"function\"?t:Qt(t)))}var no=Array.prototype.filter;function io(){return Array.from(this.children)}function oo(t){return function(){return no.call(this.children,t)}}function wr(t){return this.selectAll(t==null?io:oo(typeof t==\"function\"?t:Qt(t)))}function _r(t){typeof t!=\"function\"&&(t=$t(t));for(var e=this._groups,r=e.length,n=new Array(r),i=0;i<r;++i)for(var o=e[i],a=o.length,s=n[i]=[],l,u=0;u<a;++u)(l=o[u])&&t.call(l,l.__data__,u,o)&&s.push(l);return new T(n,this._parents)}function Zt(t){return new Array(t.length)}function br(){return new T(this._enter||this._groups.map(Zt),this._parents)}function Tt(t,e){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=e}Tt.prototype={constructor:Tt,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,e){return this._parent.insertBefore(t,e)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};function kr(t){return function(){return t}}function ao(t,e,r,n,i,o){for(var a=0,s,l=e.length,u=o.length;a<u;++a)(s=e[a])?(s.__data__=o[a],n[a]=s):r[a]=new Tt(t,o[a]);for(;a<l;++a)(s=e[a])&&(i[a]=s)}function so(t,e,r,n,i,o,a){var s,l,u=new Map,f=e.length,p=o.length,d=new Array(f),x;for(s=0;s<f;++s)(l=e[s])&&(d[s]=x=a.call(l,l.__data__,s,e)+\"\",u.has(x)?i[s]=l:u.set(x,l));for(s=0;s<p;++s)x=a.call(t,o[s],s,o)+\"\",(l=u.get(x))?(n[s]=l,l.__data__=o[s],u.delete(x)):r[s]=new Tt(t,o[s]);for(s=0;s<f;++s)(l=e[s])&&u.get(d[s])===l&&(i[s]=l)}function lo(t){return t.__data__}function Sr(t,e){if(!arguments.length)return Array.from(this,lo);var r=e?so:ao,n=this._parents,i=this._groups;typeof t!=\"function\"&&(t=kr(t));for(var o=i.length,a=new Array(o),s=new Array(o),l=new Array(o),u=0;u<o;++u){var f=n[u],p=i[u],d=p.length,x=uo(t.call(f,f&&f.__data__,u,n)),_=x.length,b=s[u]=new Array(_),A=a[u]=new Array(_),g=l[u]=new Array(d);r(f,p,b,A,g,x,e);for(var $=0,O=0,M,I;$<_;++$)if(M=b[$]){for($>=O&&(O=$+1);!(I=A[O])&&++O<_;);M._next=I||null}}return a=new T(a,n),a._enter=s,a._exit=l,a}function uo(t){return typeof t==\"object\"&&\"length\"in t?t:Array.from(t)}function Er(){return new T(this._exit||this._groups.map(Zt),this._parents)}function Cr(t,e,r){var n=this.enter(),i=this,o=this.exit();return typeof t==\"function\"?(n=t(n),n&&(n=n.selection())):n=n.append(t+\"\"),e!=null&&(i=e(i),i&&(i=i.selection())),r==null?o.remove():r(o),n&&i?n.merge(i).order():i}function Ar(t){for(var e=t.selection?t.selection():t,r=this._groups,n=e._groups,i=r.length,o=n.length,a=Math.min(i,o),s=new Array(i),l=0;l<a;++l)for(var u=r[l],f=n[l],p=u.length,d=s[l]=new Array(p),x,_=0;_<p;++_)(x=u[_]||f[_])&&(d[_]=x);for(;l<i;++l)s[l]=r[l];return new T(s,this._parents)}function zr(){for(var t=this._groups,e=-1,r=t.length;++e<r;)for(var n=t[e],i=n.length-1,o=n[i],a;--i>=0;)(a=n[i])&&(o&&a.compareDocumentPosition(o)^4&&o.parentNode.insertBefore(a,o),o=a);return this}function $r(t){t||(t=fo);function e(p,d){return p&&d?t(p.__data__,d.__data__):!p-!d}for(var r=this._groups,n=r.length,i=new Array(n),o=0;o<n;++o){for(var a=r[o],s=a.length,l=i[o]=new Array(s),u,f=0;f<s;++f)(u=a[f])&&(l[f]=u);l.sort(e)}return new T(i,this._parents).order()}function fo(t,e){return t<e?-1:t>e?1:t>=e?0:NaN}function Tr(){var t=arguments[0];return arguments[0]=this,t.apply(null,arguments),this}function Or(){return Array.from(this)}function Mr(){for(var t=this._groups,e=0,r=t.length;e<r;++e)for(var n=t[e],i=0,o=n.length;i<o;++i){var a=n[i];if(a)return a}return null}function Ir(){let t=0;for(let e of this)++t;return t}function Rr(){return!this.node()}function Nr(t){for(var e=this._groups,r=0,n=e.length;r<n;++r)for(var i=e[r],o=0,a=i.length,s;o<a;++o)(s=i[o])&&t.call(s,s.__data__,o,i);return this}function co(t){return function(){this.removeAttribute(t)}}function ho(t){return function(){this.removeAttributeNS(t.space,t.local)}}function po(t,e){return function(){this.setAttribute(t,e)}}function mo(t,e){return function(){this.setAttributeNS(t.space,t.local,e)}}function xo(t,e){return function(){var r=e.apply(this,arguments);r==null?this.removeAttribute(t):this.setAttribute(t,r)}}function go(t,e){return function(){var r=e.apply(this,arguments);r==null?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,r)}}function Pr(t,e){var r=Q(t);if(arguments.length<2){var n=this.node();return r.local?n.getAttributeNS(r.space,r.local):n.getAttribute(r)}return this.each((e==null?r.local?ho:co:typeof e==\"function\"?r.local?go:xo:r.local?mo:po)(r,e))}function Jt(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function yo(t){return function(){this.style.removeProperty(t)}}function vo(t,e,r){return function(){this.style.setProperty(t,e,r)}}function wo(t,e,r){return function(){var n=e.apply(this,arguments);n==null?this.style.removeProperty(t):this.style.setProperty(t,n,r)}}function Br(t,e,r){return arguments.length>1?this.each((e==null?yo:typeof e==\"function\"?wo:vo)(t,e,r==null?\"\":r)):et(this.node(),t)}function et(t,e){return t.style.getPropertyValue(e)||Jt(t).getComputedStyle(t,null).getPropertyValue(e)}function _o(t){return function(){delete this[t]}}function bo(t,e){return function(){this[t]=e}}function ko(t,e){return function(){var r=e.apply(this,arguments);r==null?delete this[t]:this[t]=r}}function Xr(t,e){return arguments.length>1?this.each((e==null?_o:typeof e==\"function\"?ko:bo)(t,e)):this.node()[t]}function Dr(t){return t.trim().split(/^|\\s+/)}function Oe(t){return t.classList||new qr(t)}function qr(t){this._node=t,this._names=Dr(t.getAttribute(\"class\")||\"\")}qr.prototype={add:function(t){var e=this._names.indexOf(t);e<0&&(this._names.push(t),this._node.setAttribute(\"class\",this._names.join(\" \")))},remove:function(t){var e=this._names.indexOf(t);e>=0&&(this._names.splice(e,1),this._node.setAttribute(\"class\",this._names.join(\" \")))},contains:function(t){return this._names.indexOf(t)>=0}};function Lr(t,e){for(var r=Oe(t),n=-1,i=e.length;++n<i;)r.add(e[n])}function Yr(t,e){for(var r=Oe(t),n=-1,i=e.length;++n<i;)r.remove(e[n])}function So(t){return function(){Lr(this,t)}}function Eo(t){return function(){Yr(this,t)}}function Co(t,e){return function(){(e.apply(this,arguments)?Lr:Yr)(this,t)}}function Fr(t,e){var r=Dr(t+\"\");if(arguments.length<2){for(var n=Oe(this.node()),i=-1,o=r.length;++i<o;)if(!n.contains(r[i]))return!1;return!0}return this.each((typeof e==\"function\"?Co:e?So:Eo)(r,e))}function Ao(){this.textContent=\"\"}function zo(t){return function(){this.textContent=t}}function $o(t){return function(){var e=t.apply(this,arguments);this.textContent=e==null?\"\":e}}function Hr(t){return arguments.length?this.each(t==null?Ao:(typeof t==\"function\"?$o:zo)(t)):this.node().textContent}function To(){this.innerHTML=\"\"}function Oo(t){return function(){this.innerHTML=t}}function Mo(t){return function(){var e=t.apply(this,arguments);this.innerHTML=e==null?\"\":e}}function Vr(t){return arguments.length?this.each(t==null?To:(typeof t==\"function\"?Mo:Oo)(t)):this.node().innerHTML}function Io(){this.nextSibling&&this.parentNode.appendChild(this)}function Gr(){return this.each(Io)}function Ro(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function Wr(){return this.each(Ro)}function Kr(t){var e=typeof t==\"function\"?t:Ut(t);return this.select(function(){return this.appendChild(e.apply(this,arguments))})}function No(){return null}function Ur(t,e){var r=typeof t==\"function\"?t:Ut(t),n=e==null?No:typeof e==\"function\"?e:lt(e);return this.select(function(){return this.insertBefore(r.apply(this,arguments),n.apply(this,arguments)||null)})}function Po(){var t=this.parentNode;t&&t.removeChild(this)}function Qr(){return this.each(Po)}function Bo(){var t=this.cloneNode(!1),e=this.parentNode;return e?e.insertBefore(t,this.nextSibling):t}function Xo(){var t=this.cloneNode(!0),e=this.parentNode;return e?e.insertBefore(t,this.nextSibling):t}function Zr(t){return this.select(t?Xo:Bo)}function Jr(t){return arguments.length?this.property(\"__data__\",t):this.node().__data__}function Do(t){return function(e){t.call(this,e,this.__data__)}}function qo(t){return t.trim().split(/^|\\s+/).map(function(e){var r=\"\",n=e.indexOf(\".\");return n>=0&&(r=e.slice(n+1),e=e.slice(0,n)),{type:e,name:r}})}function Lo(t){return function(){var e=this.__on;if(e){for(var r=0,n=-1,i=e.length,o;r<i;++r)o=e[r],(!t.type||o.type===t.type)&&o.name===t.name?this.removeEventListener(o.type,o.listener,o.options):e[++n]=o;++n?e.length=n:delete this.__on}}}function Yo(t,e,r){return function(){var n=this.__on,i,o=Do(e);if(n){for(var a=0,s=n.length;a<s;++a)if((i=n[a]).type===t.type&&i.name===t.name){this.removeEventListener(i.type,i.listener,i.options),this.addEventListener(i.type,i.listener=o,i.options=r),i.value=e;return}}this.addEventListener(t.type,o,r),i={type:t.type,name:t.name,value:e,listener:o,options:r},n?n.push(i):this.__on=[i]}}function jr(t,e,r){var n=qo(t+\"\"),i,o=n.length,a;if(arguments.length<2){var s=this.node().__on;if(s){for(var l=0,u=s.length,f;l<u;++l)for(i=0,f=s[l];i<o;++i)if((a=n[i]).type===f.type&&a.name===f.name)return f.value}return}for(s=e?Yo:Lo,i=0;i<o;++i)this.each(s(n[i],e,r));return this}function tn(t,e,r){var n=Jt(t),i=n.CustomEvent;typeof i==\"function\"?i=new i(e,r):(i=n.document.createEvent(\"Event\"),r?(i.initEvent(e,r.bubbles,r.cancelable),i.detail=r.detail):i.initEvent(e,!1,!1)),t.dispatchEvent(i)}function Fo(t,e){return function(){return tn(this,t,e)}}function Ho(t,e){return function(){return tn(this,t,e.apply(this,arguments))}}function en(t,e){return this.each((typeof e==\"function\"?Ho:Fo)(t,e))}function*rn(){for(var t=this._groups,e=0,r=t.length;e<r;++e)for(var n=t[e],i=0,o=n.length,a;i<o;++i)(a=n[i])&&(yield a)}var Me=[null];function T(t,e){this._groups=t,this._parents=e}function nn(){return new T([[document.documentElement]],Me)}function Vo(){return this}T.prototype=nn.prototype={constructor:T,select:gr,selectAll:yr,selectChild:vr,selectChildren:wr,filter:_r,data:Sr,enter:br,exit:Er,join:Cr,merge:Ar,selection:Vo,order:zr,sort:$r,call:Tr,nodes:Or,node:Mr,size:Ir,empty:Rr,each:Nr,attr:Pr,style:Br,property:Xr,classed:Fr,text:Hr,html:Vr,raise:Gr,lower:Wr,append:Kr,insert:Ur,remove:Qr,clone:Zr,datum:Jr,on:jr,dispatch:en,[Symbol.iterator]:rn};var Z=nn;function L(t){return typeof t==\"string\"?new T([[document.querySelector(t)]],[document.documentElement]):new T([[t]],Me)}function on(t){let e;for(;e=t.sourceEvent;)t=e;return t}function J(t,e){if(t=on(t),e===void 0&&(e=t.currentTarget),e){var r=e.ownerSVGElement||e;if(r.createSVGPoint){var n=r.createSVGPoint();return n.x=t.clientX,n.y=t.clientY,n=n.matrixTransform(e.getScreenCTM().inverse()),[n.x,n.y]}if(e.getBoundingClientRect){var i=e.getBoundingClientRect();return[t.clientX-i.left-e.clientLeft,t.clientY-i.top-e.clientTop]}}return[t.pageX,t.pageY]}var jt={capture:!0,passive:!1};function te(t){t.preventDefault(),t.stopImmediatePropagation()}function Ie(t){var e=t.document.documentElement,r=L(t).on(\"dragstart.drag\",te,jt);\"onselectstart\"in e?r.on(\"selectstart.drag\",te,jt):(e.__noselect=e.style.MozUserSelect,e.style.MozUserSelect=\"none\")}function Re(t,e){var r=t.document.documentElement,n=L(t).on(\"dragstart.drag\",null);e&&(n.on(\"click.drag\",te,jt),setTimeout(function(){n.on(\"click.drag\",null)},0)),\"onselectstart\"in r?n.on(\"selectstart.drag\",null):(r.style.MozUserSelect=r.__noselect,delete r.__noselect)}function ee(t,e,r){t.prototype=e.prototype=r,r.constructor=t}function Ne(t,e){var r=Object.create(t.prototype);for(var n in e)r[n]=e[n];return r}function It(){}var Ot=.7,ie=1/Ot,xt=\"\\\\s*([+-]?\\\\d+)\\\\s*\",Mt=\"\\\\s*([+-]?(?:\\\\d*\\\\.)?\\\\d+(?:[eE][+-]?\\\\d+)?)\\\\s*\",K=\"\\\\s*([+-]?(?:\\\\d*\\\\.)?\\\\d+(?:[eE][+-]?\\\\d+)?)%\\\\s*\",Go=/^#([0-9a-f]{3,8})$/,Wo=new RegExp(`^rgb\\\\(${xt},${xt},${xt}\\\\)$`),Ko=new RegExp(`^rgb\\\\(${K},${K},${K}\\\\)$`),Uo=new RegExp(`^rgba\\\\(${xt},${xt},${xt},${Mt}\\\\)$`),Qo=new RegExp(`^rgba\\\\(${K},${K},${K},${Mt}\\\\)$`),Zo=new RegExp(`^hsl\\\\(${Mt},${K},${K}\\\\)$`),Jo=new RegExp(`^hsla\\\\(${Mt},${K},${K},${Mt}\\\\)$`),an={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};ee(It,rt,{copy(t){return Object.assign(new this.constructor,this,t)},displayable(){return this.rgb().displayable()},hex:sn,formatHex:sn,formatHex8:jo,formatHsl:ta,formatRgb:ln,toString:ln});function sn(){return this.rgb().formatHex()}function jo(){return this.rgb().formatHex8()}function ta(){return dn(this).formatHsl()}function ln(){return this.rgb().formatRgb()}function rt(t){var e,r;return t=(t+\"\").trim().toLowerCase(),(e=Go.exec(t))?(r=e[1].length,e=parseInt(e[1],16),r===6?un(e):r===3?new D(e>>8&15|e>>4&240,e>>4&15|e&240,(e&15)<<4|e&15,1):r===8?re(e>>24&255,e>>16&255,e>>8&255,(e&255)/255):r===4?re(e>>12&15|e>>8&240,e>>8&15|e>>4&240,e>>4&15|e&240,((e&15)<<4|e&15)/255):null):(e=Wo.exec(t))?new D(e[1],e[2],e[3],1):(e=Ko.exec(t))?new D(e[1]*255/100,e[2]*255/100,e[3]*255/100,1):(e=Uo.exec(t))?re(e[1],e[2],e[3],e[4]):(e=Qo.exec(t))?re(e[1]*255/100,e[2]*255/100,e[3]*255/100,e[4]):(e=Zo.exec(t))?hn(e[1],e[2]/100,e[3]/100,1):(e=Jo.exec(t))?hn(e[1],e[2]/100,e[3]/100,e[4]):an.hasOwnProperty(t)?un(an[t]):t===\"transparent\"?new D(NaN,NaN,NaN,0):null}function un(t){return new D(t>>16&255,t>>8&255,t&255,1)}function re(t,e,r,n){return n<=0&&(t=e=r=NaN),new D(t,e,r,n)}function ea(t){return t instanceof It||(t=rt(t)),t?(t=t.rgb(),new D(t.r,t.g,t.b,t.opacity)):new D}function gt(t,e,r,n){return arguments.length===1?ea(t):new D(t,e,r,n==null?1:n)}function D(t,e,r,n){this.r=+t,this.g=+e,this.b=+r,this.opacity=+n}ee(D,gt,Ne(It,{brighter(t){return t=t==null?ie:Math.pow(ie,t),new D(this.r*t,this.g*t,this.b*t,this.opacity)},darker(t){return t=t==null?Ot:Math.pow(Ot,t),new D(this.r*t,this.g*t,this.b*t,this.opacity)},rgb(){return this},clamp(){return new D(ft(this.r),ft(this.g),ft(this.b),oe(this.opacity))},displayable(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:fn,formatHex:fn,formatHex8:ra,formatRgb:cn,toString:cn}));function fn(){return`#${ut(this.r)}${ut(this.g)}${ut(this.b)}`}function ra(){return`#${ut(this.r)}${ut(this.g)}${ut(this.b)}${ut((isNaN(this.opacity)?1:this.opacity)*255)}`}function cn(){let t=oe(this.opacity);return`${t===1?\"rgb(\":\"rgba(\"}${ft(this.r)}, ${ft(this.g)}, ${ft(this.b)}${t===1?\")\":`, ${t})`}`}function oe(t){return isNaN(t)?1:Math.max(0,Math.min(1,t))}function ft(t){return Math.max(0,Math.min(255,Math.round(t)||0))}function ut(t){return t=ft(t),(t<16?\"0\":\"\")+t.toString(16)}function hn(t,e,r,n){return n<=0?t=e=r=NaN:r<=0||r>=1?t=e=NaN:e<=0&&(t=NaN),new G(t,e,r,n)}function dn(t){if(t instanceof G)return new G(t.h,t.s,t.l,t.opacity);if(t instanceof It||(t=rt(t)),!t)return new G;if(t instanceof G)return t;t=t.rgb();var e=t.r/255,r=t.g/255,n=t.b/255,i=Math.min(e,r,n),o=Math.max(e,r,n),a=NaN,s=o-i,l=(o+i)/2;return s?(e===o?a=(r-n)/s+(r<n)*6:r===o?a=(n-e)/s+2:a=(e-r)/s+4,s/=l<.5?o+i:2-o-i,a*=60):s=l>0&&l<1?0:a,new G(a,s,l,t.opacity)}function mn(t,e,r,n){return arguments.length===1?dn(t):new G(t,e,r,n==null?1:n)}function G(t,e,r,n){this.h=+t,this.s=+e,this.l=+r,this.opacity=+n}ee(G,mn,Ne(It,{brighter(t){return t=t==null?ie:Math.pow(ie,t),new G(this.h,this.s,this.l*t,this.opacity)},darker(t){return t=t==null?Ot:Math.pow(Ot,t),new G(this.h,this.s,this.l*t,this.opacity)},rgb(){var t=this.h%360+(this.h<0)*360,e=isNaN(t)||isNaN(this.s)?0:this.s,r=this.l,n=r+(r<.5?r:1-r)*e,i=2*r-n;return new D(Pe(t>=240?t-240:t+120,i,n),Pe(t,i,n),Pe(t<120?t+240:t-120,i,n),this.opacity)},clamp(){return new G(pn(this.h),ne(this.s),ne(this.l),oe(this.opacity))},displayable(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl(){let t=oe(this.opacity);return`${t===1?\"hsl(\":\"hsla(\"}${pn(this.h)}, ${ne(this.s)*100}%, ${ne(this.l)*100}%${t===1?\")\":`, ${t})`}`}}));function pn(t){return t=(t||0)%360,t<0?t+360:t}function ne(t){return Math.max(0,Math.min(1,t||0))}function Pe(t,e,r){return(t<60?e+(r-e)*t/60:t<180?r:t<240?e+(r-e)*(240-t)/60:e)*255}function Be(t,e,r,n,i){var o=t*t,a=o*t;return((1-3*t+3*o-a)*e+(4-6*o+3*a)*r+(1+3*t+3*o-3*a)*n+a*i)/6}function xn(t){var e=t.length-1;return function(r){var n=r<=0?r=0:r>=1?(r=1,e-1):Math.floor(r*e),i=t[n],o=t[n+1],a=n>0?t[n-1]:2*i-o,s=n<e-1?t[n+2]:2*o-i;return Be((r-n/e)*e,a,i,o,s)}}function gn(t){var e=t.length;return function(r){var n=Math.floor(((r%=1)<0?++r:r)*e),i=t[(n+e-1)%e],o=t[n%e],a=t[(n+1)%e],s=t[(n+2)%e];return Be((r-n/e)*e,i,o,a,s)}}var Xe=t=>()=>t;function na(t,e){return function(r){return t+r*e}}function ia(t,e,r){return t=Math.pow(t,r),e=Math.pow(e,r)-t,r=1/r,function(n){return Math.pow(t+n*e,r)}}function yn(t){return(t=+t)==1?ae:function(e,r){return r-e?ia(e,r,t):Xe(isNaN(e)?r:e)}}function ae(t,e){var r=e-t;return r?na(t,r):Xe(isNaN(t)?e:t)}var se=(function t(e){var r=yn(e);function n(i,o){var a=r((i=gt(i)).r,(o=gt(o)).r),s=r(i.g,o.g),l=r(i.b,o.b),u=ae(i.opacity,o.opacity);return function(f){return i.r=a(f),i.g=s(f),i.b=l(f),i.opacity=u(f),i+\"\"}}return n.gamma=t,n})(1);function vn(t){return function(e){var r=e.length,n=new Array(r),i=new Array(r),o=new Array(r),a,s;for(a=0;a<r;++a)s=gt(e[a]),n[a]=s.r||0,i[a]=s.g||0,o[a]=s.b||0;return n=t(n),i=t(i),o=t(o),s.opacity=1,function(l){return s.r=n(l),s.g=i(l),s.b=o(l),s+\"\"}}}var oa=vn(xn),aa=vn(gn);function Y(t,e){return t=+t,e=+e,function(r){return t*(1-r)+e*r}}var qe=/[-+]?(?:\\d+\\.?\\d*|\\.?\\d+)(?:[eE][-+]?\\d+)?/g,De=new RegExp(qe.source,\"g\");function sa(t){return function(){return t}}function la(t){return function(e){return t(e)+\"\"}}function Le(t,e){var r=qe.lastIndex=De.lastIndex=0,n,i,o,a=-1,s=[],l=[];for(t=t+\"\",e=e+\"\";(n=qe.exec(t))&&(i=De.exec(e));)(o=i.index)>r&&(o=e.slice(r,o),s[a]?s[a]+=o:s[++a]=o),(n=n[0])===(i=i[0])?s[a]?s[a]+=i:s[++a]=i:(s[++a]=null,l.push({i:a,x:Y(n,i)})),r=De.lastIndex;return r<e.length&&(o=e.slice(r),s[a]?s[a]+=o:s[++a]=o),s.length<2?l[0]?la(l[0].x):sa(e):(e=l.length,function(u){for(var f=0,p;f<e;++f)s[(p=l[f]).i]=p.x(u);return s.join(\"\")})}var wn=180/Math.PI,le={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1};function Ye(t,e,r,n,i,o){var a,s,l;return(a=Math.sqrt(t*t+e*e))&&(t/=a,e/=a),(l=t*r+e*n)&&(r-=t*l,n-=e*l),(s=Math.sqrt(r*r+n*n))&&(r/=s,n/=s,l/=s),t*n<e*r&&(t=-t,e=-e,l=-l,a=-a),{translateX:i,translateY:o,rotate:Math.atan2(e,t)*wn,skewX:Math.atan(l)*wn,scaleX:a,scaleY:s}}var ue;function _n(t){let e=new(typeof DOMMatrix==\"function\"?DOMMatrix:WebKitCSSMatrix)(t+\"\");return e.isIdentity?le:Ye(e.a,e.b,e.c,e.d,e.e,e.f)}function bn(t){return t==null?le:(ue||(ue=document.createElementNS(\"http://www.w3.org/2000/svg\",\"g\")),ue.setAttribute(\"transform\",t),(t=ue.transform.baseVal.consolidate())?(t=t.matrix,Ye(t.a,t.b,t.c,t.d,t.e,t.f)):le)}function kn(t,e,r,n){function i(u){return u.length?u.pop()+\" \":\"\"}function o(u,f,p,d,x,_){if(u!==p||f!==d){var b=x.push(\"translate(\",null,e,null,r);_.push({i:b-4,x:Y(u,p)},{i:b-2,x:Y(f,d)})}else(p||d)&&x.push(\"translate(\"+p+e+d+r)}function a(u,f,p,d){u!==f?(u-f>180?f+=360:f-u>180&&(u+=360),d.push({i:p.push(i(p)+\"rotate(\",null,n)-2,x:Y(u,f)})):f&&p.push(i(p)+\"rotate(\"+f+n)}function s(u,f,p,d){u!==f?d.push({i:p.push(i(p)+\"skewX(\",null,n)-2,x:Y(u,f)}):f&&p.push(i(p)+\"skewX(\"+f+n)}function l(u,f,p,d,x,_){if(u!==p||f!==d){var b=x.push(i(x)+\"scale(\",null,\",\",null,\")\");_.push({i:b-4,x:Y(u,p)},{i:b-2,x:Y(f,d)})}else(p!==1||d!==1)&&x.push(i(x)+\"scale(\"+p+\",\"+d+\")\")}return function(u,f){var p=[],d=[];return u=t(u),f=t(f),o(u.translateX,u.translateY,f.translateX,f.translateY,p,d),a(u.rotate,f.rotate,p,d),s(u.skewX,f.skewX,p,d),l(u.scaleX,u.scaleY,f.scaleX,f.scaleY,p,d),u=f=null,function(x){for(var _=-1,b=d.length,A;++_<b;)p[(A=d[_]).i]=A.x(x);return p.join(\"\")}}}var Fe=kn(_n,\"px, \",\"px)\",\"deg)\"),He=kn(bn,\", \",\")\",\")\");var ua=1e-12;function Sn(t){return((t=Math.exp(t))+1/t)/2}function fa(t){return((t=Math.exp(t))-1/t)/2}function ca(t){return((t=Math.exp(2*t))-1)/(t+1)}var Ve=(function t(e,r,n){function i(o,a){var s=o[0],l=o[1],u=o[2],f=a[0],p=a[1],d=a[2],x=f-s,_=p-l,b=x*x+_*_,A,g;if(b<ua)g=Math.log(d/u)/e,A=function(F){return[s+F*x,l+F*_,u*Math.exp(e*F*g)]};else{var $=Math.sqrt(b),O=(d*d-u*u+n*b)/(2*u*r*$),M=(d*d-u*u-n*b)/(2*d*r*$),I=Math.log(Math.sqrt(O*O+1)-O),X=Math.log(Math.sqrt(M*M+1)-M);g=(X-I)/e,A=function(F){var ot=F*g,at=Sn(I),st=u/(r*$)*(at*ca(e*ot+I)-fa(I));return[s+st*x,l+st*_,u*at/Sn(e*ot+I)]}}return A.duration=g*1e3*e/Math.SQRT2,A}return i.rho=function(o){var a=Math.max(.001,+o),s=a*a,l=s*s;return t(a,s,l)},i})(Math.SQRT2,2,4);var yt=0,Nt=0,Rt=0,Cn=1e3,fe,Pt,ce=0,ct=0,he=0,Bt=typeof performance==\"object\"&&performance.now?performance:Date,An=typeof window==\"object\"&&window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(t){setTimeout(t,17)};function Dt(){return ct||(An(ha),ct=Bt.now()+he)}function ha(){ct=0}function Xt(){this._call=this._time=this._next=null}Xt.prototype=pe.prototype={constructor:Xt,restart:function(t,e,r){if(typeof t!=\"function\")throw new TypeError(\"callback is not a function\");r=(r==null?Dt():+r)+(e==null?0:+e),!this._next&&Pt!==this&&(Pt?Pt._next=this:fe=this,Pt=this),this._call=t,this._time=r,Ge()},stop:function(){this._call&&(this._call=null,this._time=1/0,Ge())}};function pe(t,e,r){var n=new Xt;return n.restart(t,e,r),n}function zn(){Dt(),++yt;for(var t=fe,e;t;)(e=ct-t._time)>=0&&t._call.call(void 0,e),t=t._next;--yt}function En(){ct=(ce=Bt.now())+he,yt=Nt=0;try{zn()}finally{yt=0,da(),ct=0}}function pa(){var t=Bt.now(),e=t-ce;e>Cn&&(he-=e,ce=t)}function da(){for(var t,e=fe,r,n=1/0;e;)e._call?(n>e._time&&(n=e._time),t=e,e=e._next):(r=e._next,e._next=null,e=t?t._next=r:fe=r);Pt=t,Ge(n)}function Ge(t){if(!yt){Nt&&(Nt=clearTimeout(Nt));var e=t-ct;e>24?(t<1/0&&(Nt=setTimeout(En,t-Bt.now()-he)),Rt&&(Rt=clearInterval(Rt))):(Rt||(ce=Bt.now(),Rt=setInterval(pa,Cn)),yt=1,An(En))}}function de(t,e,r){var n=new Xt;return e=e==null?0:+e,n.restart(i=>{n.stop(),t(i+e)},e,r),n}var ma=At(\"start\",\"end\",\"cancel\",\"interrupt\"),xa=[],On=0,$n=1,xe=2,me=3,Tn=4,ge=5,qt=6;function nt(t,e,r,n,i,o){var a=t.__transition;if(!a)t.__transition={};else if(r in a)return;ga(t,r,{name:e,index:n,group:i,on:ma,tween:xa,time:o.time,delay:o.delay,duration:o.duration,ease:o.ease,timer:null,state:On})}function Lt(t,e){var r=R(t,e);if(r.state>On)throw new Error(\"too late; already scheduled\");return r}function P(t,e){var r=R(t,e);if(r.state>me)throw new Error(\"too late; already running\");return r}function R(t,e){var r=t.__transition;if(!r||!(r=r[e]))throw new Error(\"transition not found\");return r}function ga(t,e,r){var n=t.__transition,i;n[e]=r,r.timer=pe(o,0,r.time);function o(u){r.state=$n,r.timer.restart(a,r.delay,r.time),r.delay<=u&&a(u-r.delay)}function a(u){var f,p,d,x;if(r.state!==$n)return l();for(f in n)if(x=n[f],x.name===r.name){if(x.state===me)return de(a);x.state===Tn?(x.state=qt,x.timer.stop(),x.on.call(\"interrupt\",t,t.__data__,x.index,x.group),delete n[f]):+f<e&&(x.state=qt,x.timer.stop(),x.on.call(\"cancel\",t,t.__data__,x.index,x.group),delete n[f])}if(de(function(){r.state===me&&(r.state=Tn,r.timer.restart(s,r.delay,r.time),s(u))}),r.state=xe,r.on.call(\"start\",t,t.__data__,r.index,r.group),r.state===xe){for(r.state=me,i=new Array(d=r.tween.length),f=0,p=-1;f<d;++f)(x=r.tween[f].value.call(t,t.__data__,r.index,r.group))&&(i[++p]=x);i.length=p+1}}function s(u){for(var f=u<r.duration?r.ease.call(null,u/r.duration):(r.timer.restart(l),r.state=ge,1),p=-1,d=i.length;++p<d;)i[p].call(t,f);r.state===ge&&(r.on.call(\"end\",t,t.__data__,r.index,r.group),l())}function l(){r.state=qt,r.timer.stop(),delete n[e];for(var u in n)return;delete t.__transition}}function it(t,e){var r=t.__transition,n,i,o=!0,a;if(r){e=e==null?null:e+\"\";for(a in r){if((n=r[a]).name!==e){o=!1;continue}i=n.state>xe&&n.state<ge,n.state=qt,n.timer.stop(),n.on.call(i?\"interrupt\":\"cancel\",t,t.__data__,n.index,n.group),delete r[a]}o&&delete t.__transition}}function Mn(t){return this.each(function(){it(this,t)})}function ya(t,e){var r,n;return function(){var i=P(this,t),o=i.tween;if(o!==r){n=r=o;for(var a=0,s=n.length;a<s;++a)if(n[a].name===e){n=n.slice(),n.splice(a,1);break}}i.tween=n}}function va(t,e,r){var n,i;if(typeof r!=\"function\")throw new Error;return function(){var o=P(this,t),a=o.tween;if(a!==n){i=(n=a).slice();for(var s={name:e,value:r},l=0,u=i.length;l<u;++l)if(i[l].name===e){i[l]=s;break}l===u&&i.push(s)}o.tween=i}}function In(t,e){var r=this._id;if(t+=\"\",arguments.length<2){for(var n=R(this.node(),r).tween,i=0,o=n.length,a;i<o;++i)if((a=n[i]).name===t)return a.value;return null}return this.each((e==null?ya:va)(r,t,e))}function vt(t,e,r){var n=t._id;return t.each(function(){var i=P(this,n);(i.value||(i.value={}))[e]=r.apply(this,arguments)}),function(i){return R(i,n).value[e]}}function ye(t,e){var r;return(typeof e==\"number\"?Y:e instanceof rt?se:(r=rt(e))?(e=r,se):Le)(t,e)}function wa(t){return function(){this.removeAttribute(t)}}function _a(t){return function(){this.removeAttributeNS(t.space,t.local)}}function ba(t,e,r){var n,i=r+\"\",o;return function(){var a=this.getAttribute(t);return a===i?null:a===n?o:o=e(n=a,r)}}function ka(t,e,r){var n,i=r+\"\",o;return function(){var a=this.getAttributeNS(t.space,t.local);return a===i?null:a===n?o:o=e(n=a,r)}}function Sa(t,e,r){var n,i,o;return function(){var a,s=r(this),l;return s==null?void this.removeAttribute(t):(a=this.getAttribute(t),l=s+\"\",a===l?null:a===n&&l===i?o:(i=l,o=e(n=a,s)))}}function Ea(t,e,r){var n,i,o;return function(){var a,s=r(this),l;return s==null?void this.removeAttributeNS(t.space,t.local):(a=this.getAttributeNS(t.space,t.local),l=s+\"\",a===l?null:a===n&&l===i?o:(i=l,o=e(n=a,s)))}}function Rn(t,e){var r=Q(t),n=r===\"transform\"?He:ye;return this.attrTween(t,typeof e==\"function\"?(r.local?Ea:Sa)(r,n,vt(this,\"attr.\"+t,e)):e==null?(r.local?_a:wa)(r):(r.local?ka:ba)(r,n,e))}function Ca(t,e){return function(r){this.setAttribute(t,e.call(this,r))}}function Aa(t,e){return function(r){this.setAttributeNS(t.space,t.local,e.call(this,r))}}function za(t,e){var r,n;function i(){var o=e.apply(this,arguments);return o!==n&&(r=(n=o)&&Aa(t,o)),r}return i._value=e,i}function $a(t,e){var r,n;function i(){var o=e.apply(this,arguments);return o!==n&&(r=(n=o)&&Ca(t,o)),r}return i._value=e,i}function Nn(t,e){var r=\"attr.\"+t;if(arguments.length<2)return(r=this.tween(r))&&r._value;if(e==null)return this.tween(r,null);if(typeof e!=\"function\")throw new Error;var n=Q(t);return this.tween(r,(n.local?za:$a)(n,e))}function Ta(t,e){return function(){Lt(this,t).delay=+e.apply(this,arguments)}}function Oa(t,e){return e=+e,function(){Lt(this,t).delay=e}}function Pn(t){var e=this._id;return arguments.length?this.each((typeof t==\"function\"?Ta:Oa)(e,t)):R(this.node(),e).delay}function Ma(t,e){return function(){P(this,t).duration=+e.apply(this,arguments)}}function Ia(t,e){return e=+e,function(){P(this,t).duration=e}}function Bn(t){var e=this._id;return arguments.length?this.each((typeof t==\"function\"?Ma:Ia)(e,t)):R(this.node(),e).duration}function Ra(t,e){if(typeof e!=\"function\")throw new Error;return function(){P(this,t).ease=e}}function Xn(t){var e=this._id;return arguments.length?this.each(Ra(e,t)):R(this.node(),e).ease}function Na(t,e){return function(){var r=e.apply(this,arguments);if(typeof r!=\"function\")throw new Error;P(this,t).ease=r}}function Dn(t){if(typeof t!=\"function\")throw new Error;return this.each(Na(this._id,t))}function qn(t){typeof t!=\"function\"&&(t=$t(t));for(var e=this._groups,r=e.length,n=new Array(r),i=0;i<r;++i)for(var o=e[i],a=o.length,s=n[i]=[],l,u=0;u<a;++u)(l=o[u])&&t.call(l,l.__data__,u,o)&&s.push(l);return new B(n,this._parents,this._name,this._id)}function Ln(t){if(t._id!==this._id)throw new Error;for(var e=this._groups,r=t._groups,n=e.length,i=r.length,o=Math.min(n,i),a=new Array(n),s=0;s<o;++s)for(var l=e[s],u=r[s],f=l.length,p=a[s]=new Array(f),d,x=0;x<f;++x)(d=l[x]||u[x])&&(p[x]=d);for(;s<n;++s)a[s]=e[s];return new B(a,this._parents,this._name,this._id)}function Pa(t){return(t+\"\").trim().split(/^|\\s+/).every(function(e){var r=e.indexOf(\".\");return r>=0&&(e=e.slice(0,r)),!e||e===\"start\"})}function Ba(t,e,r){var n,i,o=Pa(e)?Lt:P;return function(){var a=o(this,t),s=a.on;s!==n&&(i=(n=s).copy()).on(e,r),a.on=i}}function Yn(t,e){var r=this._id;return arguments.length<2?R(this.node(),r).on.on(t):this.each(Ba(r,t,e))}function Xa(t){return function(){var e=this.parentNode;for(var r in this.__transition)if(+r!==t)return;e&&e.removeChild(this)}}function Fn(){return this.on(\"end.remove\",Xa(this._id))}function Hn(t){var e=this._name,r=this._id;typeof t!=\"function\"&&(t=lt(t));for(var n=this._groups,i=n.length,o=new Array(i),a=0;a<i;++a)for(var s=n[a],l=s.length,u=o[a]=new Array(l),f,p,d=0;d<l;++d)(f=s[d])&&(p=t.call(f,f.__data__,d,s))&&(\"__data__\"in f&&(p.__data__=f.__data__),u[d]=p,nt(u[d],e,r,d,u,R(f,r)));return new B(o,this._parents,e,r)}function Vn(t){var e=this._name,r=this._id;typeof t!=\"function\"&&(t=zt(t));for(var n=this._groups,i=n.length,o=[],a=[],s=0;s<i;++s)for(var l=n[s],u=l.length,f,p=0;p<u;++p)if(f=l[p]){for(var d=t.call(f,f.__data__,p,l),x,_=R(f,r),b=0,A=d.length;b<A;++b)(x=d[b])&&nt(x,e,r,b,d,_);o.push(d),a.push(f)}return new B(o,a,e,r)}var Da=Z.prototype.constructor;function Gn(){return new Da(this._groups,this._parents)}function qa(t,e){var r,n,i;return function(){var o=et(this,t),a=(this.style.removeProperty(t),et(this,t));return o===a?null:o===r&&a===n?i:i=e(r=o,n=a)}}function Wn(t){return function(){this.style.removeProperty(t)}}function La(t,e,r){var n,i=r+\"\",o;return function(){var a=et(this,t);return a===i?null:a===n?o:o=e(n=a,r)}}function Ya(t,e,r){var n,i,o;return function(){var a=et(this,t),s=r(this),l=s+\"\";return s==null&&(l=s=(this.style.removeProperty(t),et(this,t))),a===l?null:a===n&&l===i?o:(i=l,o=e(n=a,s))}}function Fa(t,e){var r,n,i,o=\"style.\"+e,a=\"end.\"+o,s;return function(){var l=P(this,t),u=l.on,f=l.value[o]==null?s||(s=Wn(e)):void 0;(u!==r||i!==f)&&(n=(r=u).copy()).on(a,i=f),l.on=n}}function Kn(t,e,r){var n=(t+=\"\")==\"transform\"?Fe:ye;return e==null?this.styleTween(t,qa(t,n)).on(\"end.style.\"+t,Wn(t)):typeof e==\"function\"?this.styleTween(t,Ya(t,n,vt(this,\"style.\"+t,e))).each(Fa(this._id,t)):this.styleTween(t,La(t,n,e),r).on(\"end.style.\"+t,null)}function Ha(t,e,r){return function(n){this.style.setProperty(t,e.call(this,n),r)}}function Va(t,e,r){var n,i;function o(){var a=e.apply(this,arguments);return a!==i&&(n=(i=a)&&Ha(t,a,r)),n}return o._value=e,o}function Un(t,e,r){var n=\"style.\"+(t+=\"\");if(arguments.length<2)return(n=this.tween(n))&&n._value;if(e==null)return this.tween(n,null);if(typeof e!=\"function\")throw new Error;return this.tween(n,Va(t,e,r==null?\"\":r))}function Ga(t){return function(){this.textContent=t}}function Wa(t){return function(){var e=t(this);this.textContent=e==null?\"\":e}}function Qn(t){return this.tween(\"text\",typeof t==\"function\"?Wa(vt(this,\"text\",t)):Ga(t==null?\"\":t+\"\"))}function Ka(t){return function(e){this.textContent=t.call(this,e)}}function Ua(t){var e,r;function n(){var i=t.apply(this,arguments);return i!==r&&(e=(r=i)&&Ka(i)),e}return n._value=t,n}function Zn(t){var e=\"text\";if(arguments.length<1)return(e=this.tween(e))&&e._value;if(t==null)return this.tween(e,null);if(typeof t!=\"function\")throw new Error;return this.tween(e,Ua(t))}function Jn(){for(var t=this._name,e=this._id,r=ve(),n=this._groups,i=n.length,o=0;o<i;++o)for(var a=n[o],s=a.length,l,u=0;u<s;++u)if(l=a[u]){var f=R(l,e);nt(l,t,r,u,a,{time:f.time+f.delay+f.duration,delay:0,duration:f.duration,ease:f.ease})}return new B(n,this._parents,t,r)}function jn(){var t,e,r=this,n=r._id,i=r.size();return new Promise(function(o,a){var s={value:a},l={value:function(){--i===0&&o()}};r.each(function(){var u=P(this,n),f=u.on;f!==t&&(e=(t=f).copy(),e._.cancel.push(s),e._.interrupt.push(s),e._.end.push(l)),u.on=e}),i===0&&o()})}var Qa=0;function B(t,e,r,n){this._groups=t,this._parents=e,this._name=r,this._id=n}function ti(t){return Z().transition(t)}function ve(){return++Qa}var j=Z.prototype;B.prototype=ti.prototype={constructor:B,select:Hn,selectAll:Vn,selectChild:j.selectChild,selectChildren:j.selectChildren,filter:qn,merge:Ln,selection:Gn,transition:Jn,call:j.call,nodes:j.nodes,node:j.node,size:j.size,empty:j.empty,each:j.each,on:Yn,attr:Rn,attrTween:Nn,style:Kn,styleTween:Un,text:Qn,textTween:Zn,remove:Fn,tween:In,delay:Pn,duration:Bn,ease:Xn,easeVarying:Dn,end:jn,[Symbol.iterator]:j[Symbol.iterator]};function we(t){return((t*=2)<=1?t*t*t:(t-=2)*t*t+2)/2}var Za={time:null,delay:0,duration:250,ease:we};function Ja(t,e){for(var r;!(r=t.__transition)||!(r=r[e]);)if(!(t=t.parentNode))throw new Error(`transition ${e} not found`);return r}function ei(t){var e,r;t instanceof B?(e=t._id,t=t._name):(e=ve(),(r=Za).time=Dt(),t=t==null?null:t+\"\");for(var n=this._groups,i=n.length,o=0;o<i;++o)for(var a=n[o],s=a.length,l,u=0;u<s;++u)(l=a[u])&&nt(l,t,e,u,a,r||Ja(l,e));return new B(n,this._parents,t,e)}Z.prototype.interrupt=Mn;Z.prototype.transition=ei;var{abs:hp,max:pp,min:dp}=Math;function ri(t){return[+t[0],+t[1]]}function ja(t){return[ri(t[0]),ri(t[1])]}var mp={name:\"x\",handles:[\"w\",\"e\"].map(We),input:function(t,e){return t==null?null:[[+t[0],e[0][1]],[+t[1],e[1][1]]]},output:function(t){return t&&[t[0][0],t[1][0]]}},xp={name:\"y\",handles:[\"n\",\"s\"].map(We),input:function(t,e){return t==null?null:[[e[0][0],+t[0]],[e[1][0],+t[1]]]},output:function(t){return t&&[t[0][1],t[1][1]]}},gp={name:\"xy\",handles:[\"n\",\"w\",\"e\",\"s\",\"nw\",\"ne\",\"sw\",\"se\"].map(We),input:function(t){return t==null?null:ja(t)},output:function(t){return t}};function We(t){return{type:t}}var Ke=Math.PI,Ue=2*Ke,ht=1e-6,ts=Ue-ht;function ni(t){this._+=t[0];for(let e=1,r=t.length;e<r;++e)this._+=arguments[e]+t[e]}function es(t){let e=Math.floor(t);if(!(e>=0))throw new Error(`invalid digits: ${t}`);if(e>15)return ni;let r=10**e;return function(n){this._+=n[0];for(let i=1,o=n.length;i<o;++i)this._+=Math.round(arguments[i]*r)/r+n[i]}}var pt=class{constructor(e){this._x0=this._y0=this._x1=this._y1=null,this._=\"\",this._append=e==null?ni:es(e)}moveTo(e,r){this._append`M${this._x0=this._x1=+e},${this._y0=this._y1=+r}`}closePath(){this._x1!==null&&(this._x1=this._x0,this._y1=this._y0,this._append`Z`)}lineTo(e,r){this._append`L${this._x1=+e},${this._y1=+r}`}quadraticCurveTo(e,r,n,i){this._append`Q${+e},${+r},${this._x1=+n},${this._y1=+i}`}bezierCurveTo(e,r,n,i,o,a){this._append`C${+e},${+r},${+n},${+i},${this._x1=+o},${this._y1=+a}`}arcTo(e,r,n,i,o){if(e=+e,r=+r,n=+n,i=+i,o=+o,o<0)throw new Error(`negative radius: ${o}`);let a=this._x1,s=this._y1,l=n-e,u=i-r,f=a-e,p=s-r,d=f*f+p*p;if(this._x1===null)this._append`M${this._x1=e},${this._y1=r}`;else if(d>ht)if(!(Math.abs(p*l-u*f)>ht)||!o)this._append`L${this._x1=e},${this._y1=r}`;else{let x=n-a,_=i-s,b=l*l+u*u,A=x*x+_*_,g=Math.sqrt(b),$=Math.sqrt(d),O=o*Math.tan((Ke-Math.acos((b+d-A)/(2*g*$)))/2),M=O/$,I=O/g;Math.abs(M-1)>ht&&this._append`L${e+M*f},${r+M*p}`,this._append`A${o},${o},0,0,${+(p*x>f*_)},${this._x1=e+I*l},${this._y1=r+I*u}`}}arc(e,r,n,i,o,a){if(e=+e,r=+r,n=+n,a=!!a,n<0)throw new Error(`negative radius: ${n}`);let s=n*Math.cos(i),l=n*Math.sin(i),u=e+s,f=r+l,p=1^a,d=a?i-o:o-i;this._x1===null?this._append`M${u},${f}`:(Math.abs(this._x1-u)>ht||Math.abs(this._y1-f)>ht)&&this._append`L${u},${f}`,n&&(d<0&&(d=d%Ue+Ue),d>ts?this._append`A${n},${n},0,1,${p},${e-s},${r-l}A${n},${n},0,1,${p},${this._x1=u},${this._y1=f}`:d>ht&&this._append`A${n},${n},0,${+(d>=Ke)},${p},${this._x1=e+n*Math.cos(o)},${this._y1=r+n*Math.sin(o)}`)}rect(e,r,n,i){this._append`M${this._x0=this._x1=+e},${this._y0=this._y1=+r}h${n=+n}v${+i}h${-n}Z`}toString(){return this._}};function ii(){return new pt}ii.prototype=pt.prototype;function oi(t,e){switch(arguments.length){case 0:break;case 1:this.range(t);break;default:this.range(e).domain(t);break}return this}var Qe=Symbol(\"implicit\");function wt(){var t=new mt,e=[],r=[],n=Qe;function i(o){let a=t.get(o);if(a===void 0){if(n!==Qe)return n;t.set(o,a=e.push(o)-1)}return r[a%r.length]}return i.domain=function(o){if(!arguments.length)return e.slice();e=[],t=new mt;for(let a of o)t.has(a)||t.set(a,e.push(a)-1);return i},i.range=function(o){return arguments.length?(r=Array.from(o),i):r.slice()},i.unknown=function(o){return arguments.length?(n=o,i):n},i.copy=function(){return wt(e,r).unknown(n)},oi.apply(i,arguments),i}function ai(t){for(var e=t.length/6|0,r=new Array(e),n=0;n<e;)r[n]=\"#\"+t.slice(n*6,++n*6);return r}var Ze=ai(\"1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf\");function Je(t){return function(){return t}}function si(t){let e=3;return t.digits=function(r){if(!arguments.length)return e;if(r==null)e=null;else{let n=Math.floor(r);if(!(n>=0))throw new RangeError(`invalid digits: ${r}`);e=n}return t},()=>new pt(e)}var li=Array.prototype.slice;function ui(t){return t[0]}function fi(t){return t[1]}var je=class{constructor(e,r){this._context=e,this._x=r}areaStart(){this._line=0}areaEnd(){this._line=NaN}lineStart(){this._point=0}lineEnd(){(this._line||this._line!==0&&this._point===1)&&this._context.closePath(),this._line=1-this._line}point(e,r){switch(e=+e,r=+r,this._point){case 0:{this._point=1,this._line?this._context.lineTo(e,r):this._context.moveTo(e,r);break}case 1:this._point=2;default:{this._x?this._context.bezierCurveTo(this._x0=(this._x0+e)/2,this._y0,this._x0,r,e,r):this._context.bezierCurveTo(this._x0,this._y0=(this._y0+r)/2,e,this._y0,e,r);break}}this._x0=e,this._y0=r}};function ci(t){return new je(t,!0)}function rs(t){return t.source}function ns(t){return t.target}function hi(t){let e=rs,r=ns,n=ui,i=fi,o=null,a=null,s=si(l);function l(){let u,f=li.call(arguments),p=e.apply(this,f),d=r.apply(this,f);if(o==null&&(a=t(u=s())),a.lineStart(),f[0]=p,a.point(+n.apply(this,f),+i.apply(this,f)),f[0]=d,a.point(+n.apply(this,f),+i.apply(this,f)),a.lineEnd(),u)return a=null,u+\"\"||null}return l.source=function(u){return arguments.length?(e=u,l):e},l.target=function(u){return arguments.length?(r=u,l):r},l.x=function(u){return arguments.length?(n=typeof u==\"function\"?u:Je(+u),l):n},l.y=function(u){return arguments.length?(i=typeof u==\"function\"?u:Je(+u),l):i},l.context=function(u){return arguments.length?(u==null?o=a=null:a=t(o=u),l):o},l}function tr(){return hi(ci)}var Yt=t=>()=>t;function er(t,{sourceEvent:e,target:r,transform:n,dispatch:i}){Object.defineProperties(this,{type:{value:t,enumerable:!0,configurable:!0},sourceEvent:{value:e,enumerable:!0,configurable:!0},target:{value:r,enumerable:!0,configurable:!0},transform:{value:n,enumerable:!0,configurable:!0},_:{value:i}})}function W(t,e,r){this.k=t,this.x=e,this.y=r}W.prototype={constructor:W,scale:function(t){return t===1?this:new W(this.k*t,this.x,this.y)},translate:function(t,e){return t===0&e===0?this:new W(this.k,this.x+this.k*t,this.y+this.k*e)},apply:function(t){return[t[0]*this.k+this.x,t[1]*this.k+this.y]},applyX:function(t){return t*this.k+this.x},applyY:function(t){return t*this.k+this.y},invert:function(t){return[(t[0]-this.x)/this.k,(t[1]-this.y)/this.k]},invertX:function(t){return(t-this.x)/this.k},invertY:function(t){return(t-this.y)/this.k},rescaleX:function(t){return t.copy().domain(t.range().map(this.invertX,this).map(t.invert,t))},rescaleY:function(t){return t.copy().domain(t.range().map(this.invertY,this).map(t.invert,t))},toString:function(){return\"translate(\"+this.x+\",\"+this.y+\") scale(\"+this.k+\")\"}};var dt=new W(1,0,0);tt.prototype=W.prototype;function tt(t){for(;!t.__zoom;)if(!(t=t.parentNode))return dt;return t.__zoom}function _e(t){t.stopImmediatePropagation()}function _t(t){t.preventDefault(),t.stopImmediatePropagation()}function is(t){return(!t.ctrlKey||t.type===\"wheel\")&&!t.button}function os(){var t=this;return t instanceof SVGElement?(t=t.ownerSVGElement||t,t.hasAttribute(\"viewBox\")?(t=t.viewBox.baseVal,[[t.x,t.y],[t.x+t.width,t.y+t.height]]):[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]):[[0,0],[t.clientWidth,t.clientHeight]]}function pi(){return this.__zoom||dt}function as(t){return-t.deltaY*(t.deltaMode===1?.05:t.deltaMode?1:.002)*(t.ctrlKey?10:1)}function ss(){return navigator.maxTouchPoints||\"ontouchstart\"in this}function ls(t,e,r){var n=t.invertX(e[0][0])-r[0][0],i=t.invertX(e[1][0])-r[1][0],o=t.invertY(e[0][1])-r[0][1],a=t.invertY(e[1][1])-r[1][1];return t.translate(i>n?(n+i)/2:Math.min(0,n)||Math.max(0,i),a>o?(o+a)/2:Math.min(0,o)||Math.max(0,a))}function rr(){var t=is,e=os,r=ls,n=as,i=ss,o=[0,1/0],a=[[-1/0,-1/0],[1/0,1/0]],s=250,l=Ve,u=At(\"start\",\"zoom\",\"end\"),f,p,d,x=500,_=150,b=0,A=10;function g(h){h.property(\"__zoom\",pi).on(\"wheel.zoom\",ot,{passive:!1}).on(\"mousedown.zoom\",at).on(\"dblclick.zoom\",st).filter(i).on(\"touchstart.zoom\",Ft).on(\"touchmove.zoom\",Ht).on(\"touchend.zoom touchcancel.zoom\",bt).style(\"-webkit-tap-highlight-color\",\"rgba(0,0,0,0)\")}g.transform=function(h,y,m,w){var k=h.selection?h.selection():h;k.property(\"__zoom\",pi),h!==k?I(h,y,m,w):k.interrupt().each(function(){X(this,arguments).event(w).start().zoom(null,typeof y==\"function\"?y.apply(this,arguments):y).end()})},g.scaleBy=function(h,y,m,w){g.scaleTo(h,function(){var k=this.__zoom.k,S=typeof y==\"function\"?y.apply(this,arguments):y;return k*S},m,w)},g.scaleTo=function(h,y,m,w){g.transform(h,function(){var k=e.apply(this,arguments),S=this.__zoom,E=m==null?M(k):typeof m==\"function\"?m.apply(this,arguments):m,z=S.invert(E),c=typeof y==\"function\"?y.apply(this,arguments):y;return r(O($(S,c),E,z),k,a)},m,w)},g.translateBy=function(h,y,m,w){g.transform(h,function(){return r(this.__zoom.translate(typeof y==\"function\"?y.apply(this,arguments):y,typeof m==\"function\"?m.apply(this,arguments):m),e.apply(this,arguments),a)},null,w)},g.translateTo=function(h,y,m,w,k){g.transform(h,function(){var S=e.apply(this,arguments),E=this.__zoom,z=w==null?M(S):typeof w==\"function\"?w.apply(this,arguments):w;return r(dt.translate(z[0],z[1]).scale(E.k).translate(typeof y==\"function\"?-y.apply(this,arguments):-y,typeof m==\"function\"?-m.apply(this,arguments):-m),S,a)},w,k)};function $(h,y){return y=Math.max(o[0],Math.min(o[1],y)),y===h.k?h:new W(y,h.x,h.y)}function O(h,y,m){var w=y[0]-m[0]*h.k,k=y[1]-m[1]*h.k;return w===h.x&&k===h.y?h:new W(h.k,w,k)}function M(h){return[(+h[0][0]+ +h[1][0])/2,(+h[0][1]+ +h[1][1])/2]}function I(h,y,m,w){h.on(\"start.zoom\",function(){X(this,arguments).event(w).start()}).on(\"interrupt.zoom end.zoom\",function(){X(this,arguments).event(w).end()}).tween(\"zoom\",function(){var k=this,S=arguments,E=X(k,S).event(w),z=e.apply(k,S),c=m==null?M(z):typeof m==\"function\"?m.apply(k,S):m,v=Math.max(z[1][0]-z[0][0],z[1][1]-z[0][1]),C=k.__zoom,N=typeof y==\"function\"?y.apply(k,S):y,H=l(C.invert(c).concat(v/C.k),N.invert(c).concat(v/N.k));return function(V){if(V===1)V=N;else{var U=H(V),Se=v/U[2];V=new W(Se,c[0]-U[0]*Se,c[1]-U[1]*Se)}E.zoom(null,V)}})}function X(h,y,m){return!m&&h.__zooming||new F(h,y)}function F(h,y){this.that=h,this.args=y,this.active=0,this.sourceEvent=null,this.extent=e.apply(h,y),this.taps=0}F.prototype={event:function(h){return h&&(this.sourceEvent=h),this},start:function(){return++this.active===1&&(this.that.__zooming=this,this.emit(\"start\")),this},zoom:function(h,y){return this.mouse&&h!==\"mouse\"&&(this.mouse[1]=y.invert(this.mouse[0])),this.touch0&&h!==\"touch\"&&(this.touch0[1]=y.invert(this.touch0[0])),this.touch1&&h!==\"touch\"&&(this.touch1[1]=y.invert(this.touch1[0])),this.that.__zoom=y,this.emit(\"zoom\"),this},end:function(){return--this.active===0&&(delete this.that.__zooming,this.emit(\"end\")),this},emit:function(h){var y=L(this.that).datum();u.call(h,this.that,new er(h,{sourceEvent:this.sourceEvent,target:g,type:h,transform:this.that.__zoom,dispatch:u}),y)}};function ot(h,...y){if(!t.apply(this,arguments))return;var m=X(this,y).event(h),w=this.__zoom,k=Math.max(o[0],Math.min(o[1],w.k*Math.pow(2,n.apply(this,arguments)))),S=J(h);if(m.wheel)(m.mouse[0][0]!==S[0]||m.mouse[0][1]!==S[1])&&(m.mouse[1]=w.invert(m.mouse[0]=S)),clearTimeout(m.wheel);else{if(w.k===k)return;m.mouse=[S,w.invert(S)],it(this),m.start()}_t(h),m.wheel=setTimeout(E,_),m.zoom(\"mouse\",r(O($(w,k),m.mouse[0],m.mouse[1]),m.extent,a));function E(){m.wheel=null,m.end()}}function at(h,...y){if(d||!t.apply(this,arguments))return;var m=h.currentTarget,w=X(this,y,!0).event(h),k=L(h.view).on(\"mousemove.zoom\",c,!0).on(\"mouseup.zoom\",v,!0),S=J(h,m),E=h.clientX,z=h.clientY;Ie(h.view),_e(h),w.mouse=[S,this.__zoom.invert(S)],it(this),w.start();function c(C){if(_t(C),!w.moved){var N=C.clientX-E,H=C.clientY-z;w.moved=N*N+H*H>b}w.event(C).zoom(\"mouse\",r(O(w.that.__zoom,w.mouse[0]=J(C,m),w.mouse[1]),w.extent,a))}function v(C){k.on(\"mousemove.zoom mouseup.zoom\",null),Re(C.view,w.moved),_t(C),w.event(C).end()}}function st(h,...y){if(t.apply(this,arguments)){var m=this.__zoom,w=J(h.changedTouches?h.changedTouches[0]:h,this),k=m.invert(w),S=m.k*(h.shiftKey?.5:2),E=r(O($(m,S),w,k),e.apply(this,y),a);_t(h),s>0?L(this).transition().duration(s).call(I,E,w,h):L(this).call(g.transform,E,w,h)}}function Ft(h,...y){if(t.apply(this,arguments)){var m=h.touches,w=m.length,k=X(this,y,h.changedTouches.length===w).event(h),S,E,z,c;for(_e(h),E=0;E<w;++E)z=m[E],c=J(z,this),c=[c,this.__zoom.invert(c),z.identifier],k.touch0?!k.touch1&&k.touch0[2]!==c[2]&&(k.touch1=c,k.taps=0):(k.touch0=c,S=!0,k.taps=1+!!f);f&&(f=clearTimeout(f)),S&&(k.taps<2&&(p=c[0],f=setTimeout(function(){f=null},x)),it(this),k.start())}}function Ht(h,...y){if(this.__zooming){var m=X(this,y).event(h),w=h.changedTouches,k=w.length,S,E,z,c;for(_t(h),S=0;S<k;++S)E=w[S],z=J(E,this),m.touch0&&m.touch0[2]===E.identifier?m.touch0[0]=z:m.touch1&&m.touch1[2]===E.identifier&&(m.touch1[0]=z);if(E=m.that.__zoom,m.touch1){var v=m.touch0[0],C=m.touch0[1],N=m.touch1[0],H=m.touch1[1],V=(V=N[0]-v[0])*V+(V=N[1]-v[1])*V,U=(U=H[0]-C[0])*U+(U=H[1]-C[1])*U;E=$(E,Math.sqrt(V/U)),z=[(v[0]+N[0])/2,(v[1]+N[1])/2],c=[(C[0]+H[0])/2,(C[1]+H[1])/2]}else if(m.touch0)z=m.touch0[0],c=m.touch0[1];else return;m.zoom(\"touch\",r(O(E,z,c),m.extent,a))}}function bt(h,...y){if(this.__zooming){var m=X(this,y).event(h),w=h.changedTouches,k=w.length,S,E;for(_e(h),d&&clearTimeout(d),d=setTimeout(function(){d=null},x),S=0;S<k;++S)E=w[S],m.touch0&&m.touch0[2]===E.identifier?delete m.touch0:m.touch1&&m.touch1[2]===E.identifier&&delete m.touch1;if(m.touch1&&!m.touch0&&(m.touch0=m.touch1,delete m.touch1),m.touch0)m.touch0[1]=this.__zoom.invert(m.touch0[0]);else if(m.end(),m.taps===2&&(E=J(E,this),Math.hypot(p[0]-E[0],p[1]-E[1])<A)){var z=L(this).on(\"dblclick.zoom\");z&&z.apply(this,arguments)}}}return g.wheelDelta=function(h){return arguments.length?(n=typeof h==\"function\"?h:Yt(+h),g):n},g.filter=function(h){return arguments.length?(t=typeof h==\"function\"?h:Yt(!!h),g):t},g.touchable=function(h){return arguments.length?(i=typeof h==\"function\"?h:Yt(!!h),g):i},g.extent=function(h){return arguments.length?(e=typeof h==\"function\"?h:Yt([[+h[0][0],+h[0][1]],[+h[1][0],+h[1][1]]]),g):e},g.scaleExtent=function(h){return arguments.length?(o[0]=+h[0],o[1]=+h[1],g):[o[0],o[1]]},g.translateExtent=function(h){return arguments.length?(a[0][0]=+h[0][0],a[1][0]=+h[1][0],a[0][1]=+h[0][1],a[1][1]=+h[1][1],g):[[a[0][0],a[0][1]],[a[1][0],a[1][1]]]},g.constrain=function(h){return arguments.length?(r=h,g):r},g.duration=function(h){return arguments.length?(s=+h,g):s},g.interpolate=function(h){return arguments.length?(l=h,g):l},g.on=function(){var h=u.on.apply(u,arguments);return h===u?g:h},g.clickDistance=function(h){return arguments.length?(b=(h=+h)*h,g):Math.sqrt(b)},g.tapDistance=function(h){return arguments.length?(A=+h,g):A},g}var mi=typeof navigator<\"u\"&&navigator.userAgent.includes(\"Macintosh\"),us=wt(Ze),xi=(t=1,e=3,r=2)=>n=>t+e/r**n.state.depth,gi={autoFit:!1,duration:500,embedGlobalCSS:!0,fitRatio:.95,maxInitialScale:2,scrollForPan:mi,initialExpandLevel:-1,zoom:!0,pan:!0,toggleRecursively:!1,color:t=>{var e;return us(`${((e=t.state)==null?void 0:e.path)||\"\"}`)},lineWidth:xi(),maxWidth:0,nodeMinHeight:16,paddingX:8,spacingHorizontal:80,spacingVertical:5};function yi(t){let e={},r={...t},{color:n,colorFreezeLevel:i,lineWidth:o}=r;if((n==null?void 0:n.length)===1){let a=n[0];e.color=()=>a}else if(n!=null&&n.length){let a=wt(n);e.color=s=>a(`${s.state.path}`)}if(i){let a=e.color||gi.color;e.color=s=>(s={...s,state:{...s.state,path:s.state.path.split(\".\").slice(0,i).join(\".\")}},a(s))}if(o){let a=Array.isArray(o)?o:[o,0,1];e.lineWidth=xi(...a)}return[\"duration\",\"fitRatio\",\"initialExpandLevel\",\"maxInitialScale\",\"maxWidth\",\"nodeMinHeight\",\"paddingX\",\"spacingHorizontal\",\"spacingVertical\"].forEach(a=>{let s=r[a];typeof s==\"number\"&&(e[a]=s)}),[\"zoom\",\"pan\"].forEach(a=>{let s=r[a];s!=null&&(e[a]=!!s)}),e}function fs(t){let e=0;for(let r=0;r<t.length;r++)e=(e<<5)-e+t.charCodeAt(r)|0;return(e>>>0).toString(36)}function q(t){if(typeof t==\"string\"){let r=t;t=n=>n.matches(r)}let e=t;return function(){let r=Array.from(this.childNodes);return e&&(r=r.filter(n=>e(n))),r}}function cs(t){var e=0,r=t.children,n=r&&r.length;if(!n)e=1;else for(;--n>=0;)e+=r[n].value;t.value=e}function hs(){return this.eachAfter(cs)}function ps(t){var e=this,r,n=[e],i,o,a;do for(r=n.reverse(),n=[];e=r.pop();)if(t(e),i=e.children,i)for(o=0,a=i.length;o<a;++o)n.push(i[o]);while(n.length);return this}function ds(t){for(var e=this,r=[e],n,i;e=r.pop();)if(t(e),n=e.children,n)for(i=n.length-1;i>=0;--i)r.push(n[i]);return this}function ms(t){for(var e=this,r=[e],n=[],i,o,a;e=r.pop();)if(n.push(e),i=e.children,i)for(o=0,a=i.length;o<a;++o)r.push(i[o]);for(;e=n.pop();)t(e);return this}function xs(t){return this.eachAfter(function(e){for(var r=+t(e.data)||0,n=e.children,i=n&&n.length;--i>=0;)r+=n[i].value;e.value=r})}function gs(t){return this.eachBefore(function(e){e.children&&e.children.sort(t)})}function ys(t){for(var e=this,r=vs(e,t),n=[e];e!==r;)e=e.parent,n.push(e);for(var i=n.length;t!==r;)n.splice(i,0,t),t=t.parent;return n}function vs(t,e){if(t===e)return t;var r=t.ancestors(),n=e.ancestors(),i=null;for(t=r.pop(),e=n.pop();t===e;)i=t,t=r.pop(),e=n.pop();return i}function ws(){for(var t=this,e=[t];t=t.parent;)e.push(t);return e}function _s(){var t=[];return this.each(function(e){t.push(e)}),t}function bs(){var t=[];return this.eachBefore(function(e){e.children||t.push(e)}),t}function ks(){var t=this,e=[];return t.each(function(r){r!==t&&e.push({source:r.parent,target:r})}),e}function ar(t,e){var r=new be(t),n=+t.value&&(r.value=t.value),i,o=[r],a,s,l,u;for(e==null&&(e=Es);i=o.pop();)if(n&&(i.value=+i.data.value),(s=e(i.data))&&(u=s.length))for(i.children=new Array(u),l=u-1;l>=0;--l)o.push(a=i.children[l]=new be(s[l])),a.parent=i,a.depth=i.depth+1;return r.eachBefore(As)}function Ss(){return ar(this).eachBefore(Cs)}function Es(t){return t.children}function Cs(t){t.data=t.data.data}function As(t){var e=0;do t.height=e;while((t=t.parent)&&t.height<++e)}function be(t){this.data=t,this.depth=this.height=0,this.parent=null}be.prototype=ar.prototype={constructor:be,count:hs,each:ps,eachAfter:ms,eachBefore:ds,sum:xs,sort:gs,path:ys,ancestors:ws,descendants:_s,leaves:bs,links:ks,copy:Ss};var zs=\"2.1.2\",$s={version:zs},{version:Ts}=$s,Os=Object.freeze({children:t=>t.children,nodeSize:t=>t.data.size,spacing:0});function wi(t){let e=Object.assign({},Os,t);function r(s){let l=e[s];return typeof l==\"function\"?l:()=>l}function n(s){let l=a(o(),s,u=>u.children);return l.update(),l.data}function i(){let s=r(\"nodeSize\"),l=r(\"spacing\");return class vi extends ar.prototype.constructor{constructor(f){super(f)}copy(){let f=a(this.constructor,this,p=>p.children);return f.each(p=>p.data=p.data.data),f}get size(){return s(this)}spacing(f){return l(this,f)}get nodes(){return this.descendants()}get xSize(){return this.size[0]}get ySize(){return this.size[1]}get top(){return this.y}get bottom(){return this.y+this.ySize}get left(){return this.x-this.xSize/2}get right(){return this.x+this.xSize/2}get root(){let f=this.ancestors();return f[f.length-1]}get numChildren(){return this.hasChildren?this.children.length:0}get hasChildren(){return!this.noChildren}get noChildren(){return this.children===null}get firstChild(){return this.hasChildren?this.children[0]:null}get lastChild(){return this.hasChildren?this.children[this.numChildren-1]:null}get extents(){return(this.children||[]).reduce((f,p)=>vi.maxExtents(f,p.extents),this.nodeExtents)}get nodeExtents(){return{top:this.top,bottom:this.bottom,left:this.left,right:this.right}}static maxExtents(f,p){return{top:Math.min(f.top,p.top),bottom:Math.max(f.bottom,p.bottom),left:Math.min(f.left,p.left),right:Math.max(f.right,p.right)}}}}function o(){let s=i(),l=r(\"nodeSize\"),u=r(\"spacing\");return class extends s{constructor(f){super(f),Object.assign(this,{x:0,y:0,relX:0,prelim:0,shift:0,change:0,lExt:this,lExtRelX:0,lThr:null,rExt:this,rExtRelX:0,rThr:null})}get size(){return l(this.data)}spacing(f){return u(this.data,f.data)}get x(){return this.data.x}set x(f){this.data.x=f}get y(){return this.data.y}set y(f){this.data.y=f}update(){return _i(this),bi(this),this}}}function a(s,l,u){let f=(p,d)=>{let x=new s(p);Object.assign(x,{parent:d,depth:d===null?0:d.depth+1,height:0,length:1});let _=u(p)||[];return x.children=_.length===0?null:_.map(b=>f(b,x)),x.children&&Object.assign(x,x.children.reduce((b,A)=>({height:Math.max(b.height,A.height+1),length:b.length+A.length}),x)),x};return f(l,null)}return Object.assign(n,{nodeSize(s){return arguments.length?(e.nodeSize=s,n):e.nodeSize},spacing(s){return arguments.length?(e.spacing=s,n):e.spacing},children(s){return arguments.length?(e.children=s,n):e.children},hierarchy(s,l){let u=typeof l>\"u\"?e.children:l;return a(i(),s,u)},dump(s){let l=r(\"nodeSize\"),u=f=>p=>{let d=f+\" \",x=f+\" \",{x:_,y:b}=p,A=l(p),g=p.children||[],$=g.length===0?\" \":`,${d}children: [${x}${g.map(u(x)).join(x)}${d}],${f}`;return`{ size: [${A.join(\", \")}],${d}x: ${_}, y: ${b}${$}},`};return u(`\n`)(s)}}),n}wi.version=Ts;var _i=(t,e=0)=>(t.y=e,(t.children||[]).reduce((r,n)=>{let[i,o]=r;_i(n,t.y+t.ySize);let a=(i===0?n.lExt:n.rExt).bottom;i!==0&&Is(t,i,o);let s=Ls(a,i,o);return[i+1,s]},[0,null]),Ms(t),qs(t),t),bi=(t,e,r)=>{typeof e>\"u\"&&(e=-t.relX-t.prelim,r=0);let n=e+t.relX;return t.relX=n+t.prelim-r,t.prelim=0,t.x=r+t.relX,(t.children||[]).forEach(i=>bi(i,n,t.x)),t},Ms=t=>{(t.children||[]).reduce((e,r)=>{let[n,i]=e,o=n+r.shift,a=i+o+r.change;return r.relX+=a,[o,a]},[0,0])},Is=(t,e,r)=>{let n=t.children[e-1],i=t.children[e],o=n,a=n.relX,s=i,l=i.relX,u=!0;for(;o&&s;){o.bottom>r.lowY&&(r=r.next);let f=a+o.prelim-(l+s.prelim)+o.xSize/2+s.xSize/2+o.spacing(s);(f>0||f<0&&u)&&(l+=f,Rs(i,f),Ns(t,e,r.index,f)),u=!1;let p=o.bottom,d=s.bottom;p<=d&&(o=Bs(o),o&&(a+=o.relX)),p>=d&&(s=Ps(s),s&&(l+=s.relX))}!o&&s?Xs(t,e,s,l):o&&!s&&Ds(t,e,o,a)},Rs=(t,e)=>{t.relX+=e,t.lExtRelX+=e,t.rExtRelX+=e},Ns=(t,e,r,n)=>{let i=t.children[e],o=e-r;if(o>1){let a=n/o;t.children[r+1].shift+=a,i.shift-=a,i.change-=n-a}},Ps=t=>t.hasChildren?t.firstChild:t.lThr,Bs=t=>t.hasChildren?t.lastChild:t.rThr,Xs=(t,e,r,n)=>{let i=t.firstChild,o=i.lExt,a=t.children[e];o.lThr=r;let s=n-r.relX-i.lExtRelX;o.relX+=s,o.prelim-=s,i.lExt=a.lExt,i.lExtRelX=a.lExtRelX},Ds=(t,e,r,n)=>{let i=t.children[e],o=i.rExt,a=t.children[e-1];o.rThr=r;let s=n-r.relX-i.rExtRelX;o.relX+=s,o.prelim-=s,i.rExt=a.rExt,i.rExtRelX=a.rExtRelX},qs=t=>{if(t.hasChildren){let e=t.firstChild,r=t.lastChild,n=(e.prelim+e.relX-e.xSize/2+r.relX+r.prelim+r.xSize/2)/2;Object.assign(t,{prelim:n,lExt:e.lExt,lExtRelX:e.lExtRelX,rExt:r.rExt,rExtRelX:r.rExtRelX})}},Ls=(t,e,r)=>{for(;r!==null&&t>=r.lowY;)r=r.next;return{lowY:t,index:e,next:r}},Ys=\".markmap{--markmap-max-width: 9999px;--markmap-a-color: #0097e6;--markmap-a-hover-color: #00a8ff;--markmap-code-bg: #f0f0f0;--markmap-code-color: #555;--markmap-highlight-bg: #ffeaa7;--markmap-table-border: 1px solid currentColor;--markmap-font: 300 16px/20px sans-serif;--markmap-circle-open-bg: #fff;--markmap-text-color: #333;--markmap-highlight-node-bg: #ff02;font:var(--markmap-font);color:var(--markmap-text-color)}.markmap-link{fill:none}.markmap-node>circle{cursor:pointer}.markmap-foreign{display:inline-block}.markmap-foreign p{margin:0}.markmap-foreign a{color:var(--markmap-a-color)}.markmap-foreign a:hover{color:var(--markmap-a-hover-color)}.markmap-foreign code{padding:.25em;font-size:calc(1em - 2px);color:var(--markmap-code-color);background-color:var(--markmap-code-bg);border-radius:2px}.markmap-foreign pre{margin:0}.markmap-foreign pre>code{display:block}.markmap-foreign del{text-decoration:line-through}.markmap-foreign em{font-style:italic}.markmap-foreign strong{font-weight:700}.markmap-foreign mark{background:var(--markmap-highlight-bg)}.markmap-foreign table,.markmap-foreign th,.markmap-foreign td{border-collapse:collapse;border:var(--markmap-table-border)}.markmap-foreign img{display:inline-block}.markmap-foreign svg{fill:currentColor}.markmap-foreign>div{width:var(--markmap-max-width);text-align:left}.markmap-foreign>div>div{display:inline-block}.markmap-highlight rect{fill:var(--markmap-highlight-node-bg)}.markmap-dark .markmap{--markmap-code-bg: #1a1b26;--markmap-code-color: #ddd;--markmap-circle-open-bg: #444;--markmap-text-color: #eee}\";var nr=\"g.markmap-node\",Fs=\"path.markmap-link\",Hs=\"g.markmap-highlight\",ir=tr();function di(t,e){let r=Gt(t,e);return t[r]}function or(t){t.stopPropagation()}var Vs=new Vt,ke=class t{constructor(e,r){this.options={...gi},this._disposeList=[],this.handleZoom=n=>{let{transform:i}=n;this.g.attr(\"transform\",i)},this.handlePan=n=>{n.preventDefault();let i=tt(this.svg.node()),o=i.translate(-n.deltaX/i.k,-n.deltaY/i.k);this.svg.call(this.zoom.transform,o)},this.handleClick=(n,i)=>{let o=this.options.toggleRecursively;(mi?n.metaKey:n.ctrlKey)&&(o=!o),this.toggleNode(i,o)},this.ensureView=this.ensureVisible,this.svg=e.datum?e:L(e),this.styleNode=this.svg.append(\"style\"),this.zoom=rr().filter(n=>this.options.scrollForPan&&n.type===\"wheel\"?n.ctrlKey&&!n.button:(!n.ctrlKey||n.type===\"wheel\")&&!n.button).on(\"zoom\",this.handleZoom),this.setOptions(r),this.state={id:this.options.id||this.svg.attr(\"id\")||ur(),rect:{x1:0,y1:0,x2:0,y2:0}},this.g=this.svg.append(\"g\"),this.g.append(\"g\").attr(\"class\",\"markmap-highlight\"),this._observer=new ResizeObserver(cr(()=>{this.renderData()},100)),this._disposeList.push(Vs.tap(()=>{this.setData()}),()=>this._observer.disconnect())}getStyleContent(){let{style:e}=this.options,{id:r}=this.state,n=typeof e==\"function\"?e(r):\"\";return[this.options.embedGlobalCSS&&Ys,n].filter(Boolean).join(`\n`)}updateStyle(){this.svg.attr(\"class\",fr(this.svg.attr(\"class\"),\"markmap\",this.state.id));let e=this.getStyleContent();this.styleNode.text(e)}async toggleNode(e,r=!1){var n,i;let o=(n=e.payload)!=null&&n.fold?0:1;r?St(e,(a,s)=>{a.payload={...a.payload,fold:o},s()}):e.payload={...e.payload,fold:(i=e.payload)!=null&&i.fold?0:1},await this.renderData(e)}_initializeData(e){let r=0,{color:n,initialExpandLevel:i}=this.options,o=0,a=0;return St(e,(s,l,u)=>{var f,p,d,x;a+=1,s.children=(f=s.children)==null?void 0:f.map(b=>({...b})),r+=1,s.state={...s.state,depth:a,id:r,rect:{x:0,y:0,width:0,height:0},size:[0,0]},s.state.key=[(p=u==null?void 0:u.state)==null?void 0:p.id,s.state.id].filter(Boolean).join(\".\")+fs(s.content),s.state.path=[(d=u==null?void 0:u.state)==null?void 0:d.path,s.state.id].filter(Boolean).join(\".\"),n(s);let _=((x=s.payload)==null?void 0:x.fold)===2;_?o+=1:(o||i>=0&&s.state.depth>=i)&&(s.payload={...s.payload,fold:1}),l(),_&&(o-=1),a-=1}),e}_relayout(){if(!this.state.data)return;this.g.selectAll(q(nr)).selectAll(q(\"foreignObject\")).each(function(l){var u;let f=(u=this.firstChild)==null?void 0:u.firstChild,p=[f.scrollWidth,f.scrollHeight];l.state.size=p});let{lineWidth:e,paddingX:r,spacingHorizontal:n,spacingVertical:i}=this.options,o=wi({}).children(l=>{var u;if(!((u=l.payload)!=null&&u.fold))return l.children}).nodeSize(l=>{let[u,f]=l.data.state.size;return[f,u+(u?r*2:0)+n]}).spacing((l,u)=>(l.parent===u.parent?i:i*2)+e(l.data)),a=o.hierarchy(this.state.data);o(a);let s=a.descendants();s.forEach(l=>{let u=l.data;u.state.rect={x:l.y,y:l.x-l.xSize/2,width:l.ySize-n,height:l.xSize}}),this.state.rect={x1:Ct(s,l=>l.data.state.rect.x)||0,y1:Ct(s,l=>l.data.state.rect.y)||0,x2:Et(s,l=>l.data.state.rect.x+l.data.state.rect.width)||0,y2:Et(s,l=>l.data.state.rect.y+l.data.state.rect.height)||0}}setOptions(e){this.options={...this.options,...e},this.options.zoom?this.svg.call(this.zoom):this.svg.on(\".zoom\",null),this.options.pan?this.svg.on(\"wheel\",this.handlePan):this.svg.on(\"wheel\",null)}async setData(e,r){r&&this.setOptions(r),e&&(this.state.data=this._initializeData(e)),this.state.data&&(this.updateStyle(),await this.renderData())}async setHighlight(e){this.state.highlight=e||void 0,await this.renderData()}_getHighlightRect(e){let r=this.svg.node(),n=4/tt(r).k,i={...e.state.rect};return i.x-=n,i.y-=n,i.width+=2*n,i.height+=2*n,i}async renderData(e){let{paddingX:r,autoFit:n,color:i,maxWidth:o,lineWidth:a}=this.options,s=this.state.data;if(!s)return;let l={},u={},f=[];St(s,(c,v,C)=>{var N;(N=c.payload)!=null&&N.fold||v(),l[c.state.id]=c,C&&(u[c.state.id]=C.state.id),f.push(c)});let p={},d={},x=c=>{!c||p[c.state.id]||St(c,(v,C)=>{p[v.state.id]=c.state.id,C()})},_=c=>d[p[c.state.id]]||s.state.rect,b=c=>(l[p[c.state.id]]||s).state.rect;d[s.state.id]=s.state.rect,e&&x(e);let{highlight:A}=this.state;A&&!l[A.state.id]&&(A=void 0);let g=this.g.selectAll(q(Hs)).selectAll(q(\"rect\")).data(A?[this._getHighlightRect(A)]:[]).join(\"rect\").attr(\"x\",c=>c.x).attr(\"y\",c=>c.y).attr(\"width\",c=>c.width).attr(\"height\",c=>c.height),$=this.g.selectAll(q(nr)).each(c=>{d[c.state.id]=c.state.rect}).data(f,c=>c.state.key),O=$.enter().append(\"g\").attr(\"data-depth\",c=>c.state.depth).attr(\"data-path\",c=>c.state.path).each(c=>{x(l[u[c.state.id]])}),M=$.exit().each(c=>{x(l[u[c.state.id]])}),I=$.merge(O).attr(\"class\",c=>{var v;return[\"markmap-node\",((v=c.payload)==null?void 0:v.fold)&&\"markmap-fold\"].filter(Boolean).join(\" \")}),X=I.selectAll(q(\"line\")).data(c=>[c],c=>c.state.key),F=X.enter().append(\"line\").attr(\"stroke\",c=>i(c)).attr(\"stroke-width\",0),ot=X.merge(F),at=I.selectAll(q(\"circle\")).data(c=>{var v;return(v=c.children)!=null&&v.length?[c]:[]},c=>c.state.key),st=at.enter().append(\"circle\").attr(\"stroke-width\",0).attr(\"r\",0).on(\"click\",(c,v)=>this.handleClick(c,v)).on(\"mousedown\",or).merge(at).attr(\"stroke\",c=>i(c)).attr(\"fill\",c=>{var v;return(v=c.payload)!=null&&v.fold&&c.children?i(c):\"var(--markmap-circle-open-bg)\"}),Ft=this._observer,Ht=I.selectAll(q(\"foreignObject\")).data(c=>[c],c=>c.state.key),bt=Ht.enter().append(\"foreignObject\").attr(\"class\",\"markmap-foreign\").attr(\"x\",r).attr(\"y\",0).style(\"opacity\",0).on(\"mousedown\",or).on(\"dblclick\",or);bt.append(\"xhtml:div\").append(\"xhtml:div\").html(c=>c.content).attr(\"xmlns\",\"http://www.w3.org/1999/xhtml\"),bt.each(function(){var c;let v=(c=this.firstChild)==null?void 0:c.firstChild;Ft.observe(v)});let h=M.selectAll(q(\"foreignObject\"));h.each(function(){var c;let v=(c=this.firstChild)==null?void 0:c.firstChild;Ft.unobserve(v)});let y=bt.merge(Ht),m=f.flatMap(c=>{var v;return(v=c.payload)!=null&&v.fold?[]:c.children.map(C=>({source:c,target:C}))}),w=this.g.selectAll(q(Fs)).data(m,c=>c.target.state.key),k=w.exit(),S=w.enter().insert(\"path\",\"g\").attr(\"class\",\"markmap-link\").attr(\"data-depth\",c=>c.target.state.depth).attr(\"data-path\",c=>c.target.state.path).attr(\"d\",c=>{let v=_(c.target),C=[v.x+v.width,v.y+v.height];return ir({source:C,target:C})}).attr(\"stroke-width\",0).merge(w);this.svg.style(\"--markmap-max-width\",o?`${o}px`:null),await new Promise(requestAnimationFrame),this._relayout(),g=g.data(A?[this._getHighlightRect(A)]:[]).join(\"rect\"),this.transition(g).attr(\"x\",c=>c.x).attr(\"y\",c=>c.y).attr(\"width\",c=>c.width).attr(\"height\",c=>c.height),O.attr(\"transform\",c=>{let v=_(c);return`translate(${v.x+v.width-c.state.rect.width},${v.y+v.height-c.state.rect.height})`}),this.transition(M).attr(\"transform\",c=>{let v=b(c),C=v.x+v.width-c.state.rect.width,N=v.y+v.height-c.state.rect.height;return`translate(${C},${N})`}).remove(),this.transition(I).attr(\"transform\",c=>`translate(${c.state.rect.x},${c.state.rect.y})`);let E=M.selectAll(q(\"line\"));this.transition(E).attr(\"x1\",c=>c.state.rect.width).attr(\"stroke-width\",0),F.attr(\"x1\",c=>c.state.rect.width).attr(\"x2\",c=>c.state.rect.width),ot.attr(\"y1\",c=>c.state.rect.height+a(c)/2).attr(\"y2\",c=>c.state.rect.height+a(c)/2),this.transition(ot).attr(\"x1\",-1).attr(\"x2\",c=>c.state.rect.width+2).attr(\"stroke\",c=>i(c)).attr(\"stroke-width\",a);let z=M.selectAll(q(\"circle\"));this.transition(z).attr(\"r\",0).attr(\"stroke-width\",0),st.attr(\"cx\",c=>c.state.rect.width).attr(\"cy\",c=>c.state.rect.height+a(c)/2),this.transition(st).attr(\"r\",6).attr(\"stroke-width\",\"1.5\"),this.transition(h).style(\"opacity\",0),y.attr(\"width\",c=>Math.max(0,c.state.rect.width-r*2)).attr(\"height\",c=>c.state.rect.height),this.transition(y).style(\"opacity\",1),this.transition(k).attr(\"d\",c=>{let v=b(c.target),C=[v.x+v.width,v.y+v.height+a(c.target)/2];return ir({source:C,target:C})}).attr(\"stroke-width\",0).remove(),this.transition(S).attr(\"stroke\",c=>i(c.target)).attr(\"stroke-width\",c=>a(c.target)).attr(\"d\",c=>{let v=c.source,C=c.target,N=[v.state.rect.x+v.state.rect.width,v.state.rect.y+v.state.rect.height+a(v)/2],H=[C.state.rect.x,C.state.rect.y+C.state.rect.height+a(C)/2];return ir({source:N,target:H})}),n&&this.fit()}transition(e){let{duration:r}=this.options;return e.transition().duration(r)}async fit(e=this.options.maxInitialScale){let r=this.svg.node(),{width:n,height:i}=r.getBoundingClientRect(),{fitRatio:o}=this.options,{x1:a,y1:s,x2:l,y2:u}=this.state.rect,f=l-a,p=u-s,d=Math.min(n/f*o,i/p*o,e),x=dt.translate((n-f*d)/2-a*d,(i-p*d)/2-s*d).scale(d);return this.transition(this.svg).call(this.zoom.transform,x).end().catch(kt)}findElement(e){let r;return this.g.selectAll(q(nr)).each(function(n){n===e&&(r={data:n,g:this})}),r}async ensureVisible(e,r){var n;let i=(n=this.findElement(e))==null?void 0:n.data;if(!i)return;let o=this.svg.node(),a=o.getBoundingClientRect(),s=tt(o),[l,u]=[i.state.rect.x,i.state.rect.x+i.state.rect.width+2].map(g=>g*s.k+s.x),[f,p]=[i.state.rect.y,i.state.rect.y+i.state.rect.height].map(g=>g*s.k+s.y),d={left:0,right:0,top:0,bottom:0,...r},x=[d.left-l,a.width-d.right-u],_=[d.top-f,a.height-d.bottom-p],b=x[0]*x[1]>0?di(x,Math.abs)/s.k:0,A=_[0]*_[1]>0?di(_,Math.abs)/s.k:0;if(b||A){let g=s.translate(b,A);return this.transition(this.svg).call(this.zoom.transform,g).end().catch(kt)}}async centerNode(e,r){var n;let i=(n=this.findElement(e))==null?void 0:n.data;if(!i)return;let o=this.svg.node(),a=o.getBoundingClientRect(),s=tt(o),l=(i.state.rect.x+i.state.rect.width/2)*s.k+s.x,u=(i.state.rect.y+i.state.rect.height/2)*s.k+s.y,f={left:0,right:0,top:0,bottom:0,...r},p=(f.left+a.width-f.right)/2,d=(f.top+a.height-f.bottom)/2,x=(p-l)/s.k,_=(d-u)/s.k;if(x||_){let b=s.translate(x,_);return this.transition(this.svg).call(this.zoom.transform,b).end().catch(kt)}}async rescale(e){let r=this.svg.node(),{width:n,height:i}=r.getBoundingClientRect(),o=n/2,a=i/2,s=tt(r),l=s.translate((o-s.x)*(1-e)/s.k,(a-s.y)*(1-e)/s.k).scale(e);return this.transition(this.svg).call(this.zoom.transform,l).end().catch(kt)}destroy(){this.svg.on(\".zoom\",null),this.svg.html(null),this._disposeList.forEach(e=>{e()})}static create(e,r,n=null){let i=new t(e,r);return n&&i.setData(n).then(()=>{i.fit()}),i}};window.markmap={Markmap:ke,deriveOptions:yi};})();\n/*! Bundled license information:\n\nmarkmap-common/dist/index.mjs:\n (*! @gera2ld/jsx-dom v2.2.2 | ISC License *)\n*/\n"}};
const UI_FINGERPRINT = "2d331d41223782ff26dd5e5f1150cde9e6a686dd949c4a314a54eda3887e92a9";
function b64ToBytes(b64) { const bin = atob(b64); const a = new Uint8Array(bin.length); for (let i = 0; i < bin.length; i++) a[i] = bin.charCodeAt(i); return a; }
export default {
async fetch(request, env) {
const url = new URL(request.url);
let p = url.pathname;
// 🔴 UI 自報版本(安裝器據此判斷要不要重推,取代「猜 favicon 特徵」)。
// 比照 cypher 的 /health。舊世代的 UI 沒有這條路由 ⇒ SPA fallback 回 HTML
// ⇒ 安裝器解析 JSON 失敗=判定為舊版=重推。**天然向後相容,不需額外世代判斷。**
// bundle_version 由安裝器以 ARCRUN_BUNDLE_VERSION 注入(cypher /health 同一個值);
// 沒注入就回空字串,安裝器那端把空值一律當「舊的」處理。
if (p === '/__version') {
// 🔴 2026-08-08:多報 worker_subdomain / config_ok 兩格。
// 這條路由是**安裝器唯一會去問實例的地方**probeInstanceStale),
// 以前它只報版本 ⇒「版本對、但 apiBase 空」的實例在安裝器眼中是「已是最新」
// ⇒ 永遠不會被重推=壞掉的實例自己好不了。報了之後,安裝器把
// config_ok:false 一律當成 stale ⇒ **下一次安裝/更新就自動治好它**。
return new Response(JSON.stringify({
ok: true,
ui_fingerprint: UI_FINGERPRINT,
bundle_version: env.ARCRUN_BUNDLE_VERSION || '',
worker_subdomain: env.WORKER_SUBDOMAIN || '',
config_ok: Boolean(env.WORKER_SUBDOMAIN),
}), {
headers: { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' },
});
}
// config.js 動態產生:apiBase 指向同帳號的 cypherWORKER_SUBDOMAIN 由安裝器注入)
//
// 🔴 2026-08-08 事故(leo 的 youlin 實例整頁不能用,頂端紅字「設定檔沒載入」):
// 有人用 wrangler deploy 手動補這顆 worker ⇒ 繞過安裝器的變數注入
// ⇒ WORKER_SUBDOMAIN 空 ⇒ 這裡**安靜地**退成 apiBase:""(而且回 HTTP 200!)
// ⇒ 前端連不到自己的後端,但**部署是「成功」的**:worker 活著、curl 200、
// /__version 版本也對——只有真人打開瀏覽器才看得出壞了。
// 正解不是「退一個合理的預設值」(沒有合理預設,猜錯更慘),
// 是**大聲失敗**:回 500+專用標頭,讓機器檢查一眼看穿。
// 瀏覽器不執行非 2xx 的 <script>,所以用戶端行為與今天一致
// (portal 照樣顯示「設定檔沒載入」紅字),差別是**機器也看得見了**。
// no-store:這頁被邊緣快取過就會「修好了還是壞的」(08-08 實撞,害人誤判修復失敗)。
if (p === '/config.js') {
const sub = env.WORKER_SUBDOMAIN || '';
if (!sub) {
return new Response(CONFIG_MISSING_BODY, {
status: 500,
headers: {
'content-type': TYPES_JS,
'cache-control': 'no-store',
'x-arcrun-config-error': 'WORKER_SUBDOMAIN-missing',
},
});
}
const apiBase = `https://arcrun-cypher-executor.${sub}.workers.dev`;
return new Response(`window.ARCRUN_CONFIG = { apiBase: ${JSON.stringify(apiBase)} };`, {
headers: { 'content-type': TYPES_JS, 'cache-control': 'no-store' },
});
}
if (p.endsWith('/')) p += 'index.html';
let f = FILES[p] || FILES[p + '/index.html'] || FILES[p + '.html'];
if (!f && !p.includes('.')) f = FILES[p + '/index.html'];
if (!f) { p = '/portal/index.html'; f = FILES[p]; } // SPA fallback→portal
if (!f) return new Response('not found', { status: 404 });
const body = f.b64 ? b64ToBytes(f.data) : f.data;
return new Response(body, { headers: { 'content-type': f.type, 'cache-control': 'no-cache' } });
},
};
const TYPES_JS = 'application/javascript; charset=utf-8';
const CONFIG_MISSING_BODY = [
'/* ============================================================',
' arcrun-rag-uiWORKER_SUBDOMAIN 這個變數沒有被注入。',
' 算不出 apiBase = 前端不知道自己的後端在哪 = 整個 portal 不能用。',
'',
' 成因幾乎一定是:這顆 worker 被手動 wrangler deploy 部署,繞過了注入。',
' 修法(擇一):',
' 1. 重跑一次安裝器(它會注入,且會把這顆判定為 stale 而重推)',
' 2. node installer/scripts/deploy-ui.mjs --subdomain <你的 workers.dev 子網域>',
' ============================================================ */',
'throw new Error("arcrun-rag-ui: WORKER_SUBDOMAIN 未注入,apiBase 無法產生");',
].join('\n');