修 arcrun-rag#10:補 /portal/admin/ai(key 從來沒存進去的真因)+UI 已輸入態
真因(不是重裝洗掉,是從來沒存進去):前端唯一寫入路徑 POST /portal/admin/ai
**後端從來沒有這條 route** ⇒ 用戶填 key → 404 → 什麼都沒存,畫面卻像成功了(藍字=假綠)。
產物層鐵證:bundle tier2/ui grep 'portal/admin/ai'=1、tier2/cypher=0;兩實例實打皆 404。
反證(別改不壞的東西):走正確端點寫入 → 完整重裝 24/24 → credential 仍在、
rag_chat verdict failed→success ⇒ **重裝不洗 credential,資料層本來就是保留式的**。
① cypher 補 GET|POST /portal/admin/ai(routes/portal.ts)
- POST 內部轉呼 credentials.ts 既有 storeCredential()=**唯一寫入路徑**,不另造第二套
- GET 只回 has_key 布林,**永不回傳 key 本身**(D36)
- credential 的 api_key 欄=租戶 slug(portalTenant),與安裝器 seedCredential 寫
kbdb_internal_token 用的 ns 同值 ⇒ 同租戶分區,彼此查得到
- use_claude_for_extract 存 KV(單一布林偏好,不為它開 KBDB template)
- claude_available 目前無訊號來源(該由小幫手回報)⇒ **誠實回 false 不假綠**
- 寫入失敗回 502 帶原因——本 bug 的教訓就是「不能讓前端以為存好了」
- 兩者皆未提供 → 400,避免「看起來成功但什麼都沒做」
② 前端(console-ui/public/portal/index.html)
- 拔掉寫死 `|| "https://cypher.arcrun.dev"` fallback ⇒ 缺 config.js 就顯示紅色橫幅明顯報錯。
**寧可明顯失敗,不要靜默把用戶金鑰送去中央實例。**
⚠️ 更正我先前的錯誤診斷:config.js **有**正確注入(實查 leo 實例指向自己的 cypher),
跨租戶錯置未發生;這條是未爆彈不是現行災情。
- leo 規格:已存 → 唯讀「已輸入」+「修改」鈕(不顯示 key);按修改才變回輸入框;
未存 → 一般輸入框。舊版只改 placeholder=讀起來像臨時提示,是它像 UI bug 的原因。
- 只有真的送了新 key 才切回「已輸入」(單純改 Claude 勾選不誤報)
tsc 綠;三個 script 區塊 node --check 全過。
卷:system-dev/docs/3-specs/journeys/gemini-key-lost-on-reinstall.md
This commit is contained in:
@@ -164,7 +164,23 @@
|
||||
.kvline { display: flex; justify-content: space-between; gap: 12px; font-size: 15px; margin: 5px 0; }
|
||||
</style>
|
||||
<script src="/config.js"></script>
|
||||
<script>window.ARCRUN_API_BASE = (window.ARCRUN_CONFIG && window.ARCRUN_CONFIG.apiBase) || "https://cypher.arcrun.dev";</script>
|
||||
<script>
|
||||
// apiBase 由安裝器注入的 config.js 提供(實查用戶實例:
|
||||
// window.ARCRUN_CONFIG = { apiBase: "https://arcrun-cypher-executor.<subdomain>.workers.dev" })。
|
||||
// 🔴 2026-08-01 拔掉舊的 `|| "https://cypher.arcrun.dev"` fallback:
|
||||
// 那是「靜默打到別人家」的未爆彈——config.js 一旦沒載入/被擋/改名,
|
||||
// 前端會安靜地把請求(含**用戶金鑰**)送去中央實例,而不是明顯壞掉。
|
||||
// **寧可明顯失敗,不要靜默錯置。**
|
||||
window.ARCRUN_API_BASE = (window.ARCRUN_CONFIG && window.ARCRUN_CONFIG.apiBase) || "";
|
||||
if (!window.ARCRUN_API_BASE) {
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var b = document.createElement('div');
|
||||
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';
|
||||
b.textContent = '設定檔沒載入(config.js),這個頁面連不到你的服務。請重新整理;若持續發生,請重跑一次安裝。';
|
||||
document.body.appendChild(b);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -355,6 +371,15 @@
|
||||
<div>
|
||||
<div style="font-size:14px;font-weight:500;margin-bottom:4px">Gemini API Key</div>
|
||||
<div style="font-size:13px;line-height:1.6;color:rgba(var(--ink-rgb),.55);margin-bottom:8px">聊天問答與文件萃取都用這一把。<a href="https://aistudio.google.com/apikey" target="_blank" rel="noopener">免費申請</a>,金鑰只存在你自己的知識庫裡。</div>
|
||||
<!-- 已存狀態(leo 2026-08-01 規格):唯讀顯示「已輸入」+「修改」鈕,**不顯示 key 本身**。
|
||||
舊版只把 placeholder 改成藍色小字「已設定」⇒ 讀起來像臨時提示、不像已保存的記錄,
|
||||
這正是它看起來像 UI bug 的原因(arcrun-rag#10 附帶修正)。 -->
|
||||
<div id="st-ai-key-saved" style="display:none;align-items:center;gap:10px">
|
||||
<span style="flex:1;padding:9px 12px;border:1px solid rgba(var(--ink-rgb),.14);border-radius:8px;background:rgba(var(--ink-rgb),.03);font-size:14px">
|
||||
<b>已輸入</b><span style="color:rgba(var(--ink-rgb),.45)">(金鑰已安全保存,不顯示內容)</span>
|
||||
</span>
|
||||
<button type="button" class="btn" id="st-ai-key-edit" style="flex:none">修改</button>
|
||||
</div>
|
||||
<input type="password" id="st-ai-key" class="txt" placeholder="貼上 Gemini API Key" autocomplete="off">
|
||||
</div>
|
||||
<!-- 第二格:Claude 加強版(選填,依 daemon 回報 enable) -->
|
||||
@@ -796,6 +821,34 @@ function taipeiMonthDay(ms) { var d = new Date(ms + TAIPEI_OFFSET_MS); return {
|
||||
|
||||
// t131 AI 設定(合併 Gemini API Key+Claude 加強版)
|
||||
(function () {
|
||||
/**
|
||||
* 切換金鑰欄的「已存 / 可輸入」兩態(leo 2026-08-01 規格,arcrun-rag#10):
|
||||
* 已存 → 唯讀顯示「已輸入」+「修改」鈕(**不顯示 key 本身**,D36)
|
||||
* 未存 / 按了修改 → 一般輸入框
|
||||
* 為什麼要這樣:舊版只把 placeholder 改成「已設定」=看起來像臨時提示,
|
||||
* 用戶讀不出「這是已保存的記錄」⇒ 以為沒存到、反覆重填。
|
||||
*/
|
||||
function setAiKeySaved(saved) {
|
||||
var box = $('st-ai-key-saved');
|
||||
var input = $('st-ai-key');
|
||||
if (!box || !input) return;
|
||||
if (saved) {
|
||||
box.style.display = 'flex';
|
||||
input.style.display = 'none';
|
||||
input.value = '';
|
||||
} else {
|
||||
box.style.display = 'none';
|
||||
input.style.display = '';
|
||||
}
|
||||
}
|
||||
// 按「修改」→ 變回可輸入框並聚焦(留空送出=不變更,由後端 body 判斷)
|
||||
var editBtn = $('st-ai-key-edit');
|
||||
if (editBtn) editBtn.addEventListener('click', function () {
|
||||
setAiKeySaved(false);
|
||||
var input = $('st-ai-key');
|
||||
if (input) { input.placeholder = '貼上新的 Gemini API Key(留空取消變更)'; input.focus(); }
|
||||
});
|
||||
|
||||
// 進入設定頁時讀取現有設定(GET /portal/admin/ai)
|
||||
function loadAiConfig() {
|
||||
if (!(S.profile && S.profile.role === 'admin')) return;
|
||||
@@ -803,8 +856,8 @@ function taipeiMonthDay(ms) { var d = new Date(ms + TAIPEI_OFFSET_MS); return {
|
||||
.then(function (r) { return r.ok ? safeJson(r) : null; })
|
||||
.then(function (d) {
|
||||
if (!d) return;
|
||||
var ki = $('st-ai-key');
|
||||
if (ki && d.has_key) ki.placeholder = '已設定(留空=不變更)';
|
||||
// leo 2026-08-01 規格:已存 → 唯讀「已輸入」+「修改」鈕;未存 → 一般輸入框
|
||||
setAiKeySaved(!!d.has_key);
|
||||
var cb = $('st-ai-use-claude');
|
||||
if (cb) {
|
||||
// 有 claude 才能勾;沒有則停用並顯示提示
|
||||
@@ -850,7 +903,9 @@ function taipeiMonthDay(ms) { var d = new Date(ms + TAIPEI_OFFSET_MS); return {
|
||||
sb.disabled = false;
|
||||
if (guard401(x.status)) return;
|
||||
if (!x.ok) { m.textContent = (x.d && x.d.error) || '儲存失敗'; m.style.color = '#b4462f'; return; }
|
||||
if ($('st-ai-key')) { $('st-ai-key').value = ''; $('st-ai-key').placeholder = '已設定(留空=不變更)'; }
|
||||
// 存好了才切回「已輸入」唯讀態。只有真的送了新 key 才切;
|
||||
// 單純改 Claude 勾選(k 為空)時維持現狀,不誤報「已輸入」。
|
||||
if (k) setAiKeySaved(true);
|
||||
var claudeOn = x.d && x.d.use_claude_for_extract;
|
||||
m.textContent = claudeOn
|
||||
? '已儲存,萃取改用 Claude Code。小幫手請重連一次生效。'
|
||||
|
||||
Reference in New Issue
Block a user