66f1b59f7f
leo 回報四件事:①雲端 Gemini 無法用 ②搞不清楚設定 AI 是設雲端還是地端 ③地端不會萃、每個人都死掉因為都去抓 Claude ④雲端還要設置明明就有 Workers AI。 目標:「雲端裝好就能用,地端輸一個 Gemini API Key,然後就開始用。」 根因:extractor_config 的 KV key 由 portalTenant() 組出,而 portalTenant 是 **worker 層級**環境變數(portal.ts:43)⇒ **全租戶共用一把**。任一處設了 claude, 所有人的 daemon 都收到 claude;沒裝 Claude Code 的機器萃取全滅,而 portal 的 Claude 勾選框又恆 disabled(daemon 從未實作 report-capabilities ⇒ daemon_caps 永遠空) ⇒ 用戶自己解不開(awindhon 08-03 實證:雲端同步成功、金鑰有效、零張卡)。 本次(雲端側): - POST /portal/daemon/config **不再下發** extractor/gemini_api_key/llm_model, 只回連線欄位。⚠️ route 本身與 daemon/libraries 資料夾管理完全不動(leo 明確劃界: 「雲端拉地端檔案夾部分不要刪,刪掉從雲端設置地端 LLM 選項部分」)。 - 移除 POST|GET /portal/admin/extractor(t122)——這是「雲端指定地端引擎」的入口, 且無任何伺服器端驗證,打一下就能把全租戶設成 claude。 - 移除 POST /portal/daemon/report-capabilities(t131)——daemon 端從未實作該呼叫。 - 移除 t131 那組重複註冊的 /portal/admin/ai。**它是重複 route**:後段(arcrun-rag#10) 另有同路徑一組,Hono 先到先比 ⇒ 舊的一直贏,後段修好的「金鑰真的寫進 credentials」 形同死碼。保留後段那組(只管 Gemini 金鑰、走 storeCredential),並拿掉 Claude 偏好欄。 - portal 設定頁「AI 設定」整塊移除,改成一句話說明:雲端不需設定(Workers AI 免金鑰), 地端請在同步小幫手的「AI 設定…」填 Gemini Key。順手清掉 main 上既有的 conflict 標記。 - 清掉隨之孤兒化的 helper(ExtractorConfig/AiConfig/DaemonCapabilities/ syncExtractorFromAiConfig/readAiPref 等)。 測試:**相對 merge 前 main 基準線,新增失敗 = 0**(基準線本就 9 紅:console 藏書地圖 6/ portal HTML 殼 2/POST execute 1,皆與本次無關)。t122/t131 兩組測試改寫成 **回歸守衛**(斷言那些端點/欄位確實 404、確實不存在),不是刪掉充綠。 順手修 health bundle_version 測試與實作對齊(實作刻意省略該欄,測試卻期待空字串)。 未送達:本 commit 只到 code,尚未部署上線。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
30 lines
1.4 KiB
TypeScript
30 lines
1.4 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { SELF } from 'cloudflare:test';
|
|
import { healthRouter } from '../src/routes/health';
|
|
import type { Bindings, ExecutionContext } from '../src/types';
|
|
|
|
describe('GET /health — bundle_version 欄位', () => {
|
|
it('無 ARCRUN_BUNDLE_VERSION 時省略該欄(老實例情境)', async () => {
|
|
// wrangler.test.toml 不設此 var → health.ts 省略 bundle_version 欄位。
|
|
// daemon 端讀不到該欄=當作空字串=判 stale,對老實例而言**這是正確行為**
|
|
//(見 health.ts 檔頭註解)。此處驗「省略」而非「回空字串」,與實作對齊。
|
|
const res = await SELF.fetch('http://localhost/health');
|
|
const data = await res.json() as { ok: boolean; bundle_version?: string };
|
|
expect(res.status).toBe(200);
|
|
expect(data.ok).toBe(true);
|
|
expect(data.bundle_version).toBeUndefined();
|
|
});
|
|
|
|
it('有 ARCRUN_BUNDLE_VERSION 時回其值(安裝器注入情境)', async () => {
|
|
const fakeEnv = { ARCRUN_BUNDLE_VERSION: '2026-07-28/6d06162' } as unknown as Bindings;
|
|
const res = await healthRouter.fetch(
|
|
new Request('http://localhost/health'),
|
|
fakeEnv,
|
|
{} as ExecutionContext,
|
|
);
|
|
const data = await res.json() as { ok: boolean; bundle_version: string };
|
|
expect(data.ok).toBe(true);
|
|
expect(data.bundle_version).toBe('2026-07-28/6d06162');
|
|
});
|
|
});
|