# Skill: Add New WASM Component

## 何時用這個 skill

`arcrun_list_components()` 沒有你需要的零件。要寫一個新的 TinyGo / AssemblyScript WASM。

**重要**：寫零件 = **改 arcrun 平台本身**，不是改 user workflow。
這 skill 預設你有 arcrun repo write access。沒有 → 告訴用戶「需要 X 零件，請聯絡平台維護者」，停手。

## 7 步流程

### 1. 確認真的需要新零件

先想：能不能用 `http_request` 加組合搞定？
- 多數第三方 API → `http_request` 已夠（搭配 `auth_recipe` 處理 auth）
- 簡單轉換 → 用 logic primitives（`set` / `filter` / `array_ops`）
- 複雜流程編排 → cypher binding 多步而非單一大零件

真的需要新零件的場景：
- 跟 cypher-executor host functions 互動（KV、加解密、簽 JWT）
- 邏輯太複雜不適合多節點分解
- 為效能（一次 worker call 取代 10 次 fetch）

### 2. 讀規範

- `matrix/arcrun/.claude/rules/03-component-architecture.md` — 部署慣例
- `matrix/arcrun/.claude/rules/01-tech-stack.md` — TinyGo 限制
- 既有相似零件範例：`matrix/arcrun/registry/components/{name}/main.go`

### 3. 開新目錄

```
matrix/arcrun/registry/components/{your_component}/
├── main.go                    TinyGo source
├── component.contract.yaml    input/output schema + 描述
└── (build 後產出 .wasm)
```

合約格式（contract.yaml）：
```yaml
canonical_id: your_component
display_name: 中文顯示名
category: data | auth | api | logic
version: 0.1.0
description: |
  做什麼用、限制、注意事項。AI 看這份決定要不要用你的零件
input_schema:
  type: object
  required: [foo, bar]
  properties:
    foo: { type: string, description: "..." }
    bar: { type: number, description: "..." }
output_schema:
  type: object
  properties:
    result: { type: string }
    success: { type: boolean }
gherkin_tests:
  - given: "input foo=hello"
    when: "component runs"
    then: "result contains hello"
```

### 4. 寫 main.go

```go
package main

import (
    "encoding/json"
    "io"
    "os"
)

type Input struct {
    Foo string `json:"foo"`
    Bar int    `json:"bar"`
}

type Output struct {
    Result  string `json:"result"`
    Success bool   `json:"success"`
}

func main() {
    bytes, _ := io.ReadAll(os.Stdin)
    var in Input
    json.Unmarshal(bytes, &in)

    // 你的邏輯
    result := in.Foo + ":" + string(rune(in.Bar))

    out := Output{Result: result, Success: true}
    json.NewEncoder(os.Stdout).Encode(out)
}
```

限制：
- 只 import：`os`、`io`、`encoding/json`、`encoding/base64`、`strings`、`time` 等 stdlib
- **禁用**：`net/http`（用 host function `u6u.http_request`）、`crypto/rsa`（用 host function）
- 全部 logic 在 main()，stdin/stdout JSON I/O

### 5. 本地 build + 測

```bash
cd registry/components/your_component
tinygo build -target=wasi -o your_component.wasm main.go
echo '{"foo":"hello","bar":42}' | wasmtime your_component.wasm
```

### 6. 部署成獨立 Worker

```
.component-builds/your_component/
├── wrangler.toml      name = "arcrun-your-component"
├── package.json
├── component.wasm     從上面 build 複製過來
└── src/index.ts       固定 WASI shim（複製 component-worker-template）
```

`wrangler.toml`：
```toml
name = "arcrun-your-component"
main = "src/index.ts"
compatibility_date = "2025-02-19"
workers_dev = true   # 必須 true，cypher-executor 走 workers.dev 對內 URL
[[routes]]
pattern = "your-component.arcrun.dev/*"
zone_name = "arcrun.dev"
```

push → CI 自動部署。

### 7. 註冊到 cypher-executor 白名單

⚠️ **目前的架構債**（M2 計畫修）：每加零件要手動加 `cypher-executor/src/lib/component-loader.ts`：

```ts
const WASM_HTTP_RUNNER_IDS: ReadonlySet<string> = new Set([
  // ... 既有
  'your_component',  // ← 加這行
]);
```

不加 → workflow 用你的零件會噴「找不到零件」。

未來會改成 registry KV 動態查（`cypher-executor-dynamic-component-discovery` SDD 待開）。

## 驗證上線

```
arcrun_list_components() → 應該看到 your_component
arcrun_get_component_contract(canonical_id='your_component') → 看 schema
```

寫個 test workflow 用你的零件，跑通就完成。
