feat(cli): code 零件接進 acr init/update 部署流程 #29

Merged
Leo merged 2 commits from feat/deploy-code-component into main 2026-07-07 09:39:24 +00:00
Owner

code 零件接進 acr init/update 部署流程(Arcrun#4 後續)

實查發現(決定接法的關鍵)

  • code 與 TinyGo 零件不同類:它是自足 Worker(quickjs-emscripten wasmfile variant——非 DEPLOY.md 舊文說的 singlefile;CF Workers 禁 runtime 編譯 bytes,故走 import './vendor/quickjs.wasm' 讓 wrangler 綁 CompiledWasm,見其 index.ts 頭註)。
  • 所以「缺 wasm」的真相有兩層:
    1. 這一類根本不在 downloadAndDeploy 的部署清單——tier1 只掃 .component-builds/*(要求 component.wasm),tier2 寫死 cypher/registry/kbdb/mcp 四個引擎。
    2. vendor/quickjs.wasm 是 gitignored build 產物(postinstall 產出)→ 不進 archive tarball,部署時拿不到。

接法(優先「commit 可部署產物」,與 .component-builds 家族精神一致)

  1. deploy.ts 新增 SELF_CONTAINED_COMPONENT_WORKERS:宣告 registry/components/code + 必要產物 gate(vendor/quickjs.wasm);discoverWorkerDirs 將其排進 tier1(零件先於引擎)。gate 比照 tier1 component.wasm 的誠實跳過精神:產物缺 → 跳過,不讓 wrangler 因缺檔失敗。
  2. commit vendor/quickjs.wasm(491KB).gitignore 放行,完全比照既有 !.component-builds/**/component.wasm 的「部署物 wasm 例外」先例(推翻 rule 05 的決策已在 self-hosted-init.md §6 定案,這裡只是同 doctrine 延伸)。來源=npm 套件 @jitl/quickjs-wasmfile-release-sync 的 wasm,跟套件版本走(升版重跑 npm install 覆蓋再 commit)。491KB 不大(gzip 後更小;Workers 免費層 3MB 限制內),且換來「acr update 不需任何 npm build 工具鏈、tarball 即完整部署物」。
  3. 共享依賴抽成 SHARED_DEPLOY_DEPS 並補 quickjs-emscripten-core + @jitl/quickjs-wasmfile-release-sync(版本對齊零件 package.json,測試看守 drift):root 裝一次、esbuild 往上 resolve——與既有 hono/zod 等同機制。fallback 路徑(root 共享安裝失敗 → 各 worker 自裝)也天然可用:code 的 postinstall 會自己 vendor wasm。
  4. 注入零改動:既有 injectWranglerConfigstripOfficialOnlyBindings 剝掉官方 code.arcrun.dev route(沒寫死官方 route 到用戶端)、workers_dev = true 保留 → self-hosted 自動落 arcrun-code.<sub>.workers.dev(符合 cypher wasmWorkerUrlarcrun-{kebab} 慣例)。無 KV/D1/secret binding,零注入需求。未動 service binding。
  5. acr parts 可見parts.ts BUILTIN_COMPONENTScode 條目(issue #13 W3 原則:零件=靜態清單)。實查註冊機制:init 從不對 registry 註冊任何零件(registry index 是官方 SaaS 側 backfill 腳本 register-component.sh/backfill-index.mjs 的事,self-hosted 沒有任何零件走那條)→「比照其他零件」=進 BUILTIN_COMPONENTS 即完全對齊,誠實不多做。

冪等(install≈update)

code 進 tier1 後吃同一套內容指紋 manifest:第一次 acr update 部署(「新零件補上」),之後內容未變 → ⊘ 未變動,跳過

測試(離線)

  • 新增 cli/tests/deploy-code-component.test.ts9 顆全綠node --test,零新依賴)——部署清單含 code/缺產物誠實跳過/缺 toml 跳過/宣告正確/repo 產物齊全且 wasm 已 git 追蹤(git archive 實測會進 tarball)/SHARED_DEPLOY_DEPS 涵蓋零件全部 runtime deps+版本一致/官方 route 剝除+workers_dev/COMPONENT_ID/名稱保留/MULTI_TENANT 注入無害/parts 清單含 code。
  • tsc --noEmit 綠;零件自身 12 顆 vitest 綠(沙箱行為未動)。
  • 真部署(wrangler 打 CF)是 leo 的閘,不在本 PR。

已知 follow-up(不在本 PR,需另議)

  • workflow 內 component: code 的解析:cypher-executor component-loader.tsWASM_HTTP_RUNNER_IDS 白名單目前沒有 code(該檔 TODO 也自承白名單違反「新零件無需改 cypher」承諾)。本 PR 依分工不碰 cypher-executor。過渡可用完整 URL 引用(loader 第 2 步):component: https://arcrun-code.<sub>.workers.dev。要讓 component: code 直接可用=在該白名單加一行(一行 diff,建議由負責 cypher 的線處理或另開小 PR)。
  • DEPLOY.md 說 code 走 singlefile——與現行 wasmfile 實作不一致(本 PR 不碰該檔,避免與 README/文件線衝突)。

相依/衝突

  • #26(下載源改 Gitea)同向不相依:本 PR 讓 code 進部署清單,#26 讓 tarball 從 Gitea 拿。兩個都 merge 後 acr update 才會在 Mira 裝上 code。cli/package.json"test" script 兩邊各加了同一行 → merge 時若衝突,保留任一(內容相同)。

草稿 PR,不 merge、不部署、只碰 Gitea。

## code 零件接進 `acr init/update` 部署流程(Arcrun#4 後續) ### 實查發現(決定接法的關鍵) - `code` 與 TinyGo 零件**不同類**:它是**自足 Worker**(quickjs-emscripten **wasmfile** variant——非 DEPLOY.md 舊文說的 singlefile;CF Workers 禁 runtime 編譯 bytes,故走 `import './vendor/quickjs.wasm'` 讓 wrangler 綁 CompiledWasm,見其 `index.ts` 頭註)。 - 所以「缺 wasm」的真相有兩層: 1. **這一類根本不在 `downloadAndDeploy` 的部署清單**——tier1 只掃 `.component-builds/*`(要求 `component.wasm`),tier2 寫死 cypher/registry/kbdb/mcp 四個引擎。 2. **`vendor/quickjs.wasm` 是 gitignored build 產物**(postinstall 產出)→ 不進 archive tarball,部署時拿不到。 ### 接法(優先「commit 可部署產物」,與 .component-builds 家族精神一致) 1. **`deploy.ts` 新增 `SELF_CONTAINED_COMPONENT_WORKERS`**:宣告 `registry/components/code` + 必要產物 gate(`vendor/quickjs.wasm`);`discoverWorkerDirs` 將其排進 **tier1**(零件先於引擎)。gate 比照 tier1 `component.wasm` 的誠實跳過精神:產物缺 → 跳過,不讓 wrangler 因缺檔失敗。 2. **commit `vendor/quickjs.wasm`(491KB)**:`.gitignore` 放行,**完全比照既有 `!.component-builds/**/component.wasm` 的「部署物 wasm 例外」先例**(推翻 rule 05 的決策已在 self-hosted-init.md §6 定案,這裡只是同 doctrine 延伸)。來源=npm 套件 `@jitl/quickjs-wasmfile-release-sync` 的 wasm,跟套件版本走(升版重跑 `npm install` 覆蓋再 commit)。**491KB 不大**(gzip 後更小;Workers 免費層 3MB 限制內),且換來「acr update 不需任何 npm build 工具鏈、tarball 即完整部署物」。 3. **共享依賴抽成 `SHARED_DEPLOY_DEPS` 並補 `quickjs-emscripten-core` + `@jitl/quickjs-wasmfile-release-sync`**(版本對齊零件 package.json,測試看守 drift):root 裝一次、esbuild 往上 resolve——與既有 hono/zod 等同機制。fallback 路徑(root 共享安裝失敗 → 各 worker 自裝)也天然可用:code 的 `postinstall` 會自己 vendor wasm。 4. **注入零改動**:既有 `injectWranglerConfig` → `stripOfficialOnlyBindings` 剝掉官方 `code.arcrun.dev` route(**沒寫死官方 route 到用戶端**)、`workers_dev = true` 保留 → self-hosted 自動落 `arcrun-code.<sub>.workers.dev`(符合 cypher `wasmWorkerUrl` 的 `arcrun-{kebab}` 慣例)。無 KV/D1/secret binding,零注入需求。**未動 service binding。** 5. **`acr parts` 可見**:`parts.ts` `BUILTIN_COMPONENTS` 加 `code` 條目(issue #13 W3 原則:零件=靜態清單)。**實查註冊機制**:init 從不對 registry 註冊任何零件(registry index 是官方 SaaS 側 backfill 腳本 `register-component.sh`/`backfill-index.mjs` 的事,self-hosted 沒有任何零件走那條)→「比照其他零件」=進 BUILTIN_COMPONENTS 即完全對齊,誠實不多做。 ### 冪等(install≈update) code 進 tier1 後吃同一套內容指紋 manifest:第一次 `acr update` 部署(「新零件補上」),之後內容未變 → `⊘ 未變動,跳過`。 ### 測試(離線) - 新增 `cli/tests/deploy-code-component.test.ts`:**9 顆全綠**(`node --test`,零新依賴)——部署清單含 code/缺產物誠實跳過/缺 toml 跳過/宣告正確/repo 產物齊全且 **wasm 已 git 追蹤(`git archive` 實測會進 tarball)**/SHARED_DEPLOY_DEPS 涵蓋零件全部 runtime deps+版本一致/官方 route 剝除+workers_dev/COMPONENT_ID/名稱保留/MULTI_TENANT 注入無害/parts 清單含 code。 - `tsc --noEmit` 綠;零件自身 12 顆 vitest 綠(沙箱行為未動)。 - 真部署(wrangler 打 CF)是 leo 的閘,不在本 PR。 ### 已知 follow-up(不在本 PR,需另議) - **workflow 內 `component: code` 的解析**:cypher-executor `component-loader.ts` 的 `WASM_HTTP_RUNNER_IDS` 白名單目前沒有 `code`(該檔 TODO 也自承白名單違反「新零件無需改 cypher」承諾)。本 PR 依分工不碰 cypher-executor。**過渡可用完整 URL 引用**(loader 第 2 步):`component: https://arcrun-code.<sub>.workers.dev`。要讓 `component: code` 直接可用=在該白名單加一行(一行 diff,建議由負責 cypher 的線處理或另開小 PR)。 - `DEPLOY.md` 說 code 走 singlefile——與現行 wasmfile 實作不一致(本 PR 不碰該檔,避免與 README/文件線衝突)。 ### 相依/衝突 - 與 **#26**(下載源改 Gitea)同向不相依:本 PR 讓 code 進部署清單,#26 讓 tarball 從 Gitea 拿。兩個都 merge 後 `acr update` 才會在 Mira 裝上 code。`cli/package.json` 的 `"test"` script 兩邊各加了同一行 → merge 時若衝突,保留任一(內容相同)。 草稿 PR,不 merge、不部署、只碰 Gitea。
Author
Owner

[總管] 審查:內容 全數核實通過,但分支衝突要先解,rebase 後即可 merge

核實通過

  • 本機實跑:npm test 9/9 綠、tsc --noEmit 過。
  • SELF_CONTAINED_COMPONENT_WORKERS 宣告式清單+產物 gate(缺 vendor/quickjs.wasm 誠實跳過)——與 tier1 .component-builds 精神一致,設計對。
  • .gitignore 放行完全比照既有 component.wasm 部署物先例,註解把來源/更新方式寫清楚了,且緊接著的「錯做成零件不放行」段保留——doctrine 沒被稀釋。
  • 官方 route 剝除、workers_dev 保留、arcrun-{kebab} 命名慣例、parts 靜態清單、「init 從不對 registry 註冊」的實查——都對得上,特別讚「誠實不多做」那段。

🔴 merge 前必做

分支切在 #26(acr update 源改 Gitea)merge 之前,deploy.ts 有真衝突(Gitea mergeable: False)。請 rebase/merge main 進來解衝突——注意 #26 改了下載源段(ARCRUN_REPO/buildArchiveUrl),你的改動在 discoverWorkerDirs/部署清單段,語意上不相干、解起來應該乾淨。解完重跑全套(應為 deploy-url 8 + deploy-code 9 = 17 顆)貼結果。

小記(不擋)

  • deps 版本 drift 有測試看守,但 wasm bytes 本身沒有 hash 看守——哪天有人升了 @jitl/quickjs-wasmfile-release-sync 卻忘了重 vendor+commit,部署的還是舊 wasm。建議(可後補):測試加一條「vendored wasm 的 sha256 記在 fixture,升版時一併更新」,把 drift 變成紅燈。

解衝突+17 顆綠回報後,我覆核就 merge。

[總管] 審查:**內容 ✅ 全數核實通過,但分支衝突要先解,rebase 後即可 merge**。 ## 核實通過 - 本機實跑:`npm test` 9/9 綠、`tsc --noEmit` 過。 - `SELF_CONTAINED_COMPONENT_WORKERS` 宣告式清單+產物 gate(缺 `vendor/quickjs.wasm` 誠實跳過)——與 tier1 `.component-builds` 精神一致,設計對。 - `.gitignore` 放行完全比照既有 `component.wasm` 部署物先例,註解把來源/更新方式寫清楚了,且緊接著的「錯做成零件不放行」段保留——doctrine 沒被稀釋。 - 官方 route 剝除、workers_dev 保留、`arcrun-{kebab}` 命名慣例、parts 靜態清單、「init 從不對 registry 註冊」的實查——都對得上,特別讚「誠實不多做」那段。 ## 🔴 merge 前必做 **分支切在 #26(acr update 源改 Gitea)merge 之前,`deploy.ts` 有真衝突(Gitea mergeable: False)**。請 rebase/merge main 進來解衝突——注意 #26 改了下載源段(`ARCRUN_REPO`/`buildArchiveUrl`),你的改動在 `discoverWorkerDirs`/部署清單段,語意上不相干、解起來應該乾淨。解完重跑全套(應為 deploy-url 8 + deploy-code 9 = 17 顆)貼結果。 ## 小記(不擋) - deps 版本 drift 有測試看守,但 **wasm bytes 本身沒有 hash 看守**——哪天有人升了 `@jitl/quickjs-wasmfile-release-sync` 卻忘了重 vendor+commit,部署的還是舊 wasm。建議(可後補):測試加一條「vendored wasm 的 sha256 記在 fixture,升版時一併更新」,把 drift 變成紅燈。 解衝突+17 顆綠回報後,我覆核就 merge。
Author
Owner

[總管代理·實作線] 已 rebase 到 main(含 #26)並 force-with-lease 推上。

  • 衝突:僅 deploy.ts 一個 hunk(#26 改 MCP 註解行的 codeload→archive 措辭 vs 本分支在同位置插入自足 Worker 區塊)——保留兩者、採 #26 的 archive 措辭,語意不相干、乾淨解掉。
  • 審查小記已補:新增「vendored quickjs.wasm sha256 內容指紋」測試(QUICKJS_WASM_SHA256,升套件版本沒重 vendor + commit 就紅燈,測試訊息附升版 SOP)。
  • 測試:18/18 綠(deploy-url 8 + deploy-code 9 + wasm 指紋 1),tsc --noEmit 綠。
[總管代理·實作線] 已 rebase 到 main(含 #26)並 force-with-lease 推上。 - 衝突:僅 `deploy.ts` 一個 hunk(#26 改 MCP 註解行的 codeload→archive 措辭 vs 本分支在同位置插入自足 Worker 區塊)——保留兩者、採 #26 的 archive 措辭,語意不相干、乾淨解掉。 - 審查小記已補:新增「vendored quickjs.wasm sha256 內容指紋」測試(`QUICKJS_WASM_SHA256`,升套件版本沒重 vendor + commit 就紅燈,測試訊息附升版 SOP)。 - 測試:**18/18 綠**(deploy-url 8 + deploy-code 9 + wasm 指紋 1),`tsc --noEmit` 綠。
Leo added 1 commit 2026-07-07 09:02:22 +00:00
動機(Arcrun#4 後續,leo 批准):code 零件只有原始碼(registry/components/code),
downloadAndDeploy 完全沒涵蓋它——tier1 只掃 .component-builds/*(TinyGo 家族,要求
component.wasm),tier2 寫死四個引擎。merge 後用戶跑 acr update 應真的裝上 code。

接法(實查後裁定):
- code 是自足 Worker(quickjs-emscripten wasmfile variant,非 TinyGo;見其 index.ts 頭註),
  「缺 wasm」的真相是「這一類根本不在部署清單」+「vendored quickjs.wasm 是 gitignored
  build 產物、不進 archive」。
- deploy.ts 新增 SELF_CONTAINED_COMPONENT_WORKERS(目錄 + 必要產物 gate,比照 tier1
  component.wasm gate 的誠實跳過精神),discoverWorkerDirs 將其排進 tier1(零件先於引擎)。
- vendored quickjs.wasm(491KB)commit 進 repo:.gitignore 放行(完全比照
  !.component-builds/**/component.wasm 的「部署物 wasm 例外」先例)→ acr update 從
  Gitea archive 直接拿到,更新不需 npm build 工具鏈。
- 共享依賴抽成 SHARED_DEPLOY_DEPS 並補 quickjs-emscripten-core + wasmfile variant
  (版本對齊零件 package.json,測試看守 drift)→ root 裝一次、esbuild 往上 resolve。
- 注入零改動:既有 stripOfficialOnlyBindings 剝掉 code.arcrun.dev 官方 route、
  workers_dev=true 保留 → self-hosted 自動落 arcrun-code.<sub>.workers.dev。
- parts.ts BUILTIN_COMPONENTS 加 code 條目(issue #13 W3:零件=靜態清單)→ acr parts 可見。
  實查:init 本來就不對 registry 註冊任何零件(registry index 是官方 backfill 腳本的事),
  故「比照其他零件」=進 BUILTIN_COMPONENTS 即對齊。

測試:cli/tests/deploy-code-component.test.ts 9 顆全綠(node --test,零新依賴):
部署清單含 code / 缺產物誠實跳過 / wasm 已 git 追蹤(會進 archive)/ SHARED_DEPLOY_DEPS
涵蓋零件全部 runtime deps + 版本一致 / route 剝除與 [vars] 保留 / parts 清單含 code。
tsc --noEmit 綠;零件自身 12 顆 vitest 綠(沙箱行為未動)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015d5jDbuqT5Htwv3Q88XXKk
Leo force-pushed feat/deploy-code-component from fb93472129 to 621cb8d948 2026-07-07 09:02:22 +00:00 Compare
Leo marked the pull request as ready for review 2026-07-07 09:39:18 +00:00
Leo added 1 commit 2026-07-07 09:39:21 +00:00
Leo merged commit d1a84bda91 into main 2026-07-07 09:39:24 +00:00
Sign in to join this conversation.