From 3e65e22775bf4b26374ca2ea424fb5737edb4998 Mon Sep 17 00:00:00 2001 From: uncle6me-web Date: Sat, 6 Jun 2026 15:45:35 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=96=84=E6=AE=BC=E5=8E=9F=E5=89=87?= =?UTF-8?q?=E8=90=BD=E5=9C=B0=20+=20seed=20=E4=B8=8B=E6=B2=89=20API=20+=20?= =?UTF-8?q?MCP=20=E9=80=B2=E4=B8=BB=E5=BA=AB=20+=20=E9=83=A8=E7=BD=B2?= =?UTF-8?q?=E4=B8=80=E8=87=B4=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 壓測四橫向問題修正(docs 壓測報告): ① 薄殼原則成鐵律:能力長在 API,CLI/MCP/lib 只暴露 - seed 下沉成 API 行為:cypher-executor POST /init/seed(一次灌 API+auth recipe), 種子資料移到 server src/lib/api-recipe-seeds.ts,CLI 改薄殼一次呼叫 - 解除 deployFullyOk 連坐 + init 補 seed auth recipe + update 補 seed/全 KV - registry SUBMISSIONS_KV 補進 REQUIRED_KV_NAMESPACES(修 20/21) ② MCP 統一帳號來源(單一 remote MCP + .env 切 MCP URL) - MCP 從 sibling repo 搬進 arcrun/mcp/(remote Worker,route 改 mcp.arcrun.dev) - config 加 mcp_url 三層解析 + getMcpUrl + DEFAULT_MCP_URL - 新增 acr mcp-setup:依 config 寫專案 .mcp.json(接案切資料夾自動切 MCP) - acr --version 改動態讀 package.json(根治漂移) ③ Deploy 一致性 - tests/release.feature + scripts/check-release.sh - local-deploy.sh:CLI npm publish + auto patch bump + CHANGELOG - local-deploy.sh bash 3.2 相容修正(mapfile / 空陣列 set -u) - builtins/pnpm-lock.yaml ④ README self-hosted 同步現況(移除 R2 殘留、加 flag/env、多帳號) CLI bump → 1.3.0 Co-Authored-By: Claude Opus 4.8 --- README.md | 34 +- builtins/pnpm-lock.yaml | 898 ++++++ cli/CHANGELOG.md | 22 + cli/package-lock.json | 4 +- cli/package.json | 2 +- cli/src/commands/init.ts | 71 +- cli/src/commands/mcp-setup.ts | 57 + cli/src/commands/update.ts | 42 +- cli/src/index.ts | 23 +- cli/src/lib/config.ts | 24 +- cli/src/lib/deploy.ts | 9 +- cypher-executor/scripts/seed-api-recipes.ts | 9 +- cypher-executor/src/index.ts | 2 + .../src/lib/api-recipe-seeds.ts | 17 +- cypher-executor/src/routes/init-seed.ts | 102 + mcp/.gitignore | 16 + mcp/GUIDE.md | 477 ++++ mcp/README.md | 200 ++ mcp/package.json | 25 + mcp/pnpm-lock.yaml | 2523 +++++++++++++++++ mcp/src/component.schema.json | 10 + mcp/src/index.ts | 242 ++ mcp/src/lib/cypher-client.ts | 101 + mcp/src/lib/kbdb-client.ts | 13 + mcp/src/mcp-handler.ts | 19 + mcp/src/middleware/partner-auth.ts | 35 + mcp/src/pages/inspector.html | 674 +++++ mcp/src/pages/inspector.ts | 661 +++++ mcp/src/tools/arcrun_introspection.ts | 213 ++ mcp/src/tools/arcrun_report_feedback.ts | 147 + mcp/src/tools/arcrun_skills_examples.ts | 315 ++ mcp/src/tools/arcrun_workflow_crud.ts | 379 +++ mcp/src/tools/registry.ts | 49 + mcp/src/tools/u6u_create_tag.ts | 47 + mcp/src/tools/u6u_delete_tag.ts | 30 + mcp/src/tools/u6u_deploy_workflow.ts | 81 + mcp/src/tools/u6u_execute_workflow.ts | 54 + mcp/src/tools/u6u_get_component.ts | 59 + mcp/src/tools/u6u_get_component_guide.ts | 47 + mcp/src/tools/u6u_get_gui_context.ts | 84 + mcp/src/tools/u6u_get_workflow.ts | 33 + mcp/src/tools/u6u_list_components.ts | 39 + mcp/src/tools/u6u_list_tags.ts | 26 + mcp/src/tools/u6u_list_workflows.ts | 39 + mcp/src/tools/u6u_publish_component.ts | 83 + mcp/src/tools/u6u_search_components.ts | 65 + mcp/src/tools/u6u_tag_resource.ts | 57 + mcp/src/tools/u6u_untag_resource.ts | 42 + mcp/src/types.ts | 17 + mcp/src/workflow.schema.json | 27 + mcp/tests/unit/partner-auth.test.ts | 42 + mcp/tests/unit/tools/list-workflows.test.ts | 48 + mcp/tests/unit/tools/tag-management.test.ts | 53 + mcp/tsconfig.json | 14 + mcp/wrangler.toml | 26 + scripts/check-release.sh | 91 + scripts/local-deploy.sh | 92 +- tests/release.feature | 71 + 58 files changed, 8608 insertions(+), 74 deletions(-) create mode 100644 builtins/pnpm-lock.yaml create mode 100644 cli/CHANGELOG.md create mode 100644 cli/src/commands/mcp-setup.ts rename {cli => cypher-executor}/src/lib/api-recipe-seeds.ts (83%) create mode 100644 cypher-executor/src/routes/init-seed.ts create mode 100644 mcp/.gitignore create mode 100644 mcp/GUIDE.md create mode 100644 mcp/README.md create mode 100644 mcp/package.json create mode 100644 mcp/pnpm-lock.yaml create mode 100644 mcp/src/component.schema.json create mode 100644 mcp/src/index.ts create mode 100644 mcp/src/lib/cypher-client.ts create mode 100644 mcp/src/lib/kbdb-client.ts create mode 100644 mcp/src/mcp-handler.ts create mode 100644 mcp/src/middleware/partner-auth.ts create mode 100644 mcp/src/pages/inspector.html create mode 100644 mcp/src/pages/inspector.ts create mode 100644 mcp/src/tools/arcrun_introspection.ts create mode 100644 mcp/src/tools/arcrun_report_feedback.ts create mode 100644 mcp/src/tools/arcrun_skills_examples.ts create mode 100644 mcp/src/tools/arcrun_workflow_crud.ts create mode 100644 mcp/src/tools/registry.ts create mode 100644 mcp/src/tools/u6u_create_tag.ts create mode 100644 mcp/src/tools/u6u_delete_tag.ts create mode 100644 mcp/src/tools/u6u_deploy_workflow.ts create mode 100644 mcp/src/tools/u6u_execute_workflow.ts create mode 100644 mcp/src/tools/u6u_get_component.ts create mode 100644 mcp/src/tools/u6u_get_component_guide.ts create mode 100644 mcp/src/tools/u6u_get_gui_context.ts create mode 100644 mcp/src/tools/u6u_get_workflow.ts create mode 100644 mcp/src/tools/u6u_list_components.ts create mode 100644 mcp/src/tools/u6u_list_tags.ts create mode 100644 mcp/src/tools/u6u_list_workflows.ts create mode 100644 mcp/src/tools/u6u_publish_component.ts create mode 100644 mcp/src/tools/u6u_search_components.ts create mode 100644 mcp/src/tools/u6u_tag_resource.ts create mode 100644 mcp/src/tools/u6u_untag_resource.ts create mode 100644 mcp/src/types.ts create mode 100644 mcp/src/workflow.schema.json create mode 100644 mcp/tests/unit/partner-auth.test.ts create mode 100644 mcp/tests/unit/tools/list-workflows.test.ts create mode 100644 mcp/tests/unit/tools/tag-management.test.ts create mode 100644 mcp/tsconfig.json create mode 100644 mcp/wrangler.toml create mode 100755 scripts/check-release.sh create mode 100644 tests/release.feature diff --git a/README.md b/README.md index df74b3a..69d2342 100644 --- a/README.md +++ b/README.md @@ -95,16 +95,17 @@ arcrun 是 self-hosted 開源:你用**自己的** Cloudflare 帳號跑整套 **Account ID**:登入後在 [dash.cloudflare.com](https://dash.cloudflare.com) 隨便進一個區段,網址列會是 `dash.cloudflare.com/<這串就是 Account ID>`;或在右側欄 "Account ID" 直接複製。 -**API Token**:到 [My Profile → API Tokens](https://dash.cloudflare.com/profile/api-tokens) → **Create Token** → **Create Custom Token**,給以下權限(CLI 用它建 KV / 部署 Worker): +**API Token**:到 [My Profile → API Tokens](https://dash.cloudflare.com/profile/api-tokens) → **Create Token** → **Create Custom Token**,給以下**兩個**權限(CLI 用它建 KV / 部署 Worker): | 類型 | 項目 | 權限 | |---|---|---| | Account | Workers Scripts | Edit | | Account | Workers KV Storage | Edit | -| Account | Workers R2 Storage | Edit | 建好後**複製那串 token**(只會顯示一次)。CLI 不代管你的憑證——你自己建、自己持有。 +> 只需要這兩個權限。**不需要 R2、不需要綁信用卡**——arcrun self-hosted 只用 Workers + KV,兩者都在 Cloudflare 免費額度。 + ### 2. 安裝 Cloudflare CLI(wrangler) CLI 部署 Worker 時會用到 wrangler。先裝它: @@ -129,16 +130,27 @@ CLI 會問你 **Account ID** 和 **API Token**(步驟 1 取得的),貼上 ``` → 驗證 Cloudflare 憑證... ✓ -→ KV WEBHOOKS... ✓ (建 7 個 KV namespace,已存在則重用) -→ R2 WASM_BUCKET... ✓ +→ KV WEBHOOKS... ✓ (建 KV namespace,已存在則重用) → workers.dev subdomain: your-account → 下載部署物 + 部署 Worker(從 GitHub 拉預編譯 wasm,用你的 CF token 部署)... - ✓ 部署完成:19 個 Worker 全部成功 -→ seed 10 個 API recipe... ✓ -✓ Cloudflare 資源就緒(7 KV + R2) + ✓ 部署完成:所有 Worker 全部成功 +→ seed recipe(API recipe + auth recipe,由 API 灌入)... ✓ +✓ Cloudflare 資源就緒(KV 全建妥,免費額度即可,無需綁卡) ✓ 設定寫入 ~/.arcrun/config.yaml ``` +**非互動 / 給 AI、CI 用**:不想被問答打斷,可用 flag 或環境變數一次帶入: + +```bash +# flag(優先序最高) +acr init --self-hosted --account-id <你的 Account ID> --api-token <你的 API Token> + +# 或環境變數(與 wrangler 慣例一致) +export CLOUDFLARE_ACCOUNT_ID=<你的 Account ID> +export CLOUDFLARE_API_TOKEN=<你的 API Token> +acr init --self-hosted +``` + 你不需要懂 git、不需要懂 tinygo、不需要手動建任何東西——預編譯好的零件(`.wasm`)直接從 GitHub 下載,用**你自己的** CF token 部署到**你的**帳號。 **最後一步(手動,CLI 會印提示)**:設定加密金鑰 secret。這一步刻意不自動化(密鑰不進工具流程): @@ -155,6 +167,14 @@ wrangler secret put ENCRYPTION_KEY --name arcrun-auth-service-account > 想先不碰 Cloudflare、純在本機感受語法?`acr init --local` 然後直接跳到下面「寫一個工作流」。 +### 多帳號 / 接案(同一台電腦連不同 CF 帳號) + +設定採三層,優先序 **環境變數 > 專案層 `.arcrun.yaml` > 全域 `~/.arcrun/config.yaml`**(仿 `git config`): + +- **自己的專案**:什麼都不放 → 自動用全域(你自己的 CF)。 +- **幫客戶接案**:在客戶資料夾放一份 `.arcrun.yaml`(含該客戶的 cypher URL / api_key)→ 只在這個資料夾樹生效,離開自動切回全域。`.arcrun.yaml` 含憑證,`init` 會自動幫你加進 `.gitignore`。 +- **不確定現在用哪個帳號?** `acr config --where` 會逐欄告訴你每個值來自哪一層。 + --- ## 裝好之後:開始用 diff --git a/builtins/pnpm-lock.yaml b/builtins/pnpm-lock.yaml new file mode 100644 index 0000000..049e8e0 --- /dev/null +++ b/builtins/pnpm-lock.yaml @@ -0,0 +1,898 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + hono: + specifier: ^4.7.0 + version: 4.12.23 + devDependencies: + '@cloudflare/workers-types': + specifier: ^4.20250219.0 + version: 4.20260606.1 + typescript: + specifier: ^5.7.0 + version: 5.9.3 + wrangler: + specifier: ^4.0.0 + version: 4.98.0(@cloudflare/workers-types@4.20260606.1) + +packages: + + '@cloudflare/kv-asset-handler@0.5.0': + resolution: {integrity: sha512-jxQYkj8dSIzc0cD6cMMNdOc1UVjqSqu8BZdor5s8cGjW2I8BjODt/kWPVdY+u9zj3ms75Q5qaZgnxUad83+eAg==} + engines: {node: '>=22.0.0'} + + '@cloudflare/unenv-preset@2.16.1': + resolution: {integrity: sha512-ECxObrMfyTl5bhQf/lZCXwo5G6xX9IAUo+nDMKK4SZ8m4Jvvxp52vilxyySSWh2YTZz8+HQ07qGH/2rEom1vDw==} + peerDependencies: + unenv: 2.0.0-rc.24 + workerd: '>1.20260305.0 <2.0.0-0' + peerDependenciesMeta: + workerd: + optional: true + + '@cloudflare/workerd-darwin-64@1.20260603.1': + resolution: {integrity: sha512-cEXDWu6V3ZrpmwWkM4OJE9AeXjdAgOY5rh8EHhcBVCuP5rxnzUbPzLtrVOHx0UUUAcCrFq0Xsa6mZKL1VUZsKQ==} + engines: {node: '>=16'} + cpu: [x64] + os: [darwin] + + '@cloudflare/workerd-darwin-arm64@1.20260603.1': + resolution: {integrity: sha512-uBPK4LaWJNbbCYwPnUAehlHbbVulhVZPZsdcAhBPfZhHb3QAuAEPAQepO/P67R3V6Cni4YGx1fLbL8A5wwoaNA==} + engines: {node: '>=16'} + cpu: [arm64] + os: [darwin] + + '@cloudflare/workerd-linux-64@1.20260603.1': + resolution: {integrity: sha512-ht9l6/8Tk7Rp6kA4S9oFZ4X8u0VjnnFdmU/6B3fnABYKREYTKh2RdOqXqXxcp5eNJseireKnWik/hQOPK1CutQ==} + engines: {node: '>=16'} + cpu: [x64] + os: [linux] + + '@cloudflare/workerd-linux-arm64@1.20260603.1': + resolution: {integrity: sha512-LJZ6x00rAjSrobV4m0ZW0TpH5ilBbKcWBzlH+y+KOUsIE/CpTuhAzKV43TbSnFLRX5+jrWKiz2v0hO91lPXy6A==} + engines: {node: '>=16'} + cpu: [arm64] + os: [linux] + + '@cloudflare/workerd-windows-64@1.20260603.1': + resolution: {integrity: sha512-DvwqkXMAJRPoDN4PxapAwhlz/6ouD+6R1ttbAEK3cWD/QBvFF5STx7Ds/9Irf+rBly3np3uHWkeX+wZnNFEuzA==} + engines: {node: '>=16'} + cpu: [x64] + os: [win32] + + '@cloudflare/workers-types@4.20260606.1': + resolution: {integrity: sha512-0FFUsixapowVJcAjRlXLb6UEZG1caUlSuUX1KHhKgWgjKxq20dY5XeCS5lKPqgc80XJ9puwffJ2H1U6Fwr5N1g==} + + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + + '@esbuild/aix-ppc64@0.27.3': + resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.27.3': + resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.27.3': + resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.27.3': + resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.27.3': + resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.3': + resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.27.3': + resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.3': + resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.27.3': + resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.27.3': + resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.27.3': + resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.27.3': + resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.27.3': + resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.27.3': + resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.3': + resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.27.3': + resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.27.3': + resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.27.3': + resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.3': + resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.27.3': + resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.3': + resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.27.3': + resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.27.3': + resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.27.3': + resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.27.3': + resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.27.3': + resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + + '@poppinss/colors@4.1.6': + resolution: {integrity: sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==} + + '@poppinss/dumper@0.6.5': + resolution: {integrity: sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==} + + '@poppinss/exception@1.2.3': + resolution: {integrity: sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==} + + '@sindresorhus/is@7.2.0': + resolution: {integrity: sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==} + engines: {node: '>=18'} + + '@speed-highlight/core@1.2.15': + resolution: {integrity: sha512-BMq1K3DsElxDWawkX6eLg9+CKJrTVGCBAWVuHXVUV2u0s2711qiChLSId6ikYPfxhdYocLNt3wWwSvDiTvFabw==} + + blake3-wasm@2.1.5: + resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==} + + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} + engines: {node: '>=18'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + error-stack-parser-es@1.0.5: + resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} + + esbuild@0.27.3: + resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} + engines: {node: '>=18'} + hasBin: true + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + hono@4.12.23: + resolution: {integrity: sha512-eIaZ9qDgu7XV0pxOCrg7/WhnQ6Ivm22UcxhXx/A3dcbqbbYgBEkc6e/J/s7j2tS96zoB0S9VBdLwQNCWwUo4LA==} + engines: {node: '>=16.9.0'} + + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + + miniflare@4.20260603.0: + resolution: {integrity: sha512-+kMQYB82gC8MPOuojHur3icQsUeZUEJ+Sphuo5rVC3Ri9txBLAW/mH33b9OVrpmkogQeaaqPS4tPtugJZhk5Kw==} + engines: {node: '>=22.0.0'} + hasBin: true + + path-to-regexp@6.3.0: + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + semver@7.8.2: + resolution: {integrity: sha512-c8jsqUZm3omBOI66G90z1Dyw5z622G8oLG+omfsHBJf3CWQTlOcwOjvOG6wtiNfW6anKm/eA39LMwMtMez2TiQ==} + engines: {node: '>=10'} + hasBin: true + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + supports-color@10.2.2: + resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} + engines: {node: '>=18'} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + undici@7.24.8: + resolution: {integrity: sha512-6KQ/+QxK49Z/p3HO6E5ZCZWNnCasyZLa5ExaVYyvPxUwKtbCPMKELJOqh7EqOle0t9cH/7d2TaaTRRa6Nhs4YQ==} + engines: {node: '>=20.18.1'} + + unenv@2.0.0-rc.24: + resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==} + + workerd@1.20260603.1: + resolution: {integrity: sha512-NPcbhI1++CS+fnELyXtsIR52en+5kwr/OrKeiQeYXGy10HxmPdsQBv9N+DU7hJIOOmBHhOGAAsoGDjyiQ2YCaA==} + engines: {node: '>=16'} + hasBin: true + + wrangler@4.98.0: + resolution: {integrity: sha512-cXfFUuF4rMIvE0hiMnXjEAB27ERryaCgquBJdUoPIjFzYYE1rbRdMUkEdQ18qDPUtsPvhJdqxLntixT9OfSzQw==} + engines: {node: '>=22.0.0'} + hasBin: true + peerDependencies: + '@cloudflare/workers-types': ^4.20260603.1 + peerDependenciesMeta: + '@cloudflare/workers-types': + optional: true + + ws@8.20.1: + resolution: {integrity: sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + youch-core@0.3.3: + resolution: {integrity: sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==} + + youch@4.1.0-beta.10: + resolution: {integrity: sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==} + +snapshots: + + '@cloudflare/kv-asset-handler@0.5.0': {} + + '@cloudflare/unenv-preset@2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260603.1)': + dependencies: + unenv: 2.0.0-rc.24 + optionalDependencies: + workerd: 1.20260603.1 + + '@cloudflare/workerd-darwin-64@1.20260603.1': + optional: true + + '@cloudflare/workerd-darwin-arm64@1.20260603.1': + optional: true + + '@cloudflare/workerd-linux-64@1.20260603.1': + optional: true + + '@cloudflare/workerd-linux-arm64@1.20260603.1': + optional: true + + '@cloudflare/workerd-windows-64@1.20260603.1': + optional: true + + '@cloudflare/workers-types@4.20260606.1': {} + + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + + '@emnapi/runtime@1.10.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@esbuild/aix-ppc64@0.27.3': + optional: true + + '@esbuild/android-arm64@0.27.3': + optional: true + + '@esbuild/android-arm@0.27.3': + optional: true + + '@esbuild/android-x64@0.27.3': + optional: true + + '@esbuild/darwin-arm64@0.27.3': + optional: true + + '@esbuild/darwin-x64@0.27.3': + optional: true + + '@esbuild/freebsd-arm64@0.27.3': + optional: true + + '@esbuild/freebsd-x64@0.27.3': + optional: true + + '@esbuild/linux-arm64@0.27.3': + optional: true + + '@esbuild/linux-arm@0.27.3': + optional: true + + '@esbuild/linux-ia32@0.27.3': + optional: true + + '@esbuild/linux-loong64@0.27.3': + optional: true + + '@esbuild/linux-mips64el@0.27.3': + optional: true + + '@esbuild/linux-ppc64@0.27.3': + optional: true + + '@esbuild/linux-riscv64@0.27.3': + optional: true + + '@esbuild/linux-s390x@0.27.3': + optional: true + + '@esbuild/linux-x64@0.27.3': + optional: true + + '@esbuild/netbsd-arm64@0.27.3': + optional: true + + '@esbuild/netbsd-x64@0.27.3': + optional: true + + '@esbuild/openbsd-arm64@0.27.3': + optional: true + + '@esbuild/openbsd-x64@0.27.3': + optional: true + + '@esbuild/openharmony-arm64@0.27.3': + optional: true + + '@esbuild/sunos-x64@0.27.3': + optional: true + + '@esbuild/win32-arm64@0.27.3': + optional: true + + '@esbuild/win32-ia32@0.27.3': + optional: true + + '@esbuild/win32-x64@0.27.3': + optional: true + + '@img/colour@1.1.0': {} + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.10.0 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@poppinss/colors@4.1.6': + dependencies: + kleur: 4.1.5 + + '@poppinss/dumper@0.6.5': + dependencies: + '@poppinss/colors': 4.1.6 + '@sindresorhus/is': 7.2.0 + supports-color: 10.2.2 + + '@poppinss/exception@1.2.3': {} + + '@sindresorhus/is@7.2.0': {} + + '@speed-highlight/core@1.2.15': {} + + blake3-wasm@2.1.5: {} + + cookie@1.1.1: {} + + detect-libc@2.1.2: {} + + error-stack-parser-es@1.0.5: {} + + esbuild@0.27.3: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.3 + '@esbuild/android-arm': 0.27.3 + '@esbuild/android-arm64': 0.27.3 + '@esbuild/android-x64': 0.27.3 + '@esbuild/darwin-arm64': 0.27.3 + '@esbuild/darwin-x64': 0.27.3 + '@esbuild/freebsd-arm64': 0.27.3 + '@esbuild/freebsd-x64': 0.27.3 + '@esbuild/linux-arm': 0.27.3 + '@esbuild/linux-arm64': 0.27.3 + '@esbuild/linux-ia32': 0.27.3 + '@esbuild/linux-loong64': 0.27.3 + '@esbuild/linux-mips64el': 0.27.3 + '@esbuild/linux-ppc64': 0.27.3 + '@esbuild/linux-riscv64': 0.27.3 + '@esbuild/linux-s390x': 0.27.3 + '@esbuild/linux-x64': 0.27.3 + '@esbuild/netbsd-arm64': 0.27.3 + '@esbuild/netbsd-x64': 0.27.3 + '@esbuild/openbsd-arm64': 0.27.3 + '@esbuild/openbsd-x64': 0.27.3 + '@esbuild/openharmony-arm64': 0.27.3 + '@esbuild/sunos-x64': 0.27.3 + '@esbuild/win32-arm64': 0.27.3 + '@esbuild/win32-ia32': 0.27.3 + '@esbuild/win32-x64': 0.27.3 + + fsevents@2.3.3: + optional: true + + hono@4.12.23: {} + + kleur@4.1.5: {} + + miniflare@4.20260603.0: + dependencies: + '@cspotcode/source-map-support': 0.8.1 + sharp: 0.34.5 + undici: 7.24.8 + workerd: 1.20260603.1 + ws: 8.20.1 + youch: 4.1.0-beta.10 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + path-to-regexp@6.3.0: {} + + pathe@2.0.3: {} + + semver@7.8.2: {} + + sharp@0.34.5: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.2 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + + supports-color@10.2.2: {} + + tslib@2.8.1: + optional: true + + typescript@5.9.3: {} + + undici@7.24.8: {} + + unenv@2.0.0-rc.24: + dependencies: + pathe: 2.0.3 + + workerd@1.20260603.1: + optionalDependencies: + '@cloudflare/workerd-darwin-64': 1.20260603.1 + '@cloudflare/workerd-darwin-arm64': 1.20260603.1 + '@cloudflare/workerd-linux-64': 1.20260603.1 + '@cloudflare/workerd-linux-arm64': 1.20260603.1 + '@cloudflare/workerd-windows-64': 1.20260603.1 + + wrangler@4.98.0(@cloudflare/workers-types@4.20260606.1): + dependencies: + '@cloudflare/kv-asset-handler': 0.5.0 + '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260603.1) + blake3-wasm: 2.1.5 + esbuild: 0.27.3 + miniflare: 4.20260603.0 + path-to-regexp: 6.3.0 + unenv: 2.0.0-rc.24 + workerd: 1.20260603.1 + optionalDependencies: + '@cloudflare/workers-types': 4.20260606.1 + fsevents: 2.3.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + ws@8.20.1: {} + + youch-core@0.3.3: + dependencies: + '@poppinss/exception': 1.2.3 + error-stack-parser-es: 1.0.5 + + youch@4.1.0-beta.10: + dependencies: + '@poppinss/colors': 4.1.6 + '@poppinss/dumper': 0.6.5 + '@speed-highlight/core': 1.2.15 + cookie: 1.1.1 + youch-core: 0.3.3 diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md new file mode 100644 index 0000000..9b7c6b7 --- /dev/null +++ b/cli/CHANGELOG.md @@ -0,0 +1,22 @@ +# arcrun CLI Changelog + +> 由 `scripts/local-deploy.sh` 在 deploy 時自動維護(version bump + 此檔記錄)。 +> 也可手動編輯補充細節。最新在最上。 + +## 1.3.0 — 2026-06-06 +- MCP 搬進 arcrun/mcp/ + acr mcp-setup(依 config mcp_url 寫專案 .mcp.json,接案切資料夾自動切 MCP) +- config 加 mcp_url 三層解析(env ARCRUN_MCP_URL > 專案 > 全域)+ getMcpUrl() +- acr --version 改從 package.json 動態讀(不再 hardcode,避免漂移) +- seed 下沉成 API 行為(POST /init/seed);CLI init/update 改薄殼一次呼叫 +- registry SUBMISSIONS_KV 補進 REQUIRED_KV_NAMESPACES(修 20/21) + +## 1.2.0 — 2026-06-05 +- self-hosted fork 阻斷四項修正:strip arcrun.dev routes / R2 / AI binding;移除 R2(不綁卡) +- init 非互動(--account-id/--api-token + CLOUDFLARE_* env) +- 多帳號/專案 scope:三層 config(env > 專案 .arcrun.yaml > 全域)+ acr config --where + +## 1.1.0 — earlier +- auth recipe 系統:20 個服務預建;acr auth-recipe 指令 + +## 1.0.x — earlier +- 初始發布 → recipe / creds / push / parts / webhooks / config 分離等(見 arcrun.md CLI 版本表) diff --git a/cli/package-lock.json b/cli/package-lock.json index d287621..c114379 100644 --- a/cli/package-lock.json +++ b/cli/package-lock.json @@ -1,12 +1,12 @@ { "name": "arcrun", - "version": "1.0.2", + "version": "1.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "arcrun", - "version": "1.0.2", + "version": "1.3.0", "license": "MIT", "dependencies": { "chalk": "^5.3.0", diff --git a/cli/package.json b/cli/package.json index beb593f..317b8b8 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,6 +1,6 @@ { "name": "arcrun", - "version": "1.2.0", + "version": "1.3.0", "description": "AI Workflow CLI for arcrun — self-host WASM-based AI workflows on your own Cloudflare", "bin": { "acr": "dist/index.js" diff --git a/cli/src/commands/init.ts b/cli/src/commands/init.ts index 52f380f..cb060e1 100644 --- a/cli/src/commands/init.ts +++ b/cli/src/commands/init.ts @@ -16,8 +16,8 @@ import { downloadAndDeploy, type DeployContext, } from '../lib/deploy.js'; -import { API_RECIPE_SEEDS } from '../lib/api-recipe-seeds.js'; import { cmdInstallHarness } from './install-harness.js'; +import { cmdMcpSetup } from './mcp-setup.js'; const ARCRUN_REGISTER_URL = 'https://cypher.arcrun.dev/register'; @@ -57,6 +57,14 @@ export async function cmdInit(options: InitOptions): Promise { } catch (e) { console.log(chalk.gray(` (harness 安裝略過:${e instanceof Error ? e.message : e};可稍後跑 acr install-harness)`)); } + + // 順便寫專案 .mcp.json,讓 Claude Code 連對的 MCP(依 config 的 mcp_url,SDD mcp-account-source.md)。 + // 失敗不影響 init(可事後 acr mcp-setup 補)。 + try { + cmdMcpSetup(); + } catch (e) { + console.log(chalk.gray(` (.mcp.json 略過:${e instanceof Error ? e.message : e};可稍後跑 acr mcp-setup)`)); + } } async function initLocal(): Promise { @@ -129,7 +137,7 @@ async function initStandard(rl: ReturnType): Promise { - process.stdout.write(chalk.gray(` → seed ${API_RECIPE_SEEDS.length} 個 API recipe...`)); - let ok = 0; - for (const r of API_RECIPE_SEEDS) { - try { - const res = await fetch(`${cypherUrl}/recipes`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - canonical_id: r.canonical_id, - display_name: r.display_name, - description: r.description, - endpoint: r.endpoint, - method: r.method, - auth_service: r.auth_service, - exposure_consent: { - confirmed_by_human: true, - understood: `platform seed recipe: ${r.canonical_id} → ${r.endpoint}`, - confirmed_at: new Date().toISOString(), - }, - }), - }); - if (res.ok) ok++; - } catch { - // 單筆失敗不中斷整個 init;最終回報數量 +/** + * 薄殼:呼叫 API 的 /init/seed 一次(rule 07)。 + * seed 的編排 + 種子資料全在 cypher-executor(routes/init-seed.ts),CLI 不自己迴圈 POST。 + * 之前 seedApiRecipes 在 CLI 迴圈 POST + deployFullyOk gate 是壓測 §4.1 的反例,已移除。 + */ +async function callSeedEndpoint(cypherUrl: string): Promise { + process.stdout.write(chalk.gray(' → seed recipe(API recipe + auth recipe,由 API 灌入)...')); + try { + const res = await fetch(`${cypherUrl}/init/seed`, { method: 'POST' }); + const body = await res.json().catch(() => null) as + | { success?: boolean; message?: string } + | null; + if (res.ok && body?.success) { + console.log(chalk.green(` ✓ ${body.message ?? ''}`)); + } else { + // 誠實:不假綠。seed 沒全成就明說,提示 acr update 可重跑(冪等)。 + console.log(chalk.yellow(` ⚠ ${body?.message ?? `HTTP ${res.status}`}(可 acr update 重跑,seed 冪等)`)); } + } catch (e) { + console.log(chalk.yellow(` ⚠ seed 端點呼叫失敗(${e instanceof Error ? e.message : e});cypher 穩定後 acr update 重跑`)); } - console.log(ok === API_RECIPE_SEEDS.length ? chalk.green(' ✓') : chalk.yellow(` ${ok}/${API_RECIPE_SEEDS.length}`)); } function createHelloYamlIfMissing(): void { diff --git a/cli/src/commands/mcp-setup.ts b/cli/src/commands/mcp-setup.ts new file mode 100644 index 0000000..ee2e835 --- /dev/null +++ b/cli/src/commands/mcp-setup.ts @@ -0,0 +1,57 @@ +/** + * acr mcp-setup — 在目前資料夾寫 / 更新 .mcp.json,讓 Claude Code 連對的 arcrun MCP。 + * + * 薄殼原則(rule 07 + SDD mcp-account-source.md): + * MCP URL 與 cypher URL 一樣,由同一份三層 config 解析(env > 專案 .arcrun.yaml > 全域)決定。 + * 「切換帳號」= 在客戶資料夾跑 acr mcp-setup(讀該資料夾的 .arcrun.yaml)→ 產指向客戶 MCP 的 .mcp.json。 + * 進哪個專案資料夾 → Claude Code 讀該專案 .mcp.json → 連對應 MCP(綁該帳號的 cypher)。 + * + * 不重實作身份解析:呼叫 config.ts 的 getMcpUrl()(唯一解析來源)。 + */ + +import chalk from 'chalk'; +import { readFileSync, writeFileSync, existsSync } from 'node:fs'; +import { join } from 'node:path'; +import { loadConfig, getMcpUrl, DEFAULT_MCP_URL } from '../lib/config.js'; + +/** Claude Code .mcp.json 的 server 條目(remote HTTP MCP)。 */ +interface McpServerEntry { + type: 'http'; + url: string; +} +interface McpJson { + mcpServers?: Record>; + [k: string]: unknown; +} + +const SERVER_KEY = 'arcrun'; + +export function cmdMcpSetup(): void { + const config = loadConfig(); + const mcpUrl = getMcpUrl(config); + + const target = join(process.cwd(), '.mcp.json'); + + // 讀既有 .mcp.json(保留其他 MCP server 條目,只覆寫 arcrun 這條) + let doc: McpJson = {}; + if (existsSync(target)) { + try { + doc = JSON.parse(readFileSync(target, 'utf8')) as McpJson; + } catch { + console.log(chalk.yellow(` ⚠ 既有 .mcp.json 解析失敗,將以新內容覆寫整檔。`)); + doc = {}; + } + } + + if (!doc.mcpServers || typeof doc.mcpServers !== 'object') doc.mcpServers = {}; + doc.mcpServers[SERVER_KEY] = { type: 'http', url: mcpUrl }; + + writeFileSync(target, JSON.stringify(doc, null, 2) + '\n', 'utf8'); + + console.log(chalk.green(`\n ✓ 已寫入 ${target}`)); + console.log(chalk.gray(` arcrun MCP → ${mcpUrl}`)); + if (mcpUrl === DEFAULT_MCP_URL && (!config.mcp_url || config.mcp_url.trim() === '')) { + console.log(chalk.gray(` (用平台預設;要連自己/客戶的 MCP,在 config 設 mcp_url 或 ARCRUN_MCP_URL env,再重跑)`)); + } + console.log(chalk.gray(` Claude Code 進此資料夾會自動連這台 MCP。切帳號 = 在對應資料夾重跑 acr mcp-setup。\n`)); +} diff --git a/cli/src/commands/update.ts b/cli/src/commands/update.ts index 3decba2..c1f7c83 100644 --- a/cli/src/commands/update.ts +++ b/cli/src/commands/update.ts @@ -12,9 +12,11 @@ import chalk from 'chalk'; import { loadConfig } from '../lib/config.js'; +import { CfAccountClient } from '../lib/cf-api.js'; import { wranglerAvailable, downloadAndDeploy, + REQUIRED_KV_NAMESPACES, type DeployContext, } from '../lib/deploy.js'; @@ -40,20 +42,50 @@ export async function cmdUpdate(): Promise { console.log(chalk.bold('\n acr update — 拉新 release 並重新部署\n')); + // 重新解析「全部」KV namespace id(冪等:已存在則重用),不只 config 存的兩個。 + // 壓測 §4.1.3:舊版 update 只注入 WEBHOOKS+CREDENTIALS_KV,其餘 6 個注入成空字串 → + // 重部署反而可能弄壞需要 RECIPES/EXEC_CONTEXT/... 的 worker。改為與 init 同樣全建妥。 + const cf = new CfAccountClient(config.cloudflare_account_id, config.cf_api_token); + const kvNamespaceIds: Record = {}; + try { + const existing = await cf.listKvNamespaces(); + for (const title of REQUIRED_KV_NAMESPACES) { + kvNamespaceIds[title] = await cf.ensureKvNamespace(title, existing); + } + } catch (e) { + console.log(chalk.yellow(`\n ✗ 解析 KV namespace 失敗:${e instanceof Error ? e.message : e}\n`)); + process.exit(1); + } + const ctx: DeployContext = { accountId: config.cloudflare_account_id, apiToken: config.cf_api_token, workerSubdomain: extractSubdomain(config.cypher_executor_url), - kvNamespaceIds: { - WEBHOOKS: config.webhooks_kv_namespace_id ?? '', - CREDENTIALS_KV: config.credentials_kv_namespace_id ?? '', - }, + kvNamespaceIds, }; const result = await downloadAndDeploy(ctx); if (result.implemented) { - console.log(chalk.green('\n ✓ 更新完成\n')); + console.log(chalk.green('\n ✓ 部署完成')); + // 重跑 seed(薄殼:呼叫 API /init/seed;冪等,覆寫既有)。 + // 修壓測 §4.1.3「update 不做 seed,但 init 提示說 update 會重試 seed」的矛盾。 + const cypherUrl = config.cypher_executor_url + ?? result.cypherExecutorUrl + ?? (ctx.workerSubdomain ? `https://arcrun-cypher-executor.${ctx.workerSubdomain}.workers.dev` : ''); + if (cypherUrl) { + process.stdout.write(chalk.gray(' → 重新 seed recipe(API + auth,由 API 灌入)...')); + try { + const res = await fetch(`${cypherUrl}/init/seed`, { method: 'POST' }); + const body = await res.json().catch(() => null) as { success?: boolean; message?: string } | null; + console.log(res.ok && body?.success + ? chalk.green(` ✓ ${body.message ?? ''}`) + : chalk.yellow(` ⚠ ${body?.message ?? `HTTP ${res.status}`}`)); + } catch (e) { + console.log(chalk.yellow(` ⚠ seed 失敗(${e instanceof Error ? e.message : e})`)); + } + } + console.log(''); } else { console.log(chalk.yellow(' ⚠ 更新尚未自動化:')); console.log(chalk.gray(' ' + result.message.split('\n').join('\n ')) + '\n'); diff --git a/cli/src/index.ts b/cli/src/index.ts index 1cbbb8a..74d61c8 100644 --- a/cli/src/index.ts +++ b/cli/src/index.ts @@ -7,6 +7,9 @@ * 使用:acr <指令> */ import { Command } from 'commander'; +import { readFileSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { dirname, join } from 'node:path'; import { cmdInit } from './commands/init.js'; import { cmdConfig } from './commands/config.js'; import { cmdCredsPush } from './commands/creds.js'; @@ -19,14 +22,26 @@ import { cmdList } from './commands/list.js'; import { cmdLogs } from './commands/logs.js'; import { cmdUpdate } from './commands/update.js'; import { cmdInstallHarness } from './commands/install-harness.js'; +import { cmdMcpSetup } from './commands/mcp-setup.js'; import { cmdAuthRecipeList, cmdAuthRecipeInfo, cmdAuthRecipeScaffold } from './commands/auth-recipe.js'; const program = new Command(); +// 版本從 package.json 動態讀(dist/index.js 旁的 ../package.json),不 hardcode → 永不漂移。 +// 之前 hardcode '1.1.0' 與 package.json '1.2.0' 不一致,正是「忘了改」的反例。 +function readVersion(): string { + try { + const here = dirname(fileURLToPath(import.meta.url)); + return (JSON.parse(readFileSync(join(here, '..', 'package.json'), 'utf8')) as { version?: string }).version ?? '0.0.0'; + } catch { + return '0.0.0'; + } +} + program .name('acr') .description('arcrun — AI Workflow CLI for Cloudflare Workers + WASM') - .version('1.1.0'); + .version(readVersion()); // acr init [--self-hosted] [--account-id ] [--api-token ] program @@ -146,4 +161,10 @@ program .description('把 arcrun 的 CC harness(mindset/提醒/防做歪 hook/指令)裝進當前專案') .action(() => cmdInstallHarness()); +// acr mcp-setup(依 config 解析的 mcp_url 寫專案 .mcp.json,讓 Claude Code 連對的 MCP) +program + .command('mcp-setup') + .description('在目前資料夾寫 .mcp.json 連對的 arcrun MCP(依 config 的 mcp_url;接案切資料夾自動切)') + .action(() => cmdMcpSetup()); + program.parse(process.argv); diff --git a/cli/src/lib/config.ts b/cli/src/lib/config.ts index bad2ba5..1d35414 100644 --- a/cli/src/lib/config.ts +++ b/cli/src/lib/config.ts @@ -21,6 +21,12 @@ export interface ArcrunConfig { credentials_kv_namespace_id?: string; webhooks_kv_namespace_id?: string; // 共用 + // MCP server URL(薄殼原則:CLI 與 MCP 同一份身份解析)。 + // self-hosted / 接案:指向自己 / 客戶的 remote MCP Worker(綁該帳號的 cypher)。 + // 未設 → fallback 平台預設(SaaS 用戶)。acr mcp-setup 依此寫專案 .mcp.json, + // 讓「進哪個專案資料夾 → Claude Code 連那台 MCP」自動生效。 + // SDD: sdk-and-website/mcp-account-source.md + mcp_url?: string; multi_tenant?: boolean; // 資料外流警示:本機記住「已同意暴露 / 選擇不再警示」的資源,避免每次 push 重問(§3 首次問記住)。 // key 格式:`{kind}:{resourceName}`(如 "webhook:contacts_lookup" / "recipe:kbdb_get")。 @@ -43,10 +49,17 @@ const ENV_MAP: Record = { ARCRUN_API_KEY: 'api_key', ARCRUN_ENCRYPTION_KEY: 'encryption_key', ARCRUN_CYPHER_EXECUTOR_URL: 'cypher_executor_url', + ARCRUN_MCP_URL: 'mcp_url', CLOUDFLARE_ACCOUNT_ID: 'cloudflare_account_id', CLOUDFLARE_API_TOKEN: 'cf_api_token', }; +/** + * 平台預設 MCP URL(mcp_url 未設時的 fallback,SaaS 用戶用)。 + * MCP 搬進 arcrun 主庫後改用 arcrun.dev zone(mcp/wrangler.toml route = mcp.arcrun.dev)。 + */ +export const DEFAULT_MCP_URL = 'https://mcp.arcrun.dev'; + export function configExists(): boolean { return existsSync(CONFIG_PATH) || findProjectConfig() !== undefined; } @@ -114,7 +127,7 @@ export function resolveConfigSources(): Array<{ field: keyof ArcrunConfig; value const env = readEnvOverrides(); const fields: (keyof ArcrunConfig)[] = [ 'mode', 'api_key', 'encryption_key', 'cloudflare_account_id', - 'cf_api_token', 'cypher_executor_url', + 'cf_api_token', 'cypher_executor_url', 'mcp_url', ]; const rows: Array<{ field: keyof ArcrunConfig; value: string; source: ConfigSource }> = []; for (const f of fields) { @@ -146,3 +159,12 @@ export function getCypherExecutorUrl(config: ArcrunConfig): string { } return 'https://cypher.arcrun.dev'; } + +/** + * 取得 MCP server URL(薄殼原則:與 cypher_url 同一份 config 解析)。 + * config 有 mcp_url(env/專案/全域 任一層)→ 用它;否則 fallback 平台預設。 + * acr mcp-setup 用此決定要寫進專案 .mcp.json 的 URL → 切資料夾自動切 MCP。 + */ +export function getMcpUrl(config: ArcrunConfig): string { + return config.mcp_url && config.mcp_url.trim() !== '' ? config.mcp_url : DEFAULT_MCP_URL; +} diff --git a/cli/src/lib/deploy.ts b/cli/src/lib/deploy.ts index 3ecec87..afec5dd 100644 --- a/cli/src/lib/deploy.ts +++ b/cli/src/lib/deploy.ts @@ -17,7 +17,13 @@ import { join } from 'node:path'; * 注意:repo 名大小寫敏感(codeload 路徑需完全一致)。*/ const ARCRUN_REPO = process.env.ARCRUN_REPO ?? 'uncle6me-web/Arcrun'; -/** init 要建立的 7 個 KV namespace(title)。權威來源:.claude/rules/01-tech-stack.md 資料儲存表。*/ +/** + * init 要建立的 KV namespace(title)。 + * 前 7 個權威來源:.claude/rules/01-tech-stack.md 資料儲存表(cypher-executor 用)。 + * SUBMISSIONS_KV:registry worker 用(component 投稿)。漏建會讓 registry deploy 失敗 → + * 壓測 §2.6/#11「20/21」根因(registry/wrangler.toml 綁 SUBMISSIONS_KV,但注入清單沒有它, + * 殘留官方舊 id → wrangler deploy 因 KV 不存在而失敗)。補進來後回到 21/21。 + */ export const REQUIRED_KV_NAMESPACES = [ 'WEBHOOKS', 'CREDENTIALS_KV', @@ -26,6 +32,7 @@ export const REQUIRED_KV_NAMESPACES = [ 'SESSIONS_KV', 'ANALYTICS_KV', 'EXEC_CONTEXT', + 'SUBMISSIONS_KV', ] as const; /** 部署後要提示用戶手動 `wrangler secret put ENCRYPTION_KEY` 的 Worker。*/ diff --git a/cypher-executor/scripts/seed-api-recipes.ts b/cypher-executor/scripts/seed-api-recipes.ts index 99ffd4d..8465391 100644 --- a/cypher-executor/scripts/seed-api-recipes.ts +++ b/cypher-executor/scripts/seed-api-recipes.ts @@ -2,8 +2,9 @@ * seed-api-recipes.ts * * 將現役 API recipe 種子上傳至目標 cypher-executor(prod 或 self-host)。 - * 種子資料的單一來源在 CLI 端(cli/src/lib/api-recipe-seeds.ts),此腳本 import 它, - * 避免兩份種子定義漂移。 + * 種子資料的單一來源在 server 端(src/lib/api-recipe-seeds.ts,薄殼原則 rule 07),此腳本 import 它。 + * 注意:self-host init 與 prod 補灌建議改打 POST /init/seed(API 行為,一次灌 API+auth recipe); + * 本腳本保留作為 KV 直寫的備援路徑。 * * 執行: * npx tsx scripts/seed-api-recipes.ts @@ -18,7 +19,9 @@ * 對應 SDD:.agents/specs/arcrun/sdk-and-website/self-hosted-init.md §5 */ -import { API_RECIPE_SEEDS } from '../../cli/src/lib/api-recipe-seeds.js'; +// 種子資料的單一來源已移到 server 端(src/lib/api-recipe-seeds.ts,薄殼原則 rule 07)。 +// 注意:現在 prod 補灌建議直接打 POST /init/seed(API 行為);本腳本保留作為 KV 直寫的備援。 +import { API_RECIPE_SEEDS } from '../src/lib/api-recipe-seeds'; const BASE_URL = process.env.ARCRUN_API_URL ?? 'https://cypher.arcrun.dev'; const API_KEY = process.env.ARCRUN_API_KEY ?? ''; diff --git a/cypher-executor/src/index.ts b/cypher-executor/src/index.ts index 341b9cc..6d68d5b 100644 --- a/cypher-executor/src/index.ts +++ b/cypher-executor/src/index.ts @@ -19,6 +19,7 @@ import { webhooksNamedRouter } from './routes/webhooks-named'; import { authRouter } from './routes/auth'; import { resumeRouter } from './routes/resume'; import { executionsRouter } from './routes/executions'; +import { initSeedRouter } from './routes/init-seed'; const app = new Hono<{ Bindings: Bindings }>(); @@ -46,6 +47,7 @@ app.route('/', credentialsRouter); app.route('/', authRouter); app.route('/', resumeRouter); app.route('/', executionsRouter); // LI SDD M2.1: /executions/* + /workflows/:name/executions +app.route('/', initSeedRouter); // 薄殼原則:seed recipe 是 API 行為(rule 07,壓測 §4.1) // Worker 導出(fetch + scheduled) // scheduled handler 對應 wrangler.toml [triggers].crons,每分鐘 tick; diff --git a/cli/src/lib/api-recipe-seeds.ts b/cypher-executor/src/lib/api-recipe-seeds.ts similarity index 83% rename from cli/src/lib/api-recipe-seeds.ts rename to cypher-executor/src/lib/api-recipe-seeds.ts index 4efc335..5705418 100644 --- a/cli/src/lib/api-recipe-seeds.ts +++ b/cypher-executor/src/lib/api-recipe-seeds.ts @@ -1,16 +1,17 @@ /** - * api-recipe-seeds.ts + * api-recipe-seeds.ts(server 端,唯一真相) * - * 現役 API recipe 的種子定義。self-host 新帳號 init 時把這些灌進空的 RECIPES KV - * (透過 cypher-executor 的 POST /recipes,或 CF KV REST API 直接寫)。 + * 現役 API recipe 的種子定義。self-host 新帳號裝好後,POST /init/seed 端點把這些灌進空的 RECIPES KV。 * * API recipe = http_request + 固定設定(endpoint/method 模板)。 - * 不需 deploy Worker,cypher-executor 執行時直接 fetch(見 cypher-executor/src/routes/recipes.ts)。 + * 不需 deploy Worker,cypher-executor 執行時直接 fetch(見 routes/recipes.ts)。 * - * 放在 CLI 端而非 cypher-executor/src: - * - seed 資料是「installer 要灌進用戶 KV 的種子」,本就屬 CLI 職責(SDD self-hosted-init.md §4)。 - * - rule 02 §2.2 hook 擋 cypher-executor TS hard-code API endpoint;seed 的 endpoint 是資料欄位, - * 放 CLI 端避開誤判,也更符合職責切分。 + * 為何放在 cypher-executor/src(薄殼原則 rule 07 + 壓測 §5.5): + * - 「裝好之後預設有哪些 recipe」是 API 的能力,不是 CLI 的。seed 應由 API 端點完成 + * (POST /init/seed),CLI/MCP 只呼叫一次。種子資料是這個能力的一部分,故放 server。 + * - 種子的 endpoint 字串(sheets.googleapis.com 等)是 recipe 的「資料欄位」(宣告打哪), + * 非 TS 裡的呼叫實作;真正呼叫仍走零件 / http_request。rule 02 §2.2 hook 已對本檔加例外 + * (richblack 2026-06-06 授權,與 auth-recipe-seeds.ts 同理由)。 * * 來源:2026-06-01 從 prod cypher.arcrun.dev/recipes 逐一查得的現役定義。 * 對應 SDD:.agents/specs/arcrun/sdk-and-website/self-hosted-init.md §5 diff --git a/cypher-executor/src/routes/init-seed.ts b/cypher-executor/src/routes/init-seed.ts new file mode 100644 index 0000000..2be1fb7 --- /dev/null +++ b/cypher-executor/src/routes/init-seed.ts @@ -0,0 +1,102 @@ +/** + * /init/seed — 一鍵把平台預建的 recipe 種子灌進 RECIPES KV(API 行為,非介面層職責) + * + * 薄殼原則(rule 07 + 壓測 §4.1/§5.5): + * 「裝好後預設有哪些 recipe」是 API 的能力。seed 由本端點完成,CLI/MCP 等薄殼只呼叫一次。 + * 之前 seed 寫在 CLI init.ts(迴圈 POST + deployFullyOk gate),導致 registry 20/21 連坐 → + * seed 永遠被跳過、auth recipe 從不被 seed(壓測 §4.1)。本端點把 seed 下沉到 API,根除連坐。 + * + * 行為: + * - 冪等:已存在的 recipe 直接覆寫(重跑安全)。 + * - 一次灌「API recipe(API_RECIPE_SEEDS)+ auth recipe(AUTH_RECIPE_SEEDS)」兩者。 + * - 直接寫 KV(不走 POST /recipes 的 exposure_consent gate):種子是平台預建、非用戶互動 push, + * 帶 seed 層級的 consent 憑證(誠實標來源,軌跡可審;mindset §7:機制價值是歸責+可審非防偽)。 + * - 誠實回報:逐筆 ok/fail 計數,不假綠。 + * + * 對應 SDD:.agents/specs/arcrun/sdk-and-website/self-hosted-init.md §5 + */ + +import { Hono } from 'hono'; +import type { Bindings } from '../types'; +import { deriveRecipeHash } from '../lib/hash'; +import type { RecipeDefinition, AuthRecipeDefinition } from './recipes'; +import { API_RECIPE_SEEDS } from '../lib/api-recipe-seeds'; +import { AUTH_RECIPE_SEEDS } from '../lib/auth-recipe-seeds'; + +export const initSeedRouter = new Hono<{ Bindings: Bindings }>(); + +initSeedRouter.post('/init/seed', async (c) => { + const now = Date.now(); + const seedConsent = { + confirmed_by_human: true as const, + understood: 'platform seed (init/seed): 平台預建 recipe,非用戶互動 push', + confirmed_at: new Date(now).toISOString(), + }; + + let apiOk = 0; + let apiFail = 0; + const apiErrors: string[] = []; + + for (const seed of API_RECIPE_SEEDS) { + try { + const canonicalId = seed.canonical_id.trim().toLowerCase(); + const hashId = await deriveRecipeHash(canonicalId); + const existing = await c.env.RECIPES.get(`recipe:${canonicalId}`, 'json') as RecipeDefinition | null; + const recipe: RecipeDefinition = { + canonical_id: canonicalId, + hash_id: hashId, + display_name: seed.display_name, + description: seed.description, + endpoint: seed.endpoint, + method: (seed.method ?? 'POST').toUpperCase(), + auth_service: seed.auth_service, + exposure_consent: existing?.exposure_consent ?? seedConsent, + created_at: existing?.created_at ?? now, + updated_at: now, + }; + await Promise.all([ + c.env.RECIPES.put(`recipe:${canonicalId}`, JSON.stringify(recipe)), + c.env.RECIPES.put(`idx:${hashId}`, canonicalId), + ]); + apiOk++; + } catch (e) { + apiFail++; + apiErrors.push(`${seed.canonical_id}: ${e instanceof Error ? e.message : String(e)}`); + } + } + + let authOk = 0; + let authFail = 0; + const authErrors: string[] = []; + + for (const seed of AUTH_RECIPE_SEEDS) { + try { + const service = seed.service.trim().toLowerCase(); + const existing = await c.env.RECIPES.get(`auth_recipe:${service}`, 'json') as AuthRecipeDefinition | null; + const recipe: AuthRecipeDefinition = { + ...seed, + service, + created_at: existing?.created_at ?? now, + updated_at: now, + }; + await c.env.RECIPES.put(`auth_recipe:${service}`, JSON.stringify(recipe)); + authOk++; + } catch (e) { + authFail++; + authErrors.push(`${seed.service}: ${e instanceof Error ? e.message : String(e)}`); + } + } + + const allOk = apiFail === 0 && authFail === 0; + return c.json( + { + success: allOk, + api_recipes: { seeded: apiOk, failed: apiFail, errors: apiErrors }, + auth_recipes: { seeded: authOk, failed: authFail, errors: authErrors }, + message: allOk + ? `seed 完成:${apiOk} 個 API recipe + ${authOk} 個 auth recipe` + : `seed 部分失敗(誠實回報,未假綠):API ${apiOk}✓/${apiFail}✗,auth ${authOk}✓/${authFail}✗`, + }, + allOk ? 200 : 207, + ); +}); diff --git a/mcp/.gitignore b/mcp/.gitignore new file mode 100644 index 0000000..95c8577 --- /dev/null +++ b/mcp/.gitignore @@ -0,0 +1,16 @@ +node_modules/ +dist/ +.wrangler/ +*.sqlite +*.sqlite-shm +*.sqlite-wal +.env +.env.* +!.env.example +dev/ + +# Kiro IDE spec files (internal planning artifacts) +.kiro/ + +.swarm/ +ruvector.db diff --git a/mcp/GUIDE.md b/mcp/GUIDE.md new file mode 100644 index 0000000..57355e9 --- /dev/null +++ b/mcp/GUIDE.md @@ -0,0 +1,477 @@ +# u6u 開發指南 + +> u6u 是 **AI 優先(AI-First)** 的工作流自動化平台。 +> 跟 AI 描述你的意圖,u6u 幫你把它變成可重複執行、不需要 AI 的自動化工作流。 + +--- + +## 目錄 + +1. [核心概念:三元組(Triplet)](#核心概念三元組triplet) +2. [開發流程總覽](#開發流程總覽) +3. [建議的專案檔案結構](#建議的專案檔案結構) +4. [Workflow_Plan_YAML 格式](#workflow_plan_yaml-格式) +5. [Component_Plan_YAML 格式](#component_plan_yaml-格式) +6. [工作流(Workflow)部署流程](#工作流workflow部署流程) +7. [零件(Component)開發流程](#零件component開發流程) +8. [Tag 管理說明](#tag-管理說明) + +--- + +## 核心概念:三元組(Triplet) + +u6u 的一切都建立在「三元組」上。三元組是描述業務邏輯的最小單位,格式極度簡單,AI 不會出錯,人也能一眼看懂。 + +### 格式 + +``` +subject predicate object +``` + +| 部分 | 說明 | 範例 | +|------|------|------| +| `subject` | 執行者(誰) | `user`、`system`、`payment-service` | +| `predicate` | 動作(做什麼) | `submits`、`validates`、`sends` | +| `object` | 對象(對什麼) | `form`、`input`、`email` | + +### 命名規則 + +- 全部小寫,單字以連字號(`-`)連接 +- predicate 用動詞原形 +- 避免縮寫,語意要清楚 + +### 範例:匯率通知工作流 + +``` +system fetches exchange-rate +system parses rate-data +system sends telegram-notification +``` + +三個 triplet,三個動作,串起來就是一個完整的工作流。每個 triplet 對應一個**零件(component)**,零件負責實作那個動作的具體邏輯。 + +### 為什麼這麼簡單? + +因為 AI 擅長理解意圖,三元組擅長表達意圖。你跟 AI 說「去抓銀行匯率,用 Telegram 通知我」,AI 把它拆成三元組,u6u 查零件庫、組裝、執行。第一次需要 AI,之後自動跑,不再花 Token。 + +--- + +## 開發流程總覽 + +``` +你的意圖 + ↓ +AI 產出 Workflow_Plan_YAML(每次規劃新專案) + ↓ +u6u_search_components(查零件庫) + ↓ +有缺件?→ AI 產出 Component_Plan_YAML → u6u_publish_component + ↓ +u6u_execute_workflow(沙盒測試) + ↓ +u6u_deploy_workflow(正式部署) + ↓ +(選填)建立 tag,為工作流與零件分類 +``` + +**重要原則:** +- Workflow_Plan_YAML 和 Component_Plan_YAML 由 AI 輸出在對話中,**你自行存入本地 repo** +- MCP Server 不儲存 YAML 全文,只記錄部署成功後的 metadata(ID、名稱、時間) +- YAML 是你的原始碼,用 Git 管理 + +--- + +## 建議的專案檔案結構 + +``` +your-project/ +├── workflows/ # 工作流 YAML(Workflow_Plan_YAML) +│ ├── exchange-rate-notify.yaml +│ └── user-checkout-flow.yaml +│ +├── components/ # 零件 YAML(Component_Plan_YAML,只在有缺件時才有) +│ ├── system-fetches-exchange-rate.yaml +│ └── system-sends-telegram-notification.yaml +│ +├── .gitignore # 建議加入下方的 ignore 項目 +└── README.md +``` + +### 建議的 `.gitignore` + +```gitignore +# 環境變數(含 API Key,絕對不能 commit) +.env +.env.* +!.env.example + +# IDE 內部規劃檔案(非產品程式碼) +.kiro/ + +# 其他常見 +node_modules/ +dist/ +.DS_Store +``` + +--- + +## Workflow_Plan_YAML 格式 + +**產出時機:** 每次你向 AI 描述新的業務需求,AI 就會在對話中輸出此 YAML。將它存入 `workflows/` 目錄。 + +### 格式說明 + +```yaml +workflow: + name: <工作流名稱,kebab-case> + description: <業務目的說明> + version: "1.0.0" + tags: + - + + triplets: + - subject: <執行者> + predicate: <動作> + object: <對象> + description: <此步驟說明(選填)> + + context_schema: + : # 工作流執行時需要的輸入參數 +``` + +### 完整範例:匯率通知 + +```yaml +workflow: + name: exchange-rate-notify + description: 每日抓取銀行匯率,透過 Telegram 通知用戶 + version: "1.0.0" + tags: + - notification + - finance + + triplets: + - subject: system + predicate: fetches + object: exchange-rate + description: 從銀行 API 取得當日匯率 + - subject: system + predicate: parses + object: rate-data + description: 整理匯率資料格式 + - subject: system + predicate: sends + object: telegram-notification + description: 透過 Telegram Bot 發送通知 + + context_schema: + currency_pair: string # 例如 "USD/TWD" + chat_id: string # Telegram chat ID +``` + +### 完整範例:結帳流程 + +```yaml +workflow: + name: user-checkout-flow + description: 處理使用者結帳,從確認購物車到完成付款 + version: "1.0.0" + tags: + - ecommerce + - payment + + triplets: + - subject: user + predicate: confirms + object: cart-items + - subject: system + predicate: calculates + object: total-price + - subject: user + predicate: submits + object: payment-info + - subject: payment-service + predicate: processes + object: payment + - subject: system + predicate: creates + object: order-record + - subject: system + predicate: sends + object: confirmation-email + + context_schema: + user_id: string + cart_id: string + currency: string +``` + +--- + +## Component_Plan_YAML 格式 + +**產出時機:** 只有當 `u6u_search_components` 回報有缺件時,AI 才會產出此 YAML。不是每次都需要。 + +### 格式說明 + +```yaml +components: + - component_id: <零件唯一 ID,kebab-case> + name: <零件名稱> + triplet: " " + description: <零件功能說明,AI 用此進行語意匹配> + tags: + - + + # 選擇其中一種定義方式: + + # 方式一:API Config(直接呼叫外部 API) + api_config: + method: POST + url: https://api.example.com/endpoint + headers: + Content-Type: application/json + body_template: + key: "{{context.value}}" + + # 方式二:Gherkin(行為驅動開發規格,功能型零件使用) + gherkin: | + Feature: <功能名稱> + Scenario: <情境描述> + Given <前置條件> + When <觸發動作> + Then <預期結果> +``` + +### 完整範例 + +```yaml +components: + - component_id: system-fetches-exchange-rate + name: 系統抓取匯率 + triplet: "system fetches exchange-rate" + description: 呼叫銀行 API 取得指定貨幣對的當日匯率 + tags: + - finance + api_config: + method: GET + url: https://api.exchangerate.host/latest + headers: + Accept: application/json + body_template: + base: "{{context.currency_pair}}" + + - component_id: system-sends-telegram-notification + name: 系統發送 Telegram 通知 + triplet: "system sends telegram-notification" + description: 透過 Telegram Bot API 發送訊息給指定 chat + tags: + - notification + api_config: + method: POST + url: https://api.telegram.org/bot{{env.TELEGRAM_BOT_TOKEN}}/sendMessage + headers: + Content-Type: application/json + body_template: + chat_id: "{{context.chat_id}}" + text: "{{context.message}}" + + - component_id: payment-service-processes-payment + name: 付款服務處理交易 + triplet: "payment-service processes payment" + description: 呼叫付款閘道 API 處理信用卡交易 + tags: + - payment + - ecommerce + api_config: + method: POST + url: https://api.payment-gateway.com/v1/charges + headers: + Content-Type: application/json + Authorization: "Bearer {{env.PAYMENT_API_KEY}}" + body_template: + amount: "{{context.total_price}}" + currency: "{{context.currency}}" + card_token: "{{context.payment_token}}" + + - component_id: system-sends-confirmation-email + name: 系統寄送確認信 + triplet: "system sends confirmation-email" + description: 透過 Email 服務寄送訂單確認信給使用者 + tags: + - notification + - ecommerce + gherkin: | + Feature: 訂單確認信 + Scenario: 成功寄送確認信 + Given 訂單已建立,且 context 包含 user_email 與 order_id + When system sends confirmation-email + Then Email 服務收到寄信請求 + And 使用者收到包含 order_id 的確認信 + And 回傳 { success: true, message_id: "" } +``` + +--- + +## 工作流(Workflow)部署流程 + +### 步驟一:取得 Workflow_Plan_YAML + +向 AI 描述業務需求,AI 輸出 YAML。存入 `workflows/` 目錄。 + +### 步驟二:確認零件完整性 + +呼叫 `u6u_search_components`,傳入所有 triplet: + +```json +{ + "triplets": [ + "system fetches exchange-rate", + "system parses rate-data", + "system sends telegram-notification" + ] +} +``` + +回應會告知哪些零件已存在、哪些缺失。若有缺件,先完成[零件開發流程](#零件component開發流程)。 + +### 步驟三:沙盒測試 + +```json +// u6u_execute_workflow +{ + "triplets": [ + "system fetches exchange-rate", + "system parses rate-data", + "system sends telegram-notification" + ], + "context": { + "currency_pair": "USD/TWD", + "chat_id": "123456789" + } +} +``` + +### 步驟四:正式部署 + +```json +// u6u_deploy_workflow +{ + "yaml_content": "workflow:\n name: exchange-rate-notify\n ..." +} +``` + +部署成功後,系統回傳 `workflow_id`,並自動記錄 metadata 至 KBDB。 + +### 步驟五:加上 Tag(選填) + +```json +// u6u_tag_resource +{ + "resource_type": "workflow", + "resource_id": "wf-abc123", + "tag_name": "finance" +} +``` + +### 查詢已部署的工作流 + +``` +u6u_list_workflows → 列出所有工作流 +u6u_list_workflows(tag=finance) → 按 tag 篩選 +u6u_get_workflow(workflow_id) → 取得特定工作流 metadata +``` + +--- + +## 零件(Component)開發流程 + +### 步驟一:確認缺件 + +`u6u_search_components` 回報缺件後,AI 產出 Component_Plan_YAML。存入 `components/` 目錄。 + +### 步驟二:發佈零件 + +```json +// u6u_publish_component(API Config 方式) +{ + "component_id": "system-fetches-exchange-rate", + "api_config": { + "method": "GET", + "url": "https://api.exchangerate.host/latest" + } +} +``` + +```json +// u6u_publish_component(Gherkin 方式) +{ + "component_id": "system-sends-confirmation-email", + "gherkin": "Feature: 訂單確認信\n Scenario: ..." +} +``` + +### 步驟三:加上 Tag(選填) + +```json +// u6u_tag_resource +{ + "resource_type": "component", + "resource_id": "system-fetches-exchange-rate", + "tag_name": "finance" +} +``` + +### 查詢已發佈的零件 + +``` +u6u_list_components → 列出所有零件 +u6u_list_components(tag=payment) → 按 tag 篩選 +u6u_get_component(component_id) → 取得特定零件 metadata +``` + +--- + +## Tag 管理說明 + +Tag 是用戶自訂的標籤,可附加至工作流或零件,用於分類與篩選。 + +### Tag 操作 + +```json +// 建立 tag +// u6u_create_tag +{ "name": "finance", "description": "金融相關" } + +// 列出所有 tag +// u6u_list_tags(無需參數) +{} + +// 刪除 tag(不影響已打上此 tag 的資源關聯) +// u6u_delete_tag +{ "tag_name": "deprecated-tag" } + +// 為資源加上 tag +// u6u_tag_resource +{ + "resource_type": "workflow", // 或 "component" + "resource_id": "wf-abc123", + "tag_name": "finance" +} + +// 移除資源的 tag +// u6u_untag_resource +{ + "resource_type": "component", + "resource_id": "system-fetches-exchange-rate", + "tag_name": "beta" +} +``` + +### Tag 管理建議 + +- 專案開始前先規劃 tag 命名規則,保持一致性 +- 用有意義的名稱(`user-auth` 比 `auth` 好) +- 同一資源可附加多個 tag,靈活組合篩選 +- 定期清理不再使用的 tag diff --git a/mcp/README.md b/mcp/README.md new file mode 100644 index 0000000..00919d6 --- /dev/null +++ b/mcp/README.md @@ -0,0 +1,200 @@ +# Arcrun MCP Server + +> Arcrun 是 **AI 優先(AI-First)** 的工作流自動化平台。 +> 跟 AI 描述你的意圖,Arcrun 幫你把它變成可重複執行、不需要 AI 的自動化工作流。 + +Arcrun 是反過來的 n8n。n8n 從手寫程式開始,Arcrun 從 AI 描述開始——你說「去抓銀行匯率,用 Telegram 通知我」,AI 把它拆成三元組,Arcrun 查零件庫、組裝、執行。第一次需要 AI,之後自動跑,不再花 Token。 + +本 repo 是 Arcrun 的 **MCP Server**,讓 Claude Desktop、Cursor 等 AI client 能直接呼叫 Arcrun 的工作流與零件管理功能。 + +--- + +## 快速上手 + +### 取得 API Key + +API Key 是由邀請者提供,格式為 `pk_live_...`。 + +### 連線設定 + +#### Claude Desktop + +編輯 `~/Library/Application Support/Claude/claude_desktop_config.json`(macOS): + +```json +{ + "mcpServers": { + "arcrun": { + "type": "http", + "url": "https://mcp.finally.click/mcp", + "headers": { + "Authorization": "Bearer pk_live_YOUR_API_KEY" + } + } + } +} +``` + +#### Cursor + +在 Cursor 的 MCP 設定中新增: + +```json +{ + "arcrun": { + "type": "http", + "url": "https://mcp.finally.click/mcp", + "headers": { + "Authorization": "Bearer pk_live_YOUR_API_KEY" + } + } +} +``` + +> 使用 `type: http`(Streamable HTTP transport)。舊版 SSE 格式(`type: sse`)已不支援。 + +--- + +## MCP Tools 說明 + +### 零件開發(WASM) + +零件是 Arcrun 的最小執行單元,以 TinyGo 編譯為 `.wasm`,透過 stdin/stdout JSON 通訊。 + +| Tool | 說明 | +|------|------| +| `u6u_get_component_guide` | **開發新零件前必須先呼叫。** 取得 TinyGo 開發指引,包含白名單 import、禁止行為、contract YAML 範例、本地測試指令。 | +| `u6u_search_components` | 用自然語言語意搜尋零件庫。例如:「查詢 Google Sheets 資料」、「發送 LINE 訊息」。回傳零件清單含 canonical_id、描述、評分。 | +| `u6u_get_component` | 取得指定零件的完整合約(input_schema、output_schema、gherkin_tests、評分統計等)。 | +| `u6u_publish_component` | 提交 TinyGo WASM 零件。需提供 `contract`(合約物件)與 `wasm_base64`(編譯後的 .wasm base64)。Registry 自動執行沙盒驗收。 | + +### 工作流執行 + +| Tool | 說明 | +|------|------| +| `u6u_execute_workflow` | 在沙盒中執行工作流。輸入 `triplets`(三元組陣列)與 `context`,用於部署前驗證。 | +| `u6u_deploy_workflow` | 將工作流 YAML 部署至雲端引擎。輸入 `yaml_content`。 | + +### 工作流管理 + +| Tool | 說明 | +|------|------| +| `u6u_list_workflows` | 列出已部署的工作流。可傳入選填的 `tag` 參數篩選。 | +| `u6u_get_workflow` | 取得指定工作流的 metadata。輸入 `workflow_id`。 | + +### 零件管理 + +| Tool | 說明 | +|------|------| +| `u6u_list_components` | 列出已發佈的零件。可傳入選填的 `tag` 參數篩選。 | + +### Tag 管理 + +| Tool | 說明 | +|------|------| +| `u6u_create_tag` | 建立新 tag。輸入 `name`(必填)與 `description`(選填)。 | +| `u6u_list_tags` | 列出當前命名空間下所有 tag。 | +| `u6u_delete_tag` | 刪除指定 tag。輸入 `tag_name`。 | +| `u6u_tag_resource` | 為工作流或零件加上 tag。輸入 `resource_type`、`resource_id`、`tag_name`。 | +| `u6u_untag_resource` | 移除工作流或零件的 tag。 | + +--- + +## 零件開發流程(WASM) + +Arcrun 的零件是 TinyGo 編譯的 `.wasm`,透過 stdin/stdout JSON 通訊,可在 Cloudflare Workers(Tier 1/2)和 Wazero 邊緣環境(Tier 3)執行。 + +### 步驟一:取得開發指引 + +``` +u6u_get_component_guide +``` + +指引包含:TinyGo 白名單 import、禁止行為、`component.contract.yaml` 完整範例、本地測試指令。 + +### 步驟二:搜尋現有零件 + +``` +u6u_search_components("查詢 Google Sheets 資料") +``` + +若已有符合的零件,直接使用,不需要重新開發。 + +### 步驟三:開發零件(若缺件) + +依指引用 TinyGo 撰寫零件,只使用白名單 import: + +```go +import ( + "os" + "io" + "encoding/json" +) +``` + +編譯: + +```bash +tinygo build -o my_component.wasm -target=wasi . +``` + +本地測試: + +```bash +echo '{"input_field":"value"}' | wasmtime my_component.wasm +``` + +### 步驟四:提交零件 + +``` +u6u_publish_component( + contract={...}, // component.contract.yaml 內容 + wasm_base64="..." // base64(my_component.wasm) +) +``` + +Registry 自動執行沙盒驗收(體積、syscall 掃描、Gherkin 測試)。 + +--- + +## 工作流開發流程 + +### 步驟一:搜尋零件 + +``` +u6u_search_components("查詢匯率") +u6u_search_components("發送 Telegram 訊息") +``` + +### 步驟二:沙盒測試 + +``` +u6u_execute_workflow( + triplets=["system >> 查詢匯率 >> get-exchange-rate", ...], + context={"currency_pair": "USD/TWD"} +) +``` + +### 步驟三:部署 + +``` +u6u_deploy_workflow(yaml_content="...") +``` + +--- + +## Inspector 測試界面 + +開啟 [https://mcp.finally.click/inspector](https://mcp.finally.click/inspector) 即可在瀏覽器中互動式測試所有 MCP tools。 + +--- + +## 搭配 arcrun-gui 使用 + +[arcrun-gui](../arcrun-gui) 是 Arcrun 的人類操作介面,與 arcrun-mcp 共享同一個 KBDB 狀態: + +- AI 透過 arcrun-mcp 操作(搜尋零件、執行 Workflow) +- 人類透過 arcrun-gui 操作(拖拉畫布、查看零件庫) +- AI 的操作結果即時反映在 arcrun-gui 的畫布上 + +詳細開發指南請參閱 **[GUIDE.md](./GUIDE.md)**。 diff --git a/mcp/package.json b/mcp/package.json new file mode 100644 index 0000000..292fb53 --- /dev/null +++ b/mcp/package.json @@ -0,0 +1,25 @@ +{ + "name": "@inkstone/arcrun-mcp", + "version": "1.0.0", + "description": "u6u Remote MCP Server — 基於 Cloudflare Workers 的工作流管理工具", + "type": "module", + "scripts": { + "dev": "wrangler dev", + "deploy": "wrangler deploy", + "deploy:dry": "wrangler deploy --dry-run", + "test": "vitest" + }, + "dependencies": { + "@modelcontextprotocol/sdk": "^1.29.0", + "hono": "^4.0.0", + "yaml": "^2.9.0", + "zod": "^3.25.0" + }, + "devDependencies": { + "@cloudflare/workers-types": "^4.20241127.0", + "fast-check": "^4.6.0", + "typescript": "^5.0.0", + "vitest": "^2.0.0", + "wrangler": "^4.68.1" + } +} diff --git a/mcp/pnpm-lock.yaml b/mcp/pnpm-lock.yaml new file mode 100644 index 0000000..13d3fae --- /dev/null +++ b/mcp/pnpm-lock.yaml @@ -0,0 +1,2523 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@modelcontextprotocol/sdk': + specifier: ^1.29.0 + version: 1.29.0(zod@3.25.76) + hono: + specifier: ^4.0.0 + version: 4.12.10 + yaml: + specifier: ^2.9.0 + version: 2.9.0 + zod: + specifier: ^3.25.0 + version: 3.25.76 + devDependencies: + '@cloudflare/workers-types': + specifier: ^4.20241127.0 + version: 4.20260404.1 + fast-check: + specifier: ^4.6.0 + version: 4.6.0 + typescript: + specifier: ^5.0.0 + version: 5.9.3 + vitest: + specifier: ^2.0.0 + version: 2.1.9 + wrangler: + specifier: ^4.68.1 + version: 4.80.0(@cloudflare/workers-types@4.20260404.1) + +packages: + + '@cloudflare/kv-asset-handler@0.4.2': + resolution: {integrity: sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ==} + engines: {node: '>=18.0.0'} + + '@cloudflare/unenv-preset@2.16.0': + resolution: {integrity: sha512-8ovsRpwzPoEqPUzoErAYVv8l3FMZNeBVQfJTvtzP4AgLSRGZISRfuChFxHWUQd3n6cnrwkuTGxT+2cGo8EsyYg==} + peerDependencies: + unenv: 2.0.0-rc.24 + workerd: 1.20260301.1 || ~1.20260302.1 || ~1.20260303.1 || ~1.20260304.1 || >1.20260305.0 <2.0.0-0 + peerDependenciesMeta: + workerd: + optional: true + + '@cloudflare/workerd-darwin-64@1.20260401.1': + resolution: {integrity: sha512-ZSmceM70jH6k+/62VkEcmMNzrpr4kSctkX5Lsgqv38KktfhPY/hsh75y1lRoPWS3H3kgMa4p2pUSlidZR1u2hw==} + engines: {node: '>=16'} + cpu: [x64] + os: [darwin] + + '@cloudflare/workerd-darwin-arm64@1.20260401.1': + resolution: {integrity: sha512-7UKWF+IUZ3NXMVPsDg8Cjg0r58b+uYlfvs5Yt8bvtU+geCtW4P2MxRHmRSEo8SryckXOJjb/b8tcncgCykFu8g==} + engines: {node: '>=16'} + cpu: [arm64] + os: [darwin] + + '@cloudflare/workerd-linux-64@1.20260401.1': + resolution: {integrity: sha512-MDWUH/0bvL/l9aauN8zEddyYOXId1OueqrUCXXENNJ95R/lSmF6OgGVuXaYhoIhxQkNiEJ/0NOlnVYj9mJq4dw==} + engines: {node: '>=16'} + cpu: [x64] + os: [linux] + + '@cloudflare/workerd-linux-arm64@1.20260401.1': + resolution: {integrity: sha512-UgkzpMzVWM/bwbo3vjCTg2aoKfGcUhiEoQoDdo6RGWvbHRJyLVZ4VQCG9ZcISiztkiS2ICCoYOtPy6M/lV6Gcw==} + engines: {node: '>=16'} + cpu: [arm64] + os: [linux] + + '@cloudflare/workerd-windows-64@1.20260401.1': + resolution: {integrity: sha512-HBLzcQF5iF4Qv20tQ++pG7xs3OsCnaIbc+GAi6fmhUKZhvmzvml/jwrQzLJ+MPm0cQo41K5OO/U3T4S8tvJetQ==} + engines: {node: '>=16'} + cpu: [x64] + os: [win32] + + '@cloudflare/workers-types@4.20260404.1': + resolution: {integrity: sha512-jfZfktdn3D0ceA59i4lkMgPUR9p5Wd6trtNLQR1RTgF59iVt9/yegkiEZv0TQvJPXlmQOU1D0pAYz7cMztqErg==} + + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + + '@emnapi/runtime@1.9.2': + resolution: {integrity: sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==} + + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + + '@esbuild/aix-ppc64@0.27.3': + resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.27.3': + resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.27.3': + resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.27.3': + resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.27.3': + resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.3': + resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.27.3': + resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.3': + resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.27.3': + resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.27.3': + resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.27.3': + resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.27.3': + resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.27.3': + resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.27.3': + resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.3': + resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.27.3': + resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.27.3': + resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.27.3': + resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.3': + resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.27.3': + resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.3': + resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.27.3': + resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.27.3': + resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.27.3': + resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.27.3': + resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.27.3': + resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@hono/node-server@1.19.12': + resolution: {integrity: sha512-txsUW4SQ1iilgE0l9/e9VQWmELXifEFvmdA1j6WFh/aFPj99hIntrSsq/if0UWyGVkmrRPKA1wCeP+UCr1B9Uw==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + + '@modelcontextprotocol/sdk@1.29.0': + resolution: {integrity: sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==} + engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true + + '@poppinss/colors@4.1.6': + resolution: {integrity: sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==} + + '@poppinss/dumper@0.6.5': + resolution: {integrity: sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==} + + '@poppinss/exception@1.2.3': + resolution: {integrity: sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==} + + '@rollup/rollup-android-arm-eabi@4.60.1': + resolution: {integrity: sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.60.1': + resolution: {integrity: sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.60.1': + resolution: {integrity: sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.60.1': + resolution: {integrity: sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.60.1': + resolution: {integrity: sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.60.1': + resolution: {integrity: sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.60.1': + resolution: {integrity: sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm-musleabihf@4.60.1': + resolution: {integrity: sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-arm64-gnu@4.60.1': + resolution: {integrity: sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm64-musl@4.60.1': + resolution: {integrity: sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loong64-gnu@4.60.1': + resolution: {integrity: sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-loong64-musl@4.60.1': + resolution: {integrity: sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-ppc64-gnu@4.60.1': + resolution: {integrity: sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-ppc64-musl@4.60.1': + resolution: {integrity: sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==} + cpu: [ppc64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-riscv64-gnu@4.60.1': + resolution: {integrity: sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-musl@4.60.1': + resolution: {integrity: sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-s390x-gnu@4.60.1': + resolution: {integrity: sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-gnu@4.60.1': + resolution: {integrity: sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.60.1': + resolution: {integrity: sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-openbsd-x64@4.60.1': + resolution: {integrity: sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.60.1': + resolution: {integrity: sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.60.1': + resolution: {integrity: sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.60.1': + resolution: {integrity: sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.60.1': + resolution: {integrity: sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.60.1': + resolution: {integrity: sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ==} + cpu: [x64] + os: [win32] + + '@sindresorhus/is@7.2.0': + resolution: {integrity: sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==} + engines: {node: '>=18'} + + '@speed-highlight/core@1.2.15': + resolution: {integrity: sha512-BMq1K3DsElxDWawkX6eLg9+CKJrTVGCBAWVuHXVUV2u0s2711qiChLSId6ikYPfxhdYocLNt3wWwSvDiTvFabw==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@vitest/expect@2.1.9': + resolution: {integrity: sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==} + + '@vitest/mocker@2.1.9': + resolution: {integrity: sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@2.1.9': + resolution: {integrity: sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==} + + '@vitest/runner@2.1.9': + resolution: {integrity: sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==} + + '@vitest/snapshot@2.1.9': + resolution: {integrity: sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==} + + '@vitest/spy@2.1.9': + resolution: {integrity: sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==} + + '@vitest/utils@2.1.9': + resolution: {integrity: sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==} + + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv@8.18.0: + resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + blake3-wasm@2.1.5: + resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==} + + body-parser@2.2.2: + resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} + engines: {node: '>=18'} + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + chai@5.3.3: + resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} + engines: {node: '>=18'} + + check-error@2.1.3: + resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} + engines: {node: '>= 16'} + + content-disposition@1.0.1: + resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} + engines: {node: '>=18'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} + engines: {node: '>=18'} + + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} + engines: {node: '>= 0.10'} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + error-stack-parser-es@1.0.5: + resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + + esbuild@0.27.3: + resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} + engines: {node: '>=18'} + hasBin: true + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + eventsource-parser@3.0.6: + resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} + engines: {node: '>=18.0.0'} + + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} + + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + engines: {node: '>=12.0.0'} + + express-rate-limit@8.3.2: + resolution: {integrity: sha512-77VmFeJkO0/rvimEDuUC5H30oqUC4EyOhyGccfqoLebB0oiEYfM7nwPrsDsBL1gsTpwfzX8SFy2MT3TDyRq+bg==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + + fast-check@4.6.0: + resolution: {integrity: sha512-h7H6Dm0Fy+H4ciQYFxFjXnXkzR2kr9Fb22c0UBpHnm59K2zpr2t13aPTHlltFiNT6zuxp6HMPAVVvgur4BLdpA==} + engines: {node: '>=12.17.0'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + hono@4.12.10: + resolution: {integrity: sha512-mx/p18PLy5og9ufies2GOSUqep98Td9q4i/EF6X7yJgAiIopxqdfIO3jbqsi3jRgTgw88jMDEzVKi+V2EF+27w==} + engines: {node: '>=16.9.0'} + + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + + iconv-lite@0.7.2: + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + engines: {node: '>=0.10.0'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ip-address@10.1.0: + resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} + engines: {node: '>= 12'} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jose@6.2.2: + resolution: {integrity: sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-schema-typed@8.0.2: + resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} + + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + + loupe@3.2.1: + resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + + miniflare@4.20260401.0: + resolution: {integrity: sha512-lngHPzZFN9sxYG/mhzvnWiBMNVAN5MsO/7g32ttJ07rymtiK/ZBalODTKb8Od+BQdlU5DOR4CjVt9NydjnUyYg==} + engines: {node: '>=18.0.0'} + hasBin: true + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-to-regexp@6.3.0: + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + + path-to-regexp@8.4.2: + resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} + + pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + pathval@2.0.1: + resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} + engines: {node: '>= 14.16'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + + postcss@8.5.8: + resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} + engines: {node: ^10 || ^12 || >=14} + + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + + pure-rand@8.4.0: + resolution: {integrity: sha512-IoM8YF/jY0hiugFo/wOWqfmarlE6J0wc6fDK1PhftMk7MGhVZl88sZimmqBBFomLOCSmcCCpsfj7wXASCpvK9A==} + + qs@6.15.0: + resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==} + engines: {node: '>=0.6'} + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + rollup@4.60.1: + resolution: {integrity: sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + engines: {node: '>=10'} + hasBin: true + + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + + supports-color@10.2.2: + resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} + engines: {node: '>=18'} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinypool@1.1.1: + resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@1.2.0: + resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==} + engines: {node: '>=14.0.0'} + + tinyspy@3.0.2: + resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} + engines: {node: '>=14.0.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + undici@7.24.4: + resolution: {integrity: sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w==} + engines: {node: '>=20.18.1'} + + unenv@2.0.0-rc.24: + resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + vite-node@2.1.9: + resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + + vite@5.4.21: + resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + + vitest@2.1.9: + resolution: {integrity: sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': 2.1.9 + '@vitest/ui': 2.1.9 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + workerd@1.20260401.1: + resolution: {integrity: sha512-mUYCd+ohaWJWF5nhDzxugWaAD/DM8Dw0ze3B7bu8JaA7S70+XQJXcvcvwE8C4qGcxSdCyqjsrFzqxKubECDwzg==} + engines: {node: '>=16'} + hasBin: true + + wrangler@4.80.0: + resolution: {integrity: sha512-2ZKF7uPeOZy65BGk3YfvqBCPo/xH1MrAlMmH9mVP+tCNBrTUMnwOHSj1HrZHgR8LttkAqhko0fGz+I4ax1rzyQ==} + engines: {node: '>=20.3.0'} + hasBin: true + peerDependencies: + '@cloudflare/workers-types': ^4.20260401.1 + peerDependenciesMeta: + '@cloudflare/workers-types': + optional: true + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + yaml@2.9.0: + resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} + engines: {node: '>= 14.6'} + hasBin: true + + youch-core@0.3.3: + resolution: {integrity: sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==} + + youch@4.1.0-beta.10: + resolution: {integrity: sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==} + + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} + peerDependencies: + zod: ^3.25.28 || ^4 + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + +snapshots: + + '@cloudflare/kv-asset-handler@0.4.2': {} + + '@cloudflare/unenv-preset@2.16.0(unenv@2.0.0-rc.24)(workerd@1.20260401.1)': + dependencies: + unenv: 2.0.0-rc.24 + optionalDependencies: + workerd: 1.20260401.1 + + '@cloudflare/workerd-darwin-64@1.20260401.1': + optional: true + + '@cloudflare/workerd-darwin-arm64@1.20260401.1': + optional: true + + '@cloudflare/workerd-linux-64@1.20260401.1': + optional: true + + '@cloudflare/workerd-linux-arm64@1.20260401.1': + optional: true + + '@cloudflare/workerd-windows-64@1.20260401.1': + optional: true + + '@cloudflare/workers-types@4.20260404.1': {} + + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + + '@emnapi/runtime@1.9.2': + dependencies: + tslib: 2.8.1 + optional: true + + '@esbuild/aix-ppc64@0.21.5': + optional: true + + '@esbuild/aix-ppc64@0.27.3': + optional: true + + '@esbuild/android-arm64@0.21.5': + optional: true + + '@esbuild/android-arm64@0.27.3': + optional: true + + '@esbuild/android-arm@0.21.5': + optional: true + + '@esbuild/android-arm@0.27.3': + optional: true + + '@esbuild/android-x64@0.21.5': + optional: true + + '@esbuild/android-x64@0.27.3': + optional: true + + '@esbuild/darwin-arm64@0.21.5': + optional: true + + '@esbuild/darwin-arm64@0.27.3': + optional: true + + '@esbuild/darwin-x64@0.21.5': + optional: true + + '@esbuild/darwin-x64@0.27.3': + optional: true + + '@esbuild/freebsd-arm64@0.21.5': + optional: true + + '@esbuild/freebsd-arm64@0.27.3': + optional: true + + '@esbuild/freebsd-x64@0.21.5': + optional: true + + '@esbuild/freebsd-x64@0.27.3': + optional: true + + '@esbuild/linux-arm64@0.21.5': + optional: true + + '@esbuild/linux-arm64@0.27.3': + optional: true + + '@esbuild/linux-arm@0.21.5': + optional: true + + '@esbuild/linux-arm@0.27.3': + optional: true + + '@esbuild/linux-ia32@0.21.5': + optional: true + + '@esbuild/linux-ia32@0.27.3': + optional: true + + '@esbuild/linux-loong64@0.21.5': + optional: true + + '@esbuild/linux-loong64@0.27.3': + optional: true + + '@esbuild/linux-mips64el@0.21.5': + optional: true + + '@esbuild/linux-mips64el@0.27.3': + optional: true + + '@esbuild/linux-ppc64@0.21.5': + optional: true + + '@esbuild/linux-ppc64@0.27.3': + optional: true + + '@esbuild/linux-riscv64@0.21.5': + optional: true + + '@esbuild/linux-riscv64@0.27.3': + optional: true + + '@esbuild/linux-s390x@0.21.5': + optional: true + + '@esbuild/linux-s390x@0.27.3': + optional: true + + '@esbuild/linux-x64@0.21.5': + optional: true + + '@esbuild/linux-x64@0.27.3': + optional: true + + '@esbuild/netbsd-arm64@0.27.3': + optional: true + + '@esbuild/netbsd-x64@0.21.5': + optional: true + + '@esbuild/netbsd-x64@0.27.3': + optional: true + + '@esbuild/openbsd-arm64@0.27.3': + optional: true + + '@esbuild/openbsd-x64@0.21.5': + optional: true + + '@esbuild/openbsd-x64@0.27.3': + optional: true + + '@esbuild/openharmony-arm64@0.27.3': + optional: true + + '@esbuild/sunos-x64@0.21.5': + optional: true + + '@esbuild/sunos-x64@0.27.3': + optional: true + + '@esbuild/win32-arm64@0.21.5': + optional: true + + '@esbuild/win32-arm64@0.27.3': + optional: true + + '@esbuild/win32-ia32@0.21.5': + optional: true + + '@esbuild/win32-ia32@0.27.3': + optional: true + + '@esbuild/win32-x64@0.21.5': + optional: true + + '@esbuild/win32-x64@0.27.3': + optional: true + + '@hono/node-server@1.19.12(hono@4.12.10)': + dependencies: + hono: 4.12.10 + + '@img/colour@1.1.0': {} + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.9.2 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@modelcontextprotocol/sdk@1.29.0(zod@3.25.76)': + dependencies: + '@hono/node-server': 1.19.12(hono@4.12.10) + ajv: 8.18.0 + ajv-formats: 3.0.1(ajv@8.18.0) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.0.6 + express: 5.2.1 + express-rate-limit: 8.3.2(express@5.2.1) + hono: 4.12.10 + jose: 6.2.2 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 3.25.76 + zod-to-json-schema: 3.25.2(zod@3.25.76) + transitivePeerDependencies: + - supports-color + + '@poppinss/colors@4.1.6': + dependencies: + kleur: 4.1.5 + + '@poppinss/dumper@0.6.5': + dependencies: + '@poppinss/colors': 4.1.6 + '@sindresorhus/is': 7.2.0 + supports-color: 10.2.2 + + '@poppinss/exception@1.2.3': {} + + '@rollup/rollup-android-arm-eabi@4.60.1': + optional: true + + '@rollup/rollup-android-arm64@4.60.1': + optional: true + + '@rollup/rollup-darwin-arm64@4.60.1': + optional: true + + '@rollup/rollup-darwin-x64@4.60.1': + optional: true + + '@rollup/rollup-freebsd-arm64@4.60.1': + optional: true + + '@rollup/rollup-freebsd-x64@4.60.1': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.60.1': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.60.1': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.60.1': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.60.1': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.60.1': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.60.1': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.60.1': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.60.1': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.60.1': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.60.1': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.60.1': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.60.1': + optional: true + + '@rollup/rollup-linux-x64-musl@4.60.1': + optional: true + + '@rollup/rollup-openbsd-x64@4.60.1': + optional: true + + '@rollup/rollup-openharmony-arm64@4.60.1': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.60.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.60.1': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.60.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.60.1': + optional: true + + '@sindresorhus/is@7.2.0': {} + + '@speed-highlight/core@1.2.15': {} + + '@types/estree@1.0.8': {} + + '@vitest/expect@2.1.9': + dependencies: + '@vitest/spy': 2.1.9 + '@vitest/utils': 2.1.9 + chai: 5.3.3 + tinyrainbow: 1.2.0 + + '@vitest/mocker@2.1.9(vite@5.4.21)': + dependencies: + '@vitest/spy': 2.1.9 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 5.4.21 + + '@vitest/pretty-format@2.1.9': + dependencies: + tinyrainbow: 1.2.0 + + '@vitest/runner@2.1.9': + dependencies: + '@vitest/utils': 2.1.9 + pathe: 1.1.2 + + '@vitest/snapshot@2.1.9': + dependencies: + '@vitest/pretty-format': 2.1.9 + magic-string: 0.30.21 + pathe: 1.1.2 + + '@vitest/spy@2.1.9': + dependencies: + tinyspy: 3.0.2 + + '@vitest/utils@2.1.9': + dependencies: + '@vitest/pretty-format': 2.1.9 + loupe: 3.2.1 + tinyrainbow: 1.2.0 + + accepts@2.0.0: + dependencies: + mime-types: 3.0.2 + negotiator: 1.0.0 + + ajv-formats@3.0.1(ajv@8.18.0): + optionalDependencies: + ajv: 8.18.0 + + ajv@8.18.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + assertion-error@2.0.1: {} + + blake3-wasm@2.1.5: {} + + body-parser@2.2.2: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.3 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + on-finished: 2.4.1 + qs: 6.15.0 + raw-body: 3.0.2 + type-is: 2.0.1 + transitivePeerDependencies: + - supports-color + + bytes@3.1.2: {} + + cac@6.7.14: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + chai@5.3.3: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.3 + deep-eql: 5.0.2 + loupe: 3.2.1 + pathval: 2.0.1 + + check-error@2.1.3: {} + + content-disposition@1.0.1: {} + + content-type@1.0.5: {} + + cookie-signature@1.2.2: {} + + cookie@0.7.2: {} + + cookie@1.1.1: {} + + cors@2.8.6: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + deep-eql@5.0.2: {} + + depd@2.0.0: {} + + detect-libc@2.1.2: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + ee-first@1.1.1: {} + + encodeurl@2.0.0: {} + + error-stack-parser-es@1.0.5: {} + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-module-lexer@1.7.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + esbuild@0.21.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + + esbuild@0.27.3: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.3 + '@esbuild/android-arm': 0.27.3 + '@esbuild/android-arm64': 0.27.3 + '@esbuild/android-x64': 0.27.3 + '@esbuild/darwin-arm64': 0.27.3 + '@esbuild/darwin-x64': 0.27.3 + '@esbuild/freebsd-arm64': 0.27.3 + '@esbuild/freebsd-x64': 0.27.3 + '@esbuild/linux-arm': 0.27.3 + '@esbuild/linux-arm64': 0.27.3 + '@esbuild/linux-ia32': 0.27.3 + '@esbuild/linux-loong64': 0.27.3 + '@esbuild/linux-mips64el': 0.27.3 + '@esbuild/linux-ppc64': 0.27.3 + '@esbuild/linux-riscv64': 0.27.3 + '@esbuild/linux-s390x': 0.27.3 + '@esbuild/linux-x64': 0.27.3 + '@esbuild/netbsd-arm64': 0.27.3 + '@esbuild/netbsd-x64': 0.27.3 + '@esbuild/openbsd-arm64': 0.27.3 + '@esbuild/openbsd-x64': 0.27.3 + '@esbuild/openharmony-arm64': 0.27.3 + '@esbuild/sunos-x64': 0.27.3 + '@esbuild/win32-arm64': 0.27.3 + '@esbuild/win32-ia32': 0.27.3 + '@esbuild/win32-x64': 0.27.3 + + escape-html@1.0.3: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + + etag@1.8.1: {} + + eventsource-parser@3.0.6: {} + + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.0.6 + + expect-type@1.3.0: {} + + express-rate-limit@8.3.2(express@5.2.1): + dependencies: + express: 5.2.1 + ip-address: 10.1.0 + + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.2 + content-disposition: 1.0.1 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.2 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.15.0 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 + statuses: 2.0.2 + type-is: 2.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + fast-check@4.6.0: + dependencies: + pure-rand: 8.4.0 + + fast-deep-equal@3.1.3: {} + + fast-uri@3.1.0: {} + + finalhandler@2.1.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + forwarded@0.2.0: {} + + fresh@2.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + gopd@1.2.0: {} + + has-symbols@1.1.0: {} + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + hono@4.12.10: {} + + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + + iconv-lite@0.7.2: + dependencies: + safer-buffer: 2.1.2 + + inherits@2.0.4: {} + + ip-address@10.1.0: {} + + ipaddr.js@1.9.1: {} + + is-promise@4.0.0: {} + + isexe@2.0.0: {} + + jose@6.2.2: {} + + json-schema-traverse@1.0.0: {} + + json-schema-typed@8.0.2: {} + + kleur@4.1.5: {} + + loupe@3.2.1: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + math-intrinsics@1.1.0: {} + + media-typer@1.1.0: {} + + merge-descriptors@2.0.0: {} + + mime-db@1.54.0: {} + + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + + miniflare@4.20260401.0: + dependencies: + '@cspotcode/source-map-support': 0.8.1 + sharp: 0.34.5 + undici: 7.24.4 + workerd: 1.20260401.1 + ws: 8.18.0 + youch: 4.1.0-beta.10 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + ms@2.1.3: {} + + nanoid@3.3.11: {} + + negotiator@1.0.0: {} + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + parseurl@1.3.3: {} + + path-key@3.1.1: {} + + path-to-regexp@6.3.0: {} + + path-to-regexp@8.4.2: {} + + pathe@1.1.2: {} + + pathe@2.0.3: {} + + pathval@2.0.1: {} + + picocolors@1.1.1: {} + + pkce-challenge@5.0.1: {} + + postcss@8.5.8: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + + pure-rand@8.4.0: {} + + qs@6.15.0: + dependencies: + side-channel: 1.1.0 + + range-parser@1.2.1: {} + + raw-body@3.0.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + unpipe: 1.0.0 + + require-from-string@2.0.2: {} + + rollup@4.60.1: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.60.1 + '@rollup/rollup-android-arm64': 4.60.1 + '@rollup/rollup-darwin-arm64': 4.60.1 + '@rollup/rollup-darwin-x64': 4.60.1 + '@rollup/rollup-freebsd-arm64': 4.60.1 + '@rollup/rollup-freebsd-x64': 4.60.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.60.1 + '@rollup/rollup-linux-arm-musleabihf': 4.60.1 + '@rollup/rollup-linux-arm64-gnu': 4.60.1 + '@rollup/rollup-linux-arm64-musl': 4.60.1 + '@rollup/rollup-linux-loong64-gnu': 4.60.1 + '@rollup/rollup-linux-loong64-musl': 4.60.1 + '@rollup/rollup-linux-ppc64-gnu': 4.60.1 + '@rollup/rollup-linux-ppc64-musl': 4.60.1 + '@rollup/rollup-linux-riscv64-gnu': 4.60.1 + '@rollup/rollup-linux-riscv64-musl': 4.60.1 + '@rollup/rollup-linux-s390x-gnu': 4.60.1 + '@rollup/rollup-linux-x64-gnu': 4.60.1 + '@rollup/rollup-linux-x64-musl': 4.60.1 + '@rollup/rollup-openbsd-x64': 4.60.1 + '@rollup/rollup-openharmony-arm64': 4.60.1 + '@rollup/rollup-win32-arm64-msvc': 4.60.1 + '@rollup/rollup-win32-ia32-msvc': 4.60.1 + '@rollup/rollup-win32-x64-gnu': 4.60.1 + '@rollup/rollup-win32-x64-msvc': 4.60.1 + fsevents: 2.3.3 + + router@2.2.0: + dependencies: + debug: 4.4.3 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.4.2 + transitivePeerDependencies: + - supports-color + + safer-buffer@2.1.2: {} + + semver@7.7.4: {} + + send@1.2.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.1 + mime-types: 3.0.2 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + serve-static@2.2.1: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.1 + transitivePeerDependencies: + - supports-color + + setprototypeof@1.2.0: {} + + sharp@0.34.5: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.7.4 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + siginfo@2.0.0: {} + + source-map-js@1.2.1: {} + + stackback@0.0.2: {} + + statuses@2.0.2: {} + + std-env@3.10.0: {} + + supports-color@10.2.2: {} + + tinybench@2.9.0: {} + + tinyexec@0.3.2: {} + + tinypool@1.1.1: {} + + tinyrainbow@1.2.0: {} + + tinyspy@3.0.2: {} + + toidentifier@1.0.1: {} + + tslib@2.8.1: + optional: true + + type-is@2.0.1: + dependencies: + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.2 + + typescript@5.9.3: {} + + undici@7.24.4: {} + + unenv@2.0.0-rc.24: + dependencies: + pathe: 2.0.3 + + unpipe@1.0.0: {} + + vary@1.1.2: {} + + vite-node@2.1.9: + dependencies: + cac: 6.7.14 + debug: 4.4.3 + es-module-lexer: 1.7.0 + pathe: 1.1.2 + vite: 5.4.21 + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + vite@5.4.21: + dependencies: + esbuild: 0.21.5 + postcss: 8.5.8 + rollup: 4.60.1 + optionalDependencies: + fsevents: 2.3.3 + + vitest@2.1.9: + dependencies: + '@vitest/expect': 2.1.9 + '@vitest/mocker': 2.1.9(vite@5.4.21) + '@vitest/pretty-format': 2.1.9 + '@vitest/runner': 2.1.9 + '@vitest/snapshot': 2.1.9 + '@vitest/spy': 2.1.9 + '@vitest/utils': 2.1.9 + chai: 5.3.3 + debug: 4.4.3 + expect-type: 1.3.0 + magic-string: 0.30.21 + pathe: 1.1.2 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinypool: 1.1.1 + tinyrainbow: 1.2.0 + vite: 5.4.21 + vite-node: 2.1.9 + why-is-node-running: 2.3.0 + transitivePeerDependencies: + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + workerd@1.20260401.1: + optionalDependencies: + '@cloudflare/workerd-darwin-64': 1.20260401.1 + '@cloudflare/workerd-darwin-arm64': 1.20260401.1 + '@cloudflare/workerd-linux-64': 1.20260401.1 + '@cloudflare/workerd-linux-arm64': 1.20260401.1 + '@cloudflare/workerd-windows-64': 1.20260401.1 + + wrangler@4.80.0(@cloudflare/workers-types@4.20260404.1): + dependencies: + '@cloudflare/kv-asset-handler': 0.4.2 + '@cloudflare/unenv-preset': 2.16.0(unenv@2.0.0-rc.24)(workerd@1.20260401.1) + blake3-wasm: 2.1.5 + esbuild: 0.27.3 + miniflare: 4.20260401.0 + path-to-regexp: 6.3.0 + unenv: 2.0.0-rc.24 + workerd: 1.20260401.1 + optionalDependencies: + '@cloudflare/workers-types': 4.20260404.1 + fsevents: 2.3.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + wrappy@1.0.2: {} + + ws@8.18.0: {} + + yaml@2.9.0: {} + + youch-core@0.3.3: + dependencies: + '@poppinss/exception': 1.2.3 + error-stack-parser-es: 1.0.5 + + youch@4.1.0-beta.10: + dependencies: + '@poppinss/colors': 4.1.6 + '@poppinss/dumper': 0.6.5 + '@speed-highlight/core': 1.2.15 + cookie: 1.1.1 + youch-core: 0.3.3 + + zod-to-json-schema@3.25.2(zod@3.25.76): + dependencies: + zod: 3.25.76 + + zod@3.25.76: {} diff --git a/mcp/src/component.schema.json b/mcp/src/component.schema.json new file mode 100644 index 0000000..a797a52 --- /dev/null +++ b/mcp/src/component.schema.json @@ -0,0 +1,10 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "u6u Component Definition", + "type": "object", + "required": ["component_id", "gherkin"], + "properties": { + "component_id": { "type": "string" }, + "gherkin": { "type": "string" } + } +} \ No newline at end of file diff --git a/mcp/src/index.ts b/mcp/src/index.ts new file mode 100644 index 0000000..8c4af58 --- /dev/null +++ b/mcp/src/index.ts @@ -0,0 +1,242 @@ +import { Hono } from "hono"; +import { cors } from "hono/cors"; +import { Env } from "./types.js"; +import { partnerAuthMiddleware } from "./middleware/partner-auth.js"; +import { handleMcpRequest } from "./mcp-handler.js"; +import { inspectorHtml } from "./pages/inspector.js"; +import { kbdbFetch } from "./lib/kbdb-client.js"; + +const _app = new Hono<{ Bindings: Env; Variables: { org_namespace: string; partner_token: string } }>(); +const app = _app.basePath('/mcp'); + +app.use("*", cors({ + origin: "*", + allowMethods: ["GET", "POST", "OPTIONS"], + allowHeaders: ["Content-Type", "Authorization"], + exposeHeaders: ["Content-Type"], + maxAge: 600, +})); + +app.get("/", (c) => c.text("u6u MCP Server is running.")); + +app.get("/inspector", (c) => { + return c.html(inspectorHtml); +}); + +// ── GUI 認證端點 ─────────────────────────────────────────────────────────────── + +// GET /auth/verify — GUI 登入驗證,重用 partnerAuthMiddleware +app.get("/auth/verify", partnerAuthMiddleware, (c) => { + const orgNamespace = c.get("org_namespace"); + return c.json({ valid: true, org_namespace: orgNamespace }); +}); + +// ── GUI REST 端點(與 MCP tools 平行) ──────────────────────────────────────── + +// GET /workflows — 列出 Workflow 清單(GUI 用) +app.get("/workflows", partnerAuthMiddleware, async (c) => { + const orgNamespace = c.get("org_namespace"); + try { + const resp = await kbdbFetch( + c.env, + `/records/search?template=workflow_metadata&user_id=${encodeURIComponent(orgNamespace)}` + ); + if (!resp.ok) return c.json({ workflows: [] }); + const data = await resp.json<{ records: Array<{ id: string; slots?: Record }> }>(); + const workflows = (data.records ?? []).map(r => ({ + id: r.id, + name: (r.slots?.display_name as string | undefined) ?? (r.slots?.name as string | undefined) ?? r.id, + last_run: r.slots?.last_run as string | undefined, + status: r.slots?.status as string | undefined, + slots: r.slots, + })); + return c.json({ workflows }); + } catch { + return c.json({ workflows: [] }); + } +}); + +// GET /workflows/:id — 取得單一 Workflow(GUI poll 用) +app.get("/workflows/:id", partnerAuthMiddleware, async (c) => { + const id = c.req.param("id") ?? ''; + try { + if (!id) return c.json({ error: "Missing id" }, 400); + const resp = await kbdbFetch(c.env, `/records/${encodeURIComponent(id)}`); + if (!resp.ok) return c.json({ error: "Not found" }, 404); + const data = await resp.json<{ id: string; slots?: Record }>(); + return c.json({ + id: data.id, + name: (data.slots?.display_name as string | undefined) ?? data.id, + slots: data.slots, + }); + } catch { + return c.json({ error: "Internal error" }, 500); + } +}); + +// POST /action-log — GUI 寫入用戶動作記錄 +app.post("/action-log", partnerAuthMiddleware, async (c) => { + const orgNamespace = c.get("org_namespace"); + try { + const body = await c.req.json<{ + action_type: string; + payload?: Record; + occurred_at?: string; + }>(); + const occurred_at = body.occurred_at ?? new Date().toISOString(); + + await kbdbFetch(c.env, "/records", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + template_id: "tpl-action-log", + user_id: orgNamespace, + slots: { + org_namespace: orgNamespace, + action_type: body.action_type, + payload: JSON.stringify(body.payload ?? {}), + occurred_at, + }, + }), + }); + return c.json({ ok: true }); + } catch { + return c.json({ ok: false }, 500); + } +}); + +// ── Prototype Pages REST 端點 ───────────────────────────────────────────────── + +// GET /prototype-pages — 列出 Prototype Pages +app.get("/prototype-pages", partnerAuthMiddleware, async (c) => { + const orgNamespace = c.get("org_namespace"); + try { + const resp = await kbdbFetch( + c.env, + `/records/search?template=tpl-page-block&user_id=${encodeURIComponent(orgNamespace)}` + ); + if (!resp.ok) return c.json({ pages: [] }); + const data = await resp.json<{ records: Array<{ id: string; slots?: Record }> }>(); + const pages = (data.records ?? []).map(r => ({ + id: r.id, + page_name: (r.slots?.page_name as string | undefined) ?? 'Untitled', + components_json: (r.slots?.components_json as string | undefined) ?? '[]', + last_edited_by: (r.slots?.last_edited_by as string | undefined) ?? 'gui', + last_edited_at: (r.slots?.last_edited_at as string | undefined) ?? '', + status: (r.slots?.status as string | undefined) ?? 'draft', + })); + return c.json({ pages }); + } catch { + return c.json({ pages: [] }); + } +}); + +// POST /prototype-pages — 建立新 Prototype Page +app.post("/prototype-pages", partnerAuthMiddleware, async (c) => { + const orgNamespace = c.get("org_namespace"); + try { + const body = await c.req.json<{ page_name?: string }>(); + const page_name = body.page_name ?? 'Untitled'; + const now = new Date().toISOString(); + + const resp = await kbdbFetch(c.env, "/records", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + template_id: "tpl-page-block", + user_id: orgNamespace, + slots: { + page_name, + org_namespace: orgNamespace, + components_json: '[]', + last_edited_by: 'gui', + last_edited_at: now, + status: 'draft', + }, + }), + }); + if (!resp.ok) return c.json({ error: "Failed to create" }, 500); + const data = await resp.json<{ id: string; slots?: Record }>(); + return c.json({ + id: data.id, + page_name, + components_json: '[]', + last_edited_by: 'gui', + last_edited_at: now, + status: 'draft', + }, 201); + } catch { + return c.json({ error: "Internal error" }, 500); + } +}); + +// GET /prototype-pages/:id — 取得單一 Prototype Page +app.get("/prototype-pages/:id", partnerAuthMiddleware, async (c) => { + const id = c.req.param("id") ?? ''; + try { + if (!id) return c.json({ error: "Missing id" }, 400); + const resp = await kbdbFetch(c.env, `/records/${encodeURIComponent(id)}`); + if (!resp.ok) return c.json({ error: "Not found" }, 404); + const data = await resp.json<{ id: string; slots?: Record }>(); + return c.json({ + id: data.id, + page_name: (data.slots?.page_name as string | undefined) ?? 'Untitled', + components_json: (data.slots?.components_json as string | undefined) ?? '[]', + last_edited_by: (data.slots?.last_edited_by as string | undefined) ?? 'gui', + last_edited_at: (data.slots?.last_edited_at as string | undefined) ?? '', + status: (data.slots?.status as string | undefined) ?? 'draft', + }); + } catch { + return c.json({ error: "Internal error" }, 500); + } +}); + +// PUT /prototype-pages/:id — 儲存 Prototype Page +app.put("/prototype-pages/:id", partnerAuthMiddleware, async (c) => { + const id = c.req.param("id") ?? ''; + try { + if (!id) return c.json({ error: "Missing id" }, 400); + const body = await c.req.json<{ + components_json?: string; + page_name?: string; + }>(); + const now = new Date().toISOString(); + const slots: Record = { + last_edited_by: 'gui', + last_edited_at: now, + }; + if (body.components_json !== undefined) slots.components_json = body.components_json; + if (body.page_name !== undefined) slots.page_name = body.page_name; + + const resp = await kbdbFetch(c.env, `/records/${encodeURIComponent(id)}`, { + method: "PUT", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ slots }), + }); + if (!resp.ok) return c.json({ error: "Failed to save" }, 500); + return c.json({ ok: true }); + } catch { + return c.json({ error: "Internal error" }, 500); + } +}); + +// ── MCP 端點 ────────────────────────────────────────────────────────────────── + +app.options("/mcp", (c) => { + return new Response(null, { + status: 204, + headers: { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Methods": "POST, OPTIONS", + "Access-Control-Allow-Headers": "Content-Type, Authorization", + }, + }); +}); + +app.post("/mcp", partnerAuthMiddleware, async (c) => { + const orgNamespace = c.get("org_namespace"); + const partnerToken = c.get("partner_token"); + return handleMcpRequest(c.req.raw, c.env, orgNamespace, partnerToken); +}); + +export default app; diff --git a/mcp/src/lib/cypher-client.ts b/mcp/src/lib/cypher-client.ts new file mode 100644 index 0000000..158575a --- /dev/null +++ b/mcp/src/lib/cypher-client.ts @@ -0,0 +1,101 @@ +/** + * Cypher-executor service binding wrapper — LI SDD M2.2 + * + * 對應 .agents/specs/llm-interface/ Milestone 2.2。 + * 統一 arcrun-mcp 對 cypher-executor 的呼叫,預設 fetch 樣板 + auth header 注入。 + * + * arcrun 平台「ak_」級 api_key 跟 MCP 「pk_live」級 token 是兩層 auth: + * - pk_live (partner-auth middleware) → org_namespace(MCP 自己用) + * - ak_xxx (X-Arcrun-API-Key) → cypher-executor workflow 操作 + * + * 此 client 統一處理 ak_xxx 注入 + error contract 化(給 AI 看的 next_actions)。 + */ + +import type { Env } from "../types.js"; + +export interface CypherCallOpts { + apiKey: string; + method?: string; + body?: unknown; + query?: Record; +} + +export async function cypherFetch( + env: Env, + path: string, + opts: CypherCallOpts, +): Promise { + if (!env.CYPHER_EXECUTOR) { + throw new Error("CYPHER_EXECUTOR service binding not configured"); + } + + const url = new URL(`http://cypher-executor${path}`); + if (opts.query) { + for (const [k, v] of Object.entries(opts.query)) { + url.searchParams.set(k, String(v)); + } + } + + return env.CYPHER_EXECUTOR.fetch(url.toString(), { + method: opts.method ?? "GET", + headers: { + "Content-Type": "application/json", + "X-Arcrun-API-Key": opts.apiKey, + }, + body: opts.body ? JSON.stringify(opts.body) : undefined, + }); +} + +/** + * 統一 error response 格式化(LI SDD §1.3) + * + * 用法: + * const res = await cypherFetch(...); + * if (!res.ok) return errorResponse('not_found', `...`, [...], await res.text()); + */ +export function errorResponse( + error_code: string, + human_message: string, + next_actions: string[], + detail?: string, +): { + content: { type: "text"; text: string }[]; + isError: true; +} { + return { + content: [ + { + type: "text", + text: JSON.stringify( + { ok: false, error_code, human_message, next_actions, detail }, + null, + 2, + ), + }, + ], + isError: true, + }; +} + +/** + * 成功 response 格式化 + */ +export function successResponse( + data: unknown, + hints?: string[], +): { + content: { type: "text"; text: string }[]; +} { + return { + content: [ + { + type: "text", + text: JSON.stringify( + { ok: true, data, ...(hints ? { hints } : {}) }, + null, + 2, + ), + }, + ], + }; +} diff --git a/mcp/src/lib/kbdb-client.ts b/mcp/src/lib/kbdb-client.ts new file mode 100644 index 0000000..14bbf12 --- /dev/null +++ b/mcp/src/lib/kbdb-client.ts @@ -0,0 +1,13 @@ +import { Env } from "../types.js"; + +/** + * Wrapper around env.KBDB.fetch that automatically injects + * the KBDB_INTERNAL_TOKEN Authorization header. + */ +export function kbdbFetch(env: Env, path: string, init?: RequestInit): Promise { + const headers = new Headers((init?.headers as HeadersInit) || {}); + if (env.KBDB_INTERNAL_TOKEN) { + headers.set("Authorization", `Bearer ${env.KBDB_INTERNAL_TOKEN}`); + } + return env.KBDB.fetch(`http://kbdb${path}`, { ...init, headers }); +} diff --git a/mcp/src/mcp-handler.ts b/mcp/src/mcp-handler.ts new file mode 100644 index 0000000..c5f17fa --- /dev/null +++ b/mcp/src/mcp-handler.ts @@ -0,0 +1,19 @@ +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js"; +import { registerAllTools } from "./tools/registry.js"; +import { Env } from "./types.js"; + +export async function handleMcpRequest( + request: Request, + env: Env, + orgNamespace: string, + partnerToken: string, +): Promise { + const transport = new WebStandardStreamableHTTPServerTransport({ sessionIdGenerator: undefined }); + const server = new McpServer({ name: "u6u-mcp-server", version: "1.0.0" }); + + registerAllTools(server, env, orgNamespace, partnerToken); + await server.connect(transport); + + return transport.handleRequest(request); +} diff --git a/mcp/src/middleware/partner-auth.ts b/mcp/src/middleware/partner-auth.ts new file mode 100644 index 0000000..19a8bcd --- /dev/null +++ b/mcp/src/middleware/partner-auth.ts @@ -0,0 +1,35 @@ +import { Context, Next } from "hono"; +import { Env } from "../types.js"; + +export async function partnerAuthMiddleware( + c: Context<{ Bindings: Env; Variables: { org_namespace: string; partner_token: string } }>, + next: Next +) { + const authHeader = c.req.header('Authorization'); + if (!authHeader?.startsWith('Bearer ')) { + return c.json({ error: 'Missing or invalid Authorization header' }, 401); + } + + const token = authHeader.slice(7); + const resp = await c.env.KBDB.fetch( + `http://kbdb/partners/${encodeURIComponent(token)}/info`, + { + headers: { + 'Authorization': `Bearer ${c.env.KBDB_INTERNAL_TOKEN}` + } + } + ); + + if (!resp.ok) { + return c.json({ error: 'Invalid or expired partner key' }, 401); + } + + const info = await resp.json<{ valid: boolean; org_namespace: string }>(); + if (!info.valid) { + return c.json({ error: 'Invalid or expired partner key' }, 401); + } + + c.set('org_namespace', info.org_namespace); + c.set('partner_token', token); // 給下游(cypher-executor / KBDB)轉發用 + await next(); +} diff --git a/mcp/src/pages/inspector.html b/mcp/src/pages/inspector.html new file mode 100644 index 0000000..8278a68 --- /dev/null +++ b/mcp/src/pages/inspector.html @@ -0,0 +1,674 @@ + + + + + + u6u MCP Server 測試界面 + + + + +
+ +
+ +
+ +
+
+ +
+ + +
+
+
+
+
🔧
+

從左側選擇一個工具

+
+
+ +
+
+ Response + +
+
尚未發送請求
+
+
+
+
+ + + + diff --git a/mcp/src/pages/inspector.ts b/mcp/src/pages/inspector.ts new file mode 100644 index 0000000..8f98b97 --- /dev/null +++ b/mcp/src/pages/inspector.ts @@ -0,0 +1,661 @@ +// Auto-generated: exports inspector.html content as a string for Cloudflare Workers +// Source of truth is inspector.html — keep in sync manually or via build step + +export const inspectorHtml = ` + + + + + u6u MCP Server 測試界面 + + + + +
+ +
+ +
+ +
+
+ +
+ + +
+
+
+
+
🔧
+

從左側選擇一個工具

+
+
+ +
+
+ Response + +
+
尚未發送請求
+
+
+
+
+ +