# Implementation Plan: arcrun SDK Libraries + Website

## Overview

按 Design 的四個 Phase 實作。原則：修改不重建，SDK 是 HTTP API thin wrapper，加密只在 client 做 encrypt（不做 decrypt）。

**前置依賴**：~~必須先完成 credential-primitives-wasm 的 Phase 0-3~~ → **依賴已解除**（該卷 Phase 0-3 已完成並於 2026-07-21 封存至 `system-dev/docs/3-specs/archive/credential-primitives-wasm/`）。

---

## Phase 0（前置）：核心合併 + WASM 改寫

> ✅ 已完成並封存：`system-dev/docs/3-specs/archive/credential-primitives-wasm/tasks.md`
> 
> 摘要：
> - 合併 u6u-core → arcrun（搬 builtins、刪重複 credentials）
> - credential-injector TS → auth_static_key / auth_service_account WASM
> - 刪除 component-loader 內建 API recipes TS
> - 驗證 20 個 auth recipe 正常運作

---

## Phase 1：Python SDK

- [ ] 1. 建立 `arcrun/python-sdk/` 目錄
  - [ ] 1.1 `pyproject.toml`：name=arcrun, deps=[httpx>=0.27, cryptography>=42], build-system=hatchling
  - [ ] 1.2 `arcrun/__init__.py`：`from .client import Arcrun`
  - [ ] 1.3 `arcrun/crypto.py`：AES-GCM encrypt only（使用 `cryptography` 套件）
  - [ ] 1.4 `arcrun/creds.py`：CredentialsClient — push（加密 + POST /credentials）、list（GET /credentials）、delete
  - [ ] 1.5 `arcrun/auth.py`：AuthClient — setup（fetch recipe → match secrets → encrypt → push）、bind（fetch recipe → resolve headers from cache → return AuthenticatedClient）、get_token、list_services
  - [ ] 1.6 `arcrun/workflows.py`：WorkflowClient — run（POST /webhooks/named/{name}/trigger）、push（POST /webhooks/named）、list（GET /webhooks/named）、delete
  - [ ] 1.7 `arcrun/client.py`：Arcrun class — 讀 api_key / encryption_key 從 param > env > config.yaml

- [ ] 2. 修正上次已知的 bug
  - [ ] 2.1 `_fetch_recipe()` 回應是 `{ success: true, recipe: {...} }`，需讀 `.recipe` 欄位
  - [ ] 2.2 `inject` 下的 key 是 `header`（singular），不是 `headers`
  - [ ] 2.3 `required_secrets[].key` 是 prefixed（如 `openai_api_key`），setup() 的 kwargs alias 要能對應
  - [ ] 2.4 `list_services()` 回應的 recipe 用 `service` 欄位（不是 `service_id`）

- [ ] 3. 測試（對 cypher.arcrun.dev live API）
  - [ ] 3.1 `health()` → `{"ok": true}`
  - [ ] 3.2 `auth.list_services()` → 20 個服務
  - [ ] 3.3 `auth.setup("openai", api_key="sk-test-dummy")` → 成功
  - [ ] 3.4 `auth.bind("openai")` → AuthenticatedClient with Authorization header
  - [ ] 3.5 `auth.get_token("openai")` → "sk-test-dummy"
  - [ ] 3.6 `creds.push("test_token", "value123")` → 成功
  - [ ] 3.7 `creds.list()` → 含 "test_token"（注意 KV eventual consistency）
  - [ ] 3.8 `workflows.list()` → []
  - [ ] 3.9 cleanup: `creds.delete("test_token")`

---

## Phase 2：JS/TS SDK

- [ ] 4. 建立 `arcrun/js-sdk/` 目錄
  - [ ] 4.1 `package.json`：name TBD（arcrun vs @arcrun/sdk），deps=devDeps only（tsup, typescript, @types/node）
  - [ ] 4.2 `tsconfig.json`：ES2020, NodeNext
  - [ ] 4.3 `src/crypto.ts`：Web Crypto API AES-GCM encrypt only
  - [ ] 4.4 `src/creds.ts`：CredentialsClient — push/list/delete via fetch
  - [ ] 4.5 `src/auth.ts`：AuthClient — setup/bind/getToken/listServices
  - [ ] 4.6 `src/workflows.ts`：WorkflowClient — run/push/list/delete
  - [ ] 4.7 `src/index.ts`：export class Arcrun + re-exports

- [ ] 5. 同步修正（與 Python SDK 同樣的 recipe 格式問題）
  - [ ] 5.1 `_fetchRecipe()` 讀 `body.recipe`
  - [ ] 5.2 inject key: `header` not `headers`
  - [ ] 5.3 setup() secret key alias matching
  - [ ] 5.4 listServices() 用 `service` 欄位

- [ ] 6. Build + 測試
  - [ ] 6.1 `tsup` build → dist/index.js + dist/index.cjs + dist/index.d.ts
  - [ ] 6.2 Node.js 腳本對 live API 測試（同 Python 測試項目）

---

## Phase 3：arcrun.dev 網站

- [ ] 7. 新增 `/components` 頁面
  - [ ] 7.1 從 `registry/components/*/component.contract.yaml` 讀取 21 個零件資料
  - [ ] 7.2 卡片顯示：canonical_id, display_name, description, input required/optional, credentials_required, config_example
  - [ ] 7.3 分類篩選：邏輯類 / API 類 / 控制流類

- [ ] 8. 更新首頁
  - [ ] 8.1 Code demo tabs 改為 CLI / Python / JS 三個
  - [ ] 8.2 CLI tab 展示 `acr init → acr push → acr run`
  - [ ] 8.3 Python tab 展示 `pip install arcrun → Arcrun() → auth.setup → auth.bind`
  - [ ] 8.4 JS tab 展示 `npm install arcrun → new Arcrun() → auth.setup → auth.bind`

- [ ] 9. OAuth 流程補完
  - [ ] 9.1 確認 cypher-executor 的 `/auth/google/start`、`/auth/github/start`、`/auth/callback` 路由正確
  - [ ] 9.2 提供 richblack OAuth secrets 設定指令清單
  - [ ] 9.3 richblack 設定 secrets 後驗證登入流程

- [ ] 10. 部署
  - [ ] 10.1 Cloudflare Pages build + deploy
  - [ ] 10.2 驗證所有頁面可存取

---

## Phase 4：README + 發布

- [ ] 11. 更新 `arcrun/README.md`
  - [ ] 11.1 三種 Quick Start（CLI / Python / JS）
  - [ ] 11.2 零件列表（21 個）
  - [ ] 11.3 Auth Recipe 列表（20 個服務）
  - [ ] 11.4 連結到 arcrun.dev 和 Swagger UI

- [ ] 12. 發布
  - [ ] 12.1 Python SDK：`pip install build && python -m build && twine upload dist/*`
  - [ ] 12.2 JS SDK：`npm run build && npm publish`
  - [ ] 12.3 驗證：從零開始 `pip install arcrun` / `npm install arcrun` + hello world

---

## Phase 5：acr init --self-hosted installer（2026-06-02 新增）

> 定稿 design：`self-hosted-init.md`。CLI = installer：建 KV/R2 + 拉預編譯 wasm + wrangler deploy + seed。
> 用戶只做：申請 CF 帳號 → 裝 wrangler → 裝 acr → acr init --self-hosted。其餘自動。
> 背景：戰法轉 self-hosted 開源（docs/HANDOFF-self-host-harness.md）。

- [x] 13.1 API recipe 種子 — **位置修正**：種子資料放 `cli/src/lib/api-recipe-seeds.ts`（installer 用，避開 cypher §2.2 hook），seed 腳本 `cypher-executor/scripts/seed-api-recipes.ts`（import 種子，給 prod 補灌）。10 個現役 recipe（kbdb_*/gmail_send/google_sheets_*/telegram_send/line_notify_send）。KBDB Supabase 模式進 seed（finally.click 是 KBDB 端 follow-up，已註於 api-recipe-seeds.ts）
- [x] 13.2 `cli/src/lib/cf-api.ts` 新增 `CfAccountClient`：verifyAccess / listKvNamespaces / ensureKvNamespace（冪等）/ ensureR2Bucket（冪等）/ getWorkersSubdomain
- [x] 13.3 `cli/src/commands/init.ts` `initSelfHosted()` 改寫：驗 token → 建 7 KV + R2 → 查 subdomain → downloadAndDeploy → 寫 config → seed（部署完成時）→ 印 secret 提示。誠實：部署未自動化時明說，不假綠
- [x] 13.4 `cli/src/lib/deploy.ts`：REQUIRED_KV/R2/SECRET 常數 + wranglerAvailable() + **downloadAndDeploy 已補實**（codeload tarball 下載 + 解壓 + discoverWorkerDirs 分 tier + injectWranglerConfig 注入 KV id/subdomain + runWranglerDeploy；部分失敗誠實收集回報，不假綠）
- [x] 13.5 `cli/src/commands/update.ts` + index.ts 註冊 `acr update`（self-hosted 重部署，同走 downloadAndDeploy）
- [x] 13.6 部署物產製：**改用 commit wasm 進 repo + codeload**（取代 release artifact，richblack 2026-06-02，§6）
  - `.gitignore` 否定規則放行 `.component-builds/**/component.wasm`（registry 中間產物仍排除）→ 已驗 git check-ignore
  - rule 05 同步改（記錄推翻「wasm 不 commit」+ trade-off）
  - commit 22 個 `.component-builds/*/component.wasm` 進 repo
- [ ] 13.7 驗收：全新 CF 帳號跑 acr init --self-hosted 全自動；acr push workflow → trigger 2xx + trace（**待 richblack 用第二帳號實測** + push 含 wasm 的 commit 到 GitHub 後 codeload 才拿得到）
- [x] 13.8 typecheck：cli `tsc --noEmit` exit 0

## Phase 6：壓測四橫向問題修正（2026-06-06，richblack 點名）

> 來源：`/Users/youlinhsieh/Documents/tech_projects/test_arcrun/docs/壓測報告.md`。
> 四個結構性問題（非個別 bug）：薄殼原則未成鐵律、CLI/MCP 不同步打不同帳號、deploy 未全推、表達不清。

- [x] 6.1 **薄殼鐵律成文 + hook 強制**：新增 `.claude/rules/07-thin-shell.md`（能力長在 API，介面只暴露）；
  `02-forbidden.md` 第五類 + `CLAUDE.md` 鐵律 8 + 索引；`pre-write-guard.sh` 規則 7.x
  （擋 cli/src + arcrun-mcp/src 的 seedApiRecipes/seedAuthRecipes、upsert 拼裝、deployFullyOk gate）。
- [x] 6.2 **seed 下沉成 API 行為**（薄殼正例 + 修 §4.1 seed bug）：
  - 新增 `cypher-executor/src/routes/init-seed.ts`：`POST /init/seed` 一次灌 API recipe + auth recipe（冪等、直寫 KV、誠實計數），mount 進 index.ts
  - 種子資料移到 server：`cypher-executor/src/lib/api-recipe-seeds.ts`（唯一真相），刪 CLI 重複 `cli/src/lib/api-recipe-seeds.ts`，`seed-api-recipes.ts` 改 import server 端
  - CLI `init.ts`：`seedApiRecipes` 迴圈 → `callSeedEndpoint` 薄殼一次呼叫；**移除 deployFullyOk gate**（registry 失敗不再連坐害 seed 被跳過，§4.1 根因）；auth recipe 現在一併 seed（§4.1.2 修）
  - CLI `update.ts`：重部署後也呼叫 `/init/seed`（修 §4.1.3「update 不 seed 卻提示說會 seed」矛盾）+ 改為重解析「全部」KV id（修「只注入 2 個」風險）
- [x] 6.3 **hook seed 例外通用化**：`*-seeds.ts` 整類豁免 endpoint/template 檢查（richblack 原則：不為單一零件改全域規則），未來新種子檔自動適用，永不再動 hook。
- [x] 6.4 **registry SUBMISSIONS_KV**（修 §2.6/#11「20/21」）：加進 `REQUIRED_KV_NAMESPACES` → init/update 會建 + 注入 → registry 部署回 21/21 → 連帶 seed 不再被連坐（§4.1.1）。
- [x] 6.5 **Deploy 一致性（Gherkin + 把 npm publish 補進現行機制）**：誠實前提——GH Actions 2026-05-16 停用、公開 repo `.github/` 已移除，現行 deploy 走 `scripts/local-deploy.sh`。故：
  - `tests/release.feature`（每個 publish target 場景，描述「該到位什麼」）
  - `scripts/check-release.sh`（一眼看版本/部署狀態，已驗證抓出 CLI 1.2.0≠npm 1.1.0 漂移）
  - **`scripts/local-deploy.sh` 第 6 段新增 CLI npm publish**（cli/ 變動且 version bump → npm publish；同版跳過、未登入誠實標）。這是真正讓「推送=全部到位」的修法，根因是舊腳本只 wrangler deploy worker 從不 publish CLI。
  - `.github/workflows/publish-cli.yml` 為預備檔（gitignored、不跑），日後重啟 GH Actions 可啟用。
- [x] 6.6 **表達不清 → README 同步現況**：移除 R2 殘留文案（權限表去掉 R2、init 輸出去掉 WASM_BUCKET、「無需綁卡」）、補 `--account-id/--api-token`/env 非互動、補多帳號 `.arcrun.yaml` + `acr config --where`。
- [x] 6.7 客觀驗證：cypher-executor + cli 兩端 `tsc --noEmit` exit 0；hook 7.x + *-seeds 例外 + 非 seed 仍擋 全部回歸測試通過。
- [x] 6.8 **MCP 帳號架構**（richblack 2026-06-06 拍板「單一 remote MCP + .env 切 MCP URL」，推翻初版三方案）：
  - SDD `mcp-account-source.md` 重寫為實作版。**不加 stdio**（self-hosted 用戶也有 CF，MCP 一律 remote Worker；差別只在連哪台）。
  - 共用 config 解析：`config.ts` 加 `mcp_url` 三層（env `ARCRUN_MCP_URL` > 專案 `.arcrun.yaml` > 全域）+ `getMcpUrl()` + `DEFAULT_MCP_URL`。「切換帳號」能力收斂到 config 解析（薄殼正解），不再綁 CLI。
  - **MCP 搬進 `arcrun/mcp/`**（從 sibling repo verbatim 搬；wrangler name→`arcrun-mcp`+`workers_dev=true`；形態不變仍 remote Worker）。deploy 掃描已掃到、tsc 綠。
  - **新增 `acr mcp-setup`**：依 `getMcpUrl()` 寫專案 `.mcp.json`（remote http MCP）。init 順帶呼叫。接案進客戶資料夾跑一次 → Claude Code 連客戶 MCP。**實測 3 情境（fallback/專案覆蓋/env）+ merge 保留既有 server 全通過**。
  - `acr --version` 改從 package.json 動態讀（不再 hardcode，根治版本漂移）。
- [x] 6.10 **CLI 版本自動化**（richblack：deploy 時自動昇版 + 留記錄，避免忘了改）：`local-deploy.sh` deploy CLI 時若版本未 bump → 自動 `npm version patch` + prepend `cli/CHANGELOG.md`（含 commit subject）。已 bump 到 1.3.0 + 建 CHANGELOG.md。
- [ ] 6.9 驗收：richblack 跑 `scripts/local-deploy.sh`（worker + MCP + CLI npm 一起）；壓測者重跑 `acr init` → recipe/auth-recipe 不再空 + `.mcp.json` 自動產 → 表單→Google Sheets 端到端。
- [ ] 6.11 待 richblack 確認：MCP 搬進主庫後**對外正式網址**（現役 `studio.finally.click/mcp`，`DEFAULT_MCP_URL` 暫用此）；sibling repo `matrix/arcrun-mcp` 去留（建議標歷史、新開發在 arcrun/mcp/）。

## Notes

- JS SDK 套件名需 richblack 決定（`arcrun` 已被 CLI 佔用 → 可能用 `@arcrun/sdk`）
- OAuth secrets 設定需 richblack 手動操作（GCP Console + GitHub Settings）
- `bind()` 跨 session 限制是已知的，封測期間先接受
- credential 加密用的 `encryption_key` 目前由 `/register` 回傳，`acr init` 自動存入 config
