leo 2026-07-20 明令:「已經改用 cf 自己的 secrets,不要再說它了」 「我希望以後再也看不到這個詞再出現」 背景:credential 早已遷移至 CF Workers per-script Secrets + D1 目錄, 舊的自管金鑰(client 端 AES-GCM + KV 密文 + crypto_decrypt)是遷移期遺留。 本次連根移除,含一併作廢的死 SaaS 碼。 移除: - 舊 KV 密文解密路徑(credential-injector.ts 整檔、dual-read fallback) 前置驗證:leo21c / youlin 兩帳號 CREDENTIALS_KV 實測 *:cred:* 皆 0 筆 - migrate-to-workers-secrets 搬家端點(回填已完成,無可回填) - /register 路由與 generateApiKey(HMAC 產 ak_ key 是 SaaS 遺物; self-hosted 走 namespace 明碼 D21,已無人使用) - platform_crypto component(三帳號實測 404 已退役,無 workflow 引用) 保留(附理由): - crypto_decrypt 保留為永遠回失敗的 stub——現役三個 auth .wasm 仍宣告該 import,缺項會讓 WASM instantiate 直接失敗。待零件重編後可真正刪除。 順帶修復(原不在範圍,但會實際壞事): - /auth/callback 有 `if (!key) redirect(server_error)` 閘,未設該 secret 的 實例會登入直接失敗 → 已移除 - OAuth 兩處把 provider token 寫進舊加密 KV(租戶鍵與實際 api_key 在 rotate 後必然分歧,已失效)→ 改導向 Workers Secrets,包 try/catch 不影響登入 - acr init Standard 模式呼叫已刪除的 /register → 改引導 OAuth 取 key - .claude/rules 與 system-dev/docs 是同一規範的兩份鏡像,先前只改 rules 導致鏡像仍在教舊做法 → 已同步(此類雙檔同步應納入檢查) 新用戶安裝從此零 secret 前置。 測試 187/188(唯一 fail 為 pre-existing,stash 驗證與本次無關); cypher-executor 與 cli typecheck 全綠。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
27 KiB
Design 補充:acr init --self-hosted 一鍵自動化(installer 模式)
2026-06-01 初稿 → 2026-06-02 定案改寫(richblack 拍板 installer 形態)。 本檔是
sdk-and-website/design.md的單檔補充(規則 02 §4.3 允許)。 狀態:design 已與 richblack 對齊;實作前讀 §6 前置依賴。 背景:戰法從 SaaS 轉 self-hosted 開源(docs/HANDOFF-self-host-harness.md §0)。
1. 定案形態(richblack 2026-06-02)
arcrun CLI = installer / orchestrator(類似 rustup / nvm:工具本身小,按需從遠端拉真正內容)。
用戶只做 4 件事,中間什麼都不用懂:
- 申請 CF 帳號
- 安裝 CF CLI(
wrangler) - 安裝 arcrun CLI(
npm i -g arcrun) acr init --self-hosted(貼 CF Account ID + API Token)→ 完成,其餘看機器跑
CLI 自動做(用戶無感):
- 驗 CF token 權限
- 建 7 個 KV namespace + 1 個 R2 bucket(冪等)
- 從 GitHub release 下載預編譯部署物(含 24 個
.wasm+ 各 Worker 的 wrangler.toml + cypher-executor/registry) - 把建好的 KV namespace id 注入各 wrangler.toml + cypher-executor 的
WORKER_SUBDOMAIN wrangler deploy部署全部 Worker(用戶已裝 wrangler)- seed auth recipe + API recipe 進 RECIPES KV
- 寫回
~/.arcrun/config.yaml - 印出「手動
wrangler secret put CF_SECRETS_API_TOKEN」提示(secret 不自動化,rule 05)
關鍵技術決策(richblack 2026-06-02)
| 決策 | 選擇 | 理由 |
|---|---|---|
| 零件部署物 | 預編譯 .wasm(不在用戶端 build) |
用戶不懂 tinygo、也不該懂。下載即用。 |
| 部署工具 | wrangler(shell out) | 用戶已裝 CF CLI;self-host 本來就有上傳能力。CLI 不自己重寫 CF Script Upload API。 |
| 源碼來源 | GitHub release tarball(含預編譯 wasm) | 版本明確、不需用戶有 git、acr update 拉新 release 同一條路。 |
| 為何不是 git clone | repo 沒 commit .wasm(rule 05 build 產物不 commit)→ clone 拿不到 wasm |
必須走含 wasm 的 release artifact。 |
2. 為什麼是 installer 而非「repo 內掃 wrangler.toml」(推翻初稿)
初稿假設「用戶在 repo 內跑、CLI 掃 wrangler.toml」。推翻,因為:
- npm 全域裝的
acr手上沒有 24 個 Worker 源碼。 - repo 沒 commit
.wasm(已查證git ls-files .component-builds | grep .wasm= 0)→ 連 clone 都拿不到可部署的 wasm。 - 用戶不該需要懂 git / tinygo / repo 結構。
→ 正解:CLI 當 installer,從 GitHub release(含預編譯 wasm) 拉部署物到暫存目錄,在暫存目錄注入 KV id 後 wrangler deploy。
3. 流程設計(initSelfHosted 改寫)
acr init --self-hosted
│
├─ 1. 問 2 輸入:CF Account ID + CF API Token
│ (wrangler 是否已裝?which wrangler;沒裝 → 提示先裝 CF CLI 再來)
│ 驗 token:CF API GET /accounts/{id}/tokens/verify + GET /accounts/{id}
│ 缺權限(Workers Scripts Edit / KV Edit / R2 Edit)→ exit 1 指出缺哪個 scope
│
├─ 2. 建資源(冪等:先 list 已存在就重用)
│ 7 KV:WEBHOOKS / CREDENTIALS_KV / RECIPES / USERS_KV /
│ SESSIONS_KV / ANALYTICS_KV / EXEC_CONTEXT(rule 01 資料儲存表)
│ 1 R2:WASM_BUCKET
│
├─ 3. 下載部署物:GitHub release tarball → 解壓到暫存目錄 (~/.arcrun/.deploy-<ver>/)
│ 內含:cypher-executor/ + registry/ + .component-builds/*(每個含預編譯 component.wasm + wrangler.toml)
│
├─ 4. 注入設定到暫存目錄的 wrangler.toml(不改用戶 repo,改暫存副本)
│ - 各 Worker 的 KV binding id ← step 2 建立的
│ - cypher-executor [vars] WORKER_SUBDOMAIN ← CF API GET /accounts/{id}/workers/subdomain
│
├─ 5. 部署:對暫存目錄每個含 wrangler.toml 的 dir,shell out
│ `wrangler deploy`(env CLOUDFLARE_API_TOKEN=<token>, CLOUDFLARE_ACCOUNT_ID=<id>)
│ 分兩層:tier1 = .component-builds/*(先)→ tier2 = cypher-executor / registry(後)
│ 每個 wrangler.toml 已含 workers_dev = true → workers.dev URL 自動啟用
│
├─ 6. seed recipe 進 RECIPES KV(部署後打新 cypher URL,或直接 CF KV API 寫)
│ - auth recipe:重用 AUTH_RECIPE_SEEDS(cypher-executor/src/lib/auth-recipe-seeds.ts)
│ - API recipe:新增 seed-api-recipes.ts(見 §5)
│
├─ 7. 寫回 config(mode: self-hosted + 所有 id + cypher_executor_url = 部署後 workers.dev URL)
│
└─ 8. 印手動 secret 提示:
wrangler secret put CF_SECRETS_API_TOKEN --name arcrun-cypher-executor
(credential 值交 CF Workers Secrets 託管;auth 零件不需 secret)
acr update(同一條路,未來新零件)
- 拉新 GitHub release → 解壓 → 注入既有 config 的 KV id → wrangler deploy 變動的 Worker。
- 第一期至少做到「重跑等效 init 的部署步驟」;diff-only 部署可後續優化。
4. 動到的檔案
| 檔案 | 動作 |
|---|---|
cli/src/commands/init.ts |
改寫 initSelfHosted()(line 105-131)為 installer 流程 |
cli/src/lib/cf-api.ts |
擴充:KV namespace 建立/list、R2 bucket 建立、subdomain 查詢、token verify |
新增 cli/src/lib/deploy.ts(暫定) |
下載 release tarball + 解壓 + 注入 wrangler.toml + shell out wrangler deploy |
新增 cli/src/commands/update.ts(暫定) |
acr update:拉新 release 重部署 |
新增 cli/src/lib/api-recipe-seeds.ts |
API recipe 種子資料(installer 用;放 CLI 端,不放 cypher-executor/src——rule 02 §2.2 hook 擋 cypher-executor TS hard-code endpoint,且 seed 資料本就屬 installer 職責) |
新增 cypher-executor/scripts/seed-api-recipes.ts |
seed 腳本(給 prod 補灌用,import CLI 的種子資料;scripts/ 不受 §2.2 hook 管) |
cli/src/index.ts |
註冊 acr update 指令 |
不動:cypher-executor 執行路徑、既有零件 wasm 源碼、config 讀取端(config.ts:52 已支援 self-hosted)。
5. API recipe seed(新增 seed-api-recipes.ts,richblack 2026-06-02 定)
codebase 只有 auth recipe seed。新增 seed-api-recipes.ts,把現役 API recipe hard-code 成種子。
現役 API recipe(從 prod KV 查得,2026-06-01)
kbdb_get(+ create_block / patch_block / delete / ingest)→ auth_service: kbdbgmail_send→ google_gmail_sagoogle_sheets_append/google_sheets_read→ google_sheets_satelegram_send→ telegramline_notify_send→ line_notify
KBDB recipe 採 Supabase 模式(richblack 2026-06-02)
- KBDB 是 richblack 提供的服務(跟 arcrun 一樣),採「基礎免費、大量收費」。
- KBDB recipe 進 seed(展示能力 = 引子,Supabase 模式)。使用者要用 → 去 arcrun 取統一 API Key(已有 /register 入口),把 key 設成 credential。
- ⚠️ FOLLOW-UP(交 KBDB 端):現役 endpoint 是
kbdb.finally.click{{_path}}。richblack:這是 KBDB 端要改的問題——KBDB 該用統一對外網址提供大家用,不是 finally.click。seed 先照現況進;KBDB 端改網址後同步更新 seed。 此事不擋 init 實作。
6. 部署物產製:commit wasm 進 repo + codeload tarball(richblack 2026-06-02 定案)
此節取代初稿的「GitHub release artifact」構想。richblack 拍板更輕的做法: 直接把預編譯 wasm commit 進 repo,CLI 從 GitHub codeload tarball 拿。不需 release.yml 機制。
6.1 策略
- repo 自帶可部署的 wasm:刪
.gitignore的*.wasm排除,commit 預編譯 wasm 進 repo。 → repo 本身就是部署來源,CLI 直接拿、用戶用自己的 CF token deploy。 - CLI 走 codeload tarball:
https://codeload.github.com/richblack/arcrun/tar.gz/{ref}(ref = main 或 tag)。用戶不需 git、版本可控(tag)。acr update拉新 ref。 - 理由(richblack):「我在我的 CF 能用 = 我已擁有 wasm;用戶指向我的 GitHub 取得 wasm, 用他自己的 CF credential deploy。開源,看不看源碼不重要,體驗好最重要。」
6.2 ⚠️ 推翻既有鐵律(rule 05)— 需同步改規則
.claude/rules/05-deploy-convention.md 明文「.component-builds/{name}/component.wasm 不 commit 進 repo
(build 產物)」「Phase 1-3 暫時 commit 過,之後會加 .gitignore 清理」。
本決策反向:commit wasm 進 repo(self-host 需 repo 自帶可部署 wasm)。
→ 實作時必須同步改 rule 05 + .gitignore,否則 pre-write hook / 規則與實作打架。
→ deploy.yml 的 CI rebuild 步驟仍保留(CI 部署 prod 時用最新 source rebuild,與 commit 的 wasm 不衝突;
commit 的 wasm 是給「self-host 用戶 + acr init」用的部署來源)。
6.3 只 commit 部署所需的 wasm(省空間)
- 實況(2026-06-02 查):
registry/components/*.wasm23 個(build 中間產物)+.component-builds/*/component.wasm22 個(部署物),共 ~50MB。 - 部署只需
.component-builds/*/component.wasm(wrangler deploy 認這個)。 → 只 commit.component-builds/*/component.wasm(22 個),不必 commit registry 那 23 個(省一半)。.gitignore改成:保留排除registry/components/**/*.wasm(中間產物),只放行.component-builds/**/component.wasm。 - ⚠️ 誠實 trade-off(mindset §7):commit wasm 進 repo → 每次 wasm rebuild 都在 git 歷史累積二進位, repo 長期會膨脹。可接受(self-host 體驗優先),但記錄此代價;未來若膨脹過劇,再考慮 release artifact / git-lfs。
6.3.1 「錯做成零件」的 3 個不 commit(richblack 2026-06-02)
實際 commit 的是 19 個正當零件,不是 22。排除的 3 個:claude_api / km_writer / kbdb_upsert_block。
- 原因(richblack 修正「待刪」說法):它們不是 endpoint 薄殼,是把工作流硬塞進零件(違反 DECISIONS §1)。
例:
kbdb_upsert_block的 upsert 邏輯應在 KBDB API 那邊(API 提供 upsert endpoint),零件只該驅動它; 現在卻把「GET 找→有則 PATCH 無則 POST」整段工作流塞進零件。本質是工作流/recipe,被錯做成零件。 - 為何「現在就不 commit」而非「先 commit 之後刪」:commit 二進位進 git 歷史後,即使日後
git rm, 歷史裡仍永久殘留(repo 體積已被佔),除非 rewrite history(很麻煩)。錯誤的東西不灌進永久歷史。 - 落地:
.gitignore放行 22 個後再排除這 3 個(後出現規則勝出);deploy.ts discoverWorkerDirs只部署「同時有 wrangler.toml + component.wasm」的目錄 → self-host 用戶 codeload 拿到的目錄缺這 3 個 wasm → 自然跳過。 - 後續:這 3 個的降級(變回工作流/recipe)是 BACKLOG 既有待辦,本次不處理,但確保它們不進 self-host 部署來源。
6.4 CLI deploy 流程(deploy.ts downloadAndDeploy 補實作)
1. 下載 codeload tarball(ref 預設 main,acr update 可帶 tag)→ 解壓 ~/.arcrun/.deploy-<ref>/
2. 讀解壓出的 .component-builds/* + cypher-executor/ + registry/
3. 各 wrangler.toml 注入 ctx.kvNamespaceIds + cypher-executor WORKER_SUBDOMAIN
4. tier1=.component-builds/*(先)→ tier2=cypher-executor/registry(後)
每個 dir:pnpm install(若有 lock)→ CLOUDFLARE_API_TOKEN=<用戶> wrangler deploy
5. 回 cypherExecutorUrl = https://arcrun-cypher-executor.<subdomain>.workers.dev
注意:tier2(cypher-executor/registry)是 TS,wrangler deploy 會在用戶端用內建 esbuild bundle (不需額外工具,richblack 確認源碼可見不重要、體驗優先 → artifact 含 TS 源碼即可)。
6.5 實作順序
- 改
.gitignore(放行.component-builds/**/component.wasm)+ commit 22 個 wasm。 - 同步改 rule 05(記錄此決策推翻原慣例)。
- 補實
deploy.ts downloadAndDeploy(codeload 下載 + 注入 + wrangler deploy)。 - 在 1-2 完成前,downloadAndDeploy 維持誠實 unimplemented,不假裝(mindset §7)。
6.6 未來方向:零件按需安裝(richblack 2026-06-02,現在不做)
- 現在
acr init --self-hosted全裝基礎零件(22 個一次部署)。簡單、夠用。 - 未來若零件數量真的變很多,再思考「按需安裝」(只裝 workflow 實際用到的零件 / 用戶選裝)。
- 現在不做的理由(DECISIONS 附錄「會不會累積成債」):零件目前少且未來絕大多數是 recipe (不需 deploy)→ 為「零件爆量」做按需安裝基建 = 為不存在的規模做自動化 = 過度工程。 零件真的爆量再回頭做,屆時是「未來一次性處理的設計點」,現在不必焦慮。
7. 驗收標準(客觀證據,mindset §7)
- richblack 用全新 CF 帳號 + wrangler 已裝 + 一個 CF API Token 跑
acr init --self-hosted→ 全程無手動建 KV / 無手動 clone / 無 tinygo / 無手動填 namespace id。 - 跑完印 secret 提示,richblack 手動
wrangler secret put CF_SECRETS_API_TOKEN。 acr push一個含 http_request + 自建 recipe 的 workflow → trigger → HTTP 2xx + execution trace。- 冪等:重跑 init 不重建已存在 KV / 不報錯。
acr update拉新 codeload tarball(tag)→ 重部署成功。
7.5 壓測修正(2026-06-04):fork 帳號裝不起來的四個阻斷項
來源:
docs/壓測報告.md(壓測者:一個「完全不懂程式」的人 + AI 自架)。 §3/§6 的 installer 流程在非官方 CF 帳號上實測無法完成部署。根因與修法如下,全部在本 SDD 範圍內(installer 補洞 + R2 dead storage 清除),不是新架構。
根因
各 worker 的 wrangler.toml(repo 內)寫死了只有 arcrun 官方帳號才有的綁定:
[[routes]] zone_name = "arcrun.dev"(每個零件 + cypher-executor)→ fork 沒有此 zone →wrangler deploy找不到 zone 失敗(阻斷 #1)[[r2_buckets]]+[ai](cypher-executor)→ fork 未必有 R2/AI(阻斷 #2)- R2 是 dead storage,卻因 CF R2 首次啟用強制綁信用卡 → 違背「開源免費自架」(阻斷 #3)
- R2 bucket 名
WASM_BUCKET(大寫+底線)違反 R2 命名規則 → 證明該碼從未成功跑過(阻斷 #4)
修法(只動 cli/,不刪 repo 內 worker toml)
關鍵判準:repo 內 toml 的 [[routes]] 是官方 prod CI 部署需要的(對外開放零件),直接刪會破壞官方部署。
正解是 deploy.ts 在注入暫存副本時 strip(§3 step 4 本就「不改用戶 repo,改暫存副本」),因為 deploy.ts 只在 self-hosted 路徑跑。
| 檔案 | 改動 |
|---|---|
cli/src/lib/deploy.ts |
新增 stripOfficialOnlyBindings():注入時移除 [[routes]]/zone_name/[[r2_buckets]]/[ai]。worker 靠 workers_dev=true 對外。移除 REQUIRED_R2_BUCKET |
cli/src/commands/init.ts |
移除 ensureR2Bucket 呼叫 + wasm_bucket config + token 提示去掉「R2 Edit」+ 結果文案改「7 KV,無需綁卡」 |
cli/src/lib/cf-api.ts |
移除 ensureR2Bucket() 方法 |
cli/src/lib/config.ts |
移除 wasm_bucket? 欄位 |
cli/src/commands/validate.ts |
錯誤文案「WASM_BUCKET 中找不到」→「registry 中找不到零件」(去命名誤導) |
→ self-hosted 改為只需 Workers + KV(皆免費額度、不綁卡),回歸開源免費承諾。
客觀證據(mindset §7)
stripOfficialOnlyBindings()對真實auth_static_key/cypher-executortoml 實測:routes/R2/AI 全 strip,name/workers_dev/kv_namespaces/vars 全保留。npx tsc --noEmitCLI 全綠;grep R2/WASM_BUCKET src/零殘留。
報告其他項(本次未動,記錄待辦)
- #7 init 只能互動式(readline,無 flag/env)→ AI/CI 不友善。建議支援
--account-id/--api-token或讀 env。待 richblack 決定。 - #8 無多帳號/專案 scope(config 寫死全域
~/.arcrun/config.yaml)→ 接案者痛點。報告建議專案層.arcrun.yaml覆蓋全域(git config 模式)。屬新功能(change),需 richblack 確認後另開 SDD。 - #5/#6 權限前置驗證 + 錯誤訊息:移除 R2 後 R2 權限問題自然消失;KV 前置一次驗證可後續優化。
7.6 壓測修正(2026-06-06):seed 下沉成 API 行為(推翻 §5「seed 資料放 CLI」)
來源:壓測報告 §4.1(seed 機制對所有 self-host 用戶都壞)+ §5.5(薄殼原則)。richblack 點名「薄殼原則寫入鐵律」。 此節推翻 §5「種子資料放 CLI 端」+ §8「只動 cli/」的範圍——seed 改為 API 行為(rule 07)。
推翻什麼
§5 原寫「種子資料放 cli/src/lib/api-recipe-seeds.ts(installer 職責)」。壓測證明這是 §4.1 bug 的結構根因:
seed 邏輯寫在 CLi init.ts(迴圈 POST + deployFullyOk gate),registry 一個無關 worker 失敗就連坐讓 seed 永遠被跳過;且 init 從不 seed auth recipe。
改法(seed = API 能力,薄殼只呼叫一次)
| 檔案 | 改動 |
|---|---|
新增 cypher-executor/src/routes/init-seed.ts |
POST /init/seed:一次灌 API recipe + auth recipe(冪等、直寫 KV、誠實計數) |
新增 cypher-executor/src/lib/api-recipe-seeds.ts |
種子資料唯一真相移到 server(rule 02 §2.2 hook 對 *-seeds.ts 整類加例外,richblack 2026-06-06 授權) |
刪 cli/src/lib/api-recipe-seeds.ts |
CLI 重複檔刪除(避免漂移) |
cypher-executor/scripts/seed-api-recipes.ts |
import 改指 server 端;備援路徑 |
cli/src/commands/init.ts |
seedApiRecipes 迴圈 → callSeedEndpoint 一次呼叫;移除 deployFullyOk gate |
cli/src/commands/update.ts |
重部署後也呼叫 /init/seed;改重解析全部 KV id |
cli/src/lib/deploy.ts |
REQUIRED_KV_NAMESPACES 加 SUBMISSIONS_KV(修 registry 20/21,§4.1.1) |
對 §8「為何不違反鐵律」的修正
§8 原寫「只動 cli/ + scripts/」。現在也動 cypher-executor/src/(新增 /init/seed route + 種子資料),
但不違反 rule 02 §2.2:seed 端點只做「讀內嵌種子資料 → 寫 KV」的 routing/資料搬運,不解密/不簽章/不展開 template;
種子的 endpoint 字串是資料宣告(*-seeds.ts 類豁免),真正 API 呼叫仍走零件路徑。符合薄殼原則(rule 07)。
7.7 壓測修正(2026-06-06):self-hosted 身份 = 明碼 namespace(不發 api_key)
來源:壓測報告 §7.2(seed 通了,但 creds push/push/runtime 全卡「缺少 api_key」)。 richblack 拍板:self-hosted 不需要「祕密 api_key」,因為它只需要 namespace(分區標籤),不需要認證(你的 cypher 在你自己的 CF,無「別人」會冒用)。
根因
credential/部署/執行三條路徑全建在多租戶 {api_key}:cred:{name} 模型,但 self-hosted(單租戶)init 從不發 api_key →
creds push/push 硬要 api_key 而退出;runtime webhook trigger 也要 X-Arcrun-API-Key header(公開表單帶不了)。
設計(richblack 2026-06-06)
self-hosted 的「api_key」= 明碼 namespace,用戶在 .env 自填。工具不生成、不 hash、不外傳。
- 一欄(由用戶持有):
NAMESPACE=leo(明碼分區標籤,當 KV 前綴;非密碼)
- 誠實限制(mindset §7):namespace 明碼不提供認證。要防外部呼叫 → 對 webhook 加保護(mindset §6);arcrun 不做授權判斷(mindset §3)。
- 零分叉:SaaS 仍走 register 發的真 api_key;self-hosted 走 .env 的 NAMESPACE。同一條
api_key路徑、同一份 config 解析,只是值來源不同。
改法
| 檔案 | 改動 |
|---|---|
cli/src/lib/config.ts |
ENV_MAP 加 NAMESPACE/ARCRUN_NAMESPACE → 對應 api_key;新增 .env 自動載入(就近往上找,shell > .env,無 dotenv 依賴) |
cli/src/commands/creds.ts、push.ts |
self-hosted 缺值時,引導設 .env 的 NAMESPACE |
cli/src/commands/init.ts |
self-hosted 結尾改提示「在 .env 設 NAMESPACE」+「把 CF_SECRETS_API_TOKEN wrangler secret put 進 worker;不想自己跑可明示同意我代設」 |
cypher-executor/src/routes/webhooks-named.ts |
新增 POST /webhooks/named/:ns/:name/trigger(namespace 走 path,公開表單免 header);與 header 路徑共用 triggerNamed,不分叉 |
cli/src/commands/push.ts |
self-hosted 輸出 path-based 公開 webhook URL(免 header) |
為何 namespace 進 URL path 安全
namespace 是明碼標籤非密碼,放 path 不洩漏任何祕密。真正的祕密是 credential 值(由 CF Workers Secrets 託管,永不進 URL/path)。要防外部濫用 webhook 是「webhook 保護層」職責,非 namespace。
7.8 壓測修正(2026-06-08):onboarding 四缺陷 → pip 式自我修復安裝(CHANGE,待 review)
來源:Haiku 冷啟動壓測(test_arcrun/2/test_record.md)+ richblack 觀察。 核心判準(haiku-capable-is-design-goal):Haiku 撞牆 = 介面缺陷,不是換強模型。 暴露的四個缺陷都是 onboarding/AI-UX,非功能 bug。richblack 要的是系統級正解,不是暫時解法/外掛 doctor。
缺陷清單(壓測實證)
| # | 缺陷 | 根因 | Haiku 實際行為(撞牆) |
|---|---|---|---|
| D1 | 安裝不偵測環境(缺 node/wrangler/CF登入/D1 任一就卡) | init 假設前置齊備,缺了不自己補也不引導 | Haiku 遇 D1 不存在 → 跑去讀原始碼自己想辦法建(非技術用戶災難) |
| D2 | 帳號 scope:AI 繞過 CLI 自己 curl 全域 | config 優先序已實作(專案>全域,config.ts:169-193),但 AI 不用 CLI 讀帳號、自己 curl 猜 → 打到全域 | Haiku curl 全域帳號 URL,非當前 project scope |
| D3 | MCP 掛不進不提示重啟 | 安裝完 project scope MCP 顯示無法用,沒告訴用戶「MCP 要重啟 client 才載入」 | 用戶以為壞了 |
| D4 | (壓測舊版 1.3.0 無 D1 自動建;1.3.2 已修,但 D1↑ 的「偵測+冪等」更根本) | — | — |
正解:安裝流程內建偵測 + 自我修復 + 冪等(pip 式)—— richblack 2026-06-08 拍板
acr init(安裝流程本身)= 像 pip:先偵測環境有什麼、版本對不對,才動手;缺什麼 Arcrun 自己負責裝。
重跑會檢查後說「什麼也沒動」(冪等)。不另做 doctor——偵測是正規安裝流程的一部分。
- 偵測先於動作:init 先檢查各前置(node / wrangler / CF 登入 / D1 / KV / migration)+ 版本 → 缺的才裝/建、有的跳過、版本不對才升。不是假設齊備直接動手。
- Arcrun 負責裝它需要的:缺什麼是 Arcrun 的工作,不丟給 AI/用戶自己想辦法(D1 不存在 → init 自己建+套 migration, 非讓 AI 讀原始碼)。需人類授權的(建 CF 資源、暴露)仍停下請示(mindset §7 非 TTY 不偽造同意)。
- 冪等可重跑:重跑檢查後「什麼也沒動」(像 pip install 已裝),不報錯不重建。
- AI 無腦入口 = 一個 GitHub 連結:AI 讀 README/連結就照著走,不繞、不讀原始碼、不自己 curl。 安裝指示集中在一處,AI 跟著做即可。
配套介面(讓 AI 不需也不該猜)
acr whoami/acr config show(D2 修法):印「當前生效帳號 + scope 來源(project/global/env)」。 AI 無腦問 CLI 拿正確帳號,不自己 curl。同步加 MCParcrun_whoami(薄殼一致,rule 07 §5)。 → 治本 D2:不是 config 沒實作(已對),是 AI 該用工具讀、不該繞 CLI 猜帳號。- MCP 掛載後提示重啟���D3 修法):
acr init/acr mcp-setup寫完.mcp.json後, 明確印「⚠️ MCP 已設定,請重啟 IDE/client 才會載入 project scope MCP」。掛不進時引導重啟,不讓用戶以為壞了。
範圍 / 分期(richblack 2026-06-09 授權 P0-P2 執行)
- P0:
acr init偵測 + 驗收(pip 式)。新增cli/src/lib/preflight.ts:detectEnvironment()安裝前偵測 node/wrangler(缺=fatal 停下給補救指令,不假設齊備直接動手);verifyInstall()裝完實查 CF(KV/D1 listKv/listD1)+ 打 cypher/health確認真就緒,缺哪項報哪項 + 一鍵補裝(acr update 冪等)。initSelfHosted開頭接 detect(fatal 即 exit 1)、結尾接 verify(未就緒印補裝指引)。冪等沿用 ensureKv/ensureD1。cli tsc exit 0。2026-06-09 完成
- P1:
acr whoami(cli/src/commands/whoami.ts,人讀 +--json,印 mode/帳號/連哪台/來源層,薄殼讀 resolveConfigSources)+ MCParcrun_whoami(mcp/src/tools/arcrun_whoami.ts,回報 orgNamespace + binding,與 CLI 對齊)。AI 問工具拿身份,不自己 curl 猜。cli+mcp tsc exit 0。2026-06-09 完成 - P2:MCP 掛載重啟提示(D3)。
cli/src/commands/mcp-setup.ts寫完.mcp.json後印「⚠ 請重啟 IDE/client 才會載入 project scope MCP」+ 信任工作區提醒。經 init 也會流到(init 呼叫 cmdMcpSetup)。2026-06-09 完成 - [~] P3:README/GitHub 入口整理成「AI 讀了就照著裝」的單一指引(D 無腦入口)。部分完成 2026-06-09:
- 新增 repo 根
.env.example範本(CF Account/Token 基礎兩格 + NAMESPACE + 服務 token 區, 每格上面白話說明「去哪申請、怎麼拿」,值留空。.gitignore加!.env.example放行進 repo)。 llms.txtstep 3 改成「你(AI)先cp .env.example .env,帶用戶填值(用戶只填「=」右邊)」—— 把「建 .env 結構」從用戶身上挪到 AI,用戶只做貼值。step 4 補 init「安裝驗收」說明。- 仍待:
arcrun.dev/llms.txt沒 serve(landing/public 缺檔,404;GitHub repo 內 llms.txt 正常)。 test/5 prompt 給 GitHub URL 故不阻擋;arcrun.dev serve 另排。
- 新增 repo 根
誠實:偵測各前置 + 版本比對 + 冪等重跑工程量不小(跨 CLI 多步)。但「裝很久 + AI 一直繞」對非技術用戶 是致命體驗 → 這是 onboarding 必修不是優化。
2026-06-09 補(test_arcrun/4 壓測根因):D1/D2/D3 之上還有更致命的一層——壓測時 AI 整個沒跑
acr init(settings.local.json 沒 allow init),導致 D1/harness/MCP/slash-command 全沒裝(全掛在 cmdInit 內)。 P0 的「偵測+驗收」讓「跑了 init 但環境半殘」能被看見並自癒;但「根本沒跑 init」要靠 P3(README/入口 引導 AI「第一件事就是 acr init」)+ harness 的 mindset/CLAUDE.md 提醒。P3 後續補。
8. 為何不違反鐵律
- 只動
cli/+ 新增cypher-executor/scripts/(seed 腳本,非執行路徑業務邏輯)。 - 不在
registry/components/寫 TS;不在 cypher-executor TS 實作 credential/auth/JWT。 - 不新增 Service Binding。
- secret 不進自動化(§3 step 8 手動)。
- 不重寫部署輪子(用 wrangler,不自寫 CF Script Upload)。