81 lines
706 KiB
JavaScript
81 lines
706 KiB
JavaScript
// arcrun-rag-ui — 用戶實例的 GUI(console-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-01(arcrun-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 // 台北時間 helper(lib/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) => ({ '&': '&', '<': '<', '>': '>', '\"': '"', \"'\": ''' }[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-01(arcrun-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 <!-- t36(leo 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 // 台北時間 helper(lib/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 { '&': '&', '<': '<', '>': '>', '\"': '"', \"'\": ''' }[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*>\\s?/.test(line)) { closeList(); out.push('<blockquote>' + mdInline(line.replace(/^\\s*>\\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 // 隱藏頁/不存在頁 guard:hash 不在 VIEWS → 改寫成 HOME(hashchange 會再進來一次正常渲染)\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/map(cypher 代轉 KBDB 基本盤,kbdb-proxy.ts——同 /kbdb/search 慣例)。\n // 兩段式渲染:先用全館列表(top_entities=名字 top3)立即出卡片,再逐庫拉 /kbdb/map/:library\n // 補 degree/bridges/commit_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 // ── 零件 / recipes(v0 搜尋台保留區)──\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#9:todo+inbox 二源、三欄 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 entries(Logseq 萃取,ingest 灌入中)+ inbox entries(Telegram)。<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-check(console session 保護的小端點——瀏覽器沒有 KBDB\n // token,PATCH 由 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#25:portal admin 密碼救援——只吃 console owner session(S.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/#82,leo 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 root(leo 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 #17181A/Paper #FDFCFB/Canvas #F2F1ED/Muted #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.on,console 同修)── */\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 用 --amber/Relation\n 當 logo 色——CIS:Relation 是「唯一強調色」不是品牌色,logo 上色是一句謊話),\n 靠兩張圖(-ink/-paper-on-ink)依 data-theme 切換,不用 filter 避免色偏。\n 08-01 二次修正:官方原始 PNG(1840x560)畫布只有 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#152(leo 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#152(leo 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#152(leo 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#44:leo「要看到從 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/macOS/Android 各長一套,\n 同一份畫面在不同機器上不一致,設計稿無法被保證;\n ② emoji 吃不到 CIS 的 --ink/--amber ⇒ 切深色模式時它不會跟著變色;\n ③ 本 repo 的 CIS 是紙感墨字(見 system-dev/wiki/cis-web-style.md)。\n 尺寸/筆畫全部照 leo 核准的設計稿(Main.dc.html/Launcher-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.12(MIT)=檢索過程樹狀圖的佈局與渲染引擎。leo 2026-08-18:\n 「類似 https://markmap.js.org/ 可以把文字轉圖,**不要自造輪胎**。」\n · 為什麼 vendored 不走 CDN:這頁由 worker 內嵌供檔、今天零外部依賴,\n 企業內網/離線實例也要打得開;走 CDN 等於把「能不能看檢索過程」綁在第三方網域活著。\n · 為什麼只有 markmap-view,沒有 markmap-lib:後者是 markdown 解析器(依賴鏈 741KB,\n 含 katex/highlight.js/prismjs),而我們的檢索過程本來就是結構化資料,\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 sprite(Arcrun#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.html/Launcher-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<!-- 首次設定(t49,leo 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#152:OS 級四段導覽——取代原本的單層清單。已安裝的 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-suite:upload 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 零件/Recipe/Credential 現在活在另一套 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/零件/Recipe/Credential</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-02(leo:「不顯示的話用戶不知道要不要更新」+「發現落後就按一下開啟 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 <!-- D62(leo 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-09(arcrun-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\">接上你的 AI(MCP)</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 <!-- t176(leo 08-03):AI 設定整塊移除。\n 雲端聊天問答走 Workers AI(用戶自己 CF 帳號內建,**免金鑰、裝好就能用**);\n 地端萃取用哪把金鑰改由「同步小幫手」自己設定(托盤選單「AI 設定…」)。\n 為什麼移除:雲端的 extractor 設定是全租戶共用一把 KV,任一處設了 claude\n 會讓所有沒裝 Claude Code 的機器萃取全滅,而這裡的 Claude 勾選框又恆為\n disabled(daemon 從未回報 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-08(t213,InkStoneCo 總管交辦)發現這顆按鈕在**封測者的瀏覽器**裡執行,\n 跟他電腦上的 daemon 是兩個獨立行程,構不到本機資料(檔案總量/失敗分類/\n daemon 版本)——完整版改在 arcrun-app(同步小幫手)「版本與更新」頁本機端匯出\n (打新端點 GET /portal/daemon/diagnostics)。當時按鈕先保留當退路,文案改成\n 誠實講清楚自己只有一半、導去完整版。\n\n 2026-08-09(leo 拍板拿掉):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 <!-- 管理(P4,admin-only:nav 只有 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 // 台北時間 helper(lib/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 { '&': '&', '<': '<', '>': '>', '\"': '"', \"'\": ''' }[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 再上格式,防 XSS;console 同款)──\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*>\\s?/.test(line)) { closeList(); out.push('<blockquote>' + mdInline(line.replace(/^\\s*>\\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 顯示 helpers(source/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-t21,2026-08-05 分支整理救回):\n // 新 ingest 鏈(rag_ingest_card/rag_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-07:entry_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 系統 v0(K5):'app' 是**唯一**代表「隨便哪個已安裝 App」的 view——\n // 具體是哪一個由 S.appId(route 的 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-24(Arcrun#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#152,leo 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-status(configured 布林,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 // t53(leo 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-X/tab-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 // t161(leo 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-27,leo:「客戶是用 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 // t176(leo 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:複製任意網址到剪貼簿的共用 helper(08-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-09(arcrun-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#81(leo 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#81(leo 08-12):第二項「啟用 AI 問答(貼 Google AI 金鑰)」整條刪除。\n // 為什麼不是「一個沒用的欄位」而已:它長在**安裝完成清單裡而且是勾選項**\n // ⇒ 用戶會以為不做這步就沒裝完,而它要人離開流程、去第三方網站申請帳號、\n // 把金鑰貼進表單——整條安裝路徑上最重的一個動作,而且是白做的。\n // 真相:雲端問答走 t181(08-04)改好的 Workers AI(`env.AI` binding,免金鑰)——\n // /portal/data/chat → tenant 的 rag_chat workflow → `workers_ai_chat` recipe\n // (api-recipe-seeds.ts:150,endpoint `@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 // t54:config.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 #44:answer/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 — **這個軟體裡唯一的樹狀渲染入口**(D97,leo 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 沒有存 hostname/machine 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 // maxWidth/spacingHorizontal 壓小=樹變窄=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-18,Chrome)兩種量法\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 而不是 setTimeout/rAF:markmap 寫 `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 沒有 hostname/machine id/device 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 只代查再作答;答案附 sources(mode+page),點 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-wrap+esc,不走 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#100:leo 看到\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 // 固定種子 PRNG(mulberry32):確定性佈局\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 系統 v0:Portal 泛用 loader(K5)──\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 // ── Icon(Arcrun#152):描邊式 inline SVG,不用 emoji ─────────────────────\n // 為什麼換掉 emoji:① emoji 是各作業系統自帶的彩色點陣字形,Windows/macOS/\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 // 遇到不認得的 icon(App 宣告裡自己填的 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#152,leo 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/#82,leo 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/upload;Gitea 位置與 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 尾段即 base64(unicode 安全,免手刻 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-retention,role=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_id,entries 標 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_version)vs 最新版(安裝器 /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-05:Mac 一律給 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 指向同帳號的 cypher(WORKER_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-ui:WORKER_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');
|