Files
Arcrun/CONTRIBUTING.md
T
Leo c4351e4b7f docs: multi-language component guide — TinyGo, AssemblyScript, Rust
README: add language comparison table in contributing section, explain AI writing
quality differences and why TinyGo is recommended for official components.

CONTRIBUTING: full rewrite with separate TinyGo + AssemblyScript sections,
each with AI prompt templates, code templates, build commands, and test commands.
Rust documented as supported with basic setup reference.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 13:53:55 +08:00

370 lines
9.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Contributing to arcrun
感謝你考慮貢獻 arcrun!本文件說明如何新增零件(WASM component)並提交至公眾零件庫。
arcrun 的零件**主要由 AI 撰寫**。你不需要是 TinyGo 或 AssemblyScript 專家,只需要把這份文件和你的 API 文件或需求貼給 AI,讓它生成源碼,你負責編譯、測試、提交。
---
## 選擇開發語言
零件只需要輸出符合 **WASI preview1**`.wasm` 檔案,與使用哪個語言無關。
| 語言 | 輸出大小 | AI 撰寫品質 | 說明 |
|------|---------|------------|------|
| **TinyGo** | 極小(10–80KB) | 優秀 | 官方零件使用;語法簡單,AI 出錯率低 |
| **AssemblyScript** | 小(20150KB | 良好 | TypeScript 語法,前端開發者最快上手 |
| **Rust** | 小–中(30–300KB) | 良好 | 效能最強;適合複雜演算法,工具鏈稍複雜 |
**AI 開發建議:**
-**TinyGo**Go 語法與 TypeScript 差異夠大,AI 不易把 TS 邏輯直接搬過來造成錯誤,是最穩的選擇。
-**AssemblyScript**:適合已熟悉 TypeScript 的開發者,但要注意 AS 不是 TS — 提示 AI 時明確說「AssemblyScript,不是 TypeScript」。
-**Rust**:效能要求高時使用;需要更詳細的提示和更仔細的審查。
---
## 零件規格:共通規則
無論使用哪個語言,零件必須遵守:
- **I/O 模型**:從 `stdin` 讀取 JSON,往 `stdout` 輸出 JSON,不使用 return value
- **回傳格式**:成功 `{"success":true,"result":...}`,失敗 `{"success":false,"error":"..."}`
- **不 panic**:任何錯誤都應輸出 `success:false` JSON,不讓執行器收到空輸出
- **不使用網路 / 檔案系統**(功能類零件):`no_network_syscall: true`
- **允許網路**(整合類零件):`no_network_syscall: false`,必須宣告 `credentials_required`
---
## 目錄結構
```
registry/components/my_component/
├── component.contract.yaml # 零件規格宣告(必填)
├── main.go # TinyGo 源碼(TinyGo 零件)
├── assembly/index.ts # AssemblyScript 源碼(AS 零件)
├── src/lib.rs # Rust 源碼(Rust 零件)
└── my_component.wasm # 編譯產出(不提交至 git,CI 自動產生)
```
---
## component.contract.yaml
所有語言共用相同的合約格式:
```yaml
canonical_id: "my_component" # 小寫底線,全庫唯一
display_name: "我的零件"
category: "data" # api / logic / data / ai / style / anim / ui
version: "v1"
author: "@your-github-username"
wasi_target: "preview1"
stability: "floating" # floating / stable / pinned
runtime_compat:
- "cf-workers"
- "workerd"
- "wazero"
constraints:
max_size_kb: 2048
max_cold_start_ms: 50
no_network_syscall: true # 功能類 true,整合類 false
io_model: "stdin_stdout_json"
input_schema:
type: object
required: [text]
properties:
text:
type: string
description: 輸入文字
output_schema:
type: object
properties:
result:
type: string
gherkin_tests:
- scenario: "基本轉換"
given: '{"text":"hello"}'
then_contains: '"result"'
- scenario: "缺少必填欄位"
given: '{}'
then_contains: '"success":false'
config_example: |
transform:
text: "{{input.text}}"
description: "我的零件功能說明。"
```
整合類零件額外加入:
```yaml
credentials_required:
- key: my_api_token
type: api_key
description: "My Service API token"
inject_as: api_token
```
---
## TinyGo 零件開發
### 環境安裝
```bash
# TinyGo
brew install tinygo # macOS
# 其他平台:https://tinygo.org/getting-started/
# 本機測試執行器
brew install wasmtime # macOS
```
### 給 AI 的提示範本
```
請幫我用 TinyGo 寫一個 arcrun WASM 零件。
需求:[你的需求]
規則:
- 從 stdin 讀取 JSON,往 stdout 輸出 JSON
- 成功回傳 {"success":true,"result":...}
- 失敗回傳 {"success":false,"error":"..."},不 panic
- 不使用網路、不使用檔案系統(純功能類零件)
- import 只用標準庫(encoding/json, os, fmt, strings 等)
請生成 main.go 和 component.contract.yaml。
```
### main.go 範本
```go
package main
import (
"encoding/json"
"fmt"
"os"
)
type Input struct {
Text string `json:"text"`
}
type Output struct {
Success bool `json:"success"`
Result string `json:"result,omitempty"`
Error string `json:"error,omitempty"`
}
func main() {
var input Input
if err := json.NewDecoder(os.Stdin).Decode(&input); err != nil {
writeError("invalid input: " + err.Error())
return
}
if input.Text == "" {
writeError("text is required")
return
}
// 你的邏輯
result := "[transformed] " + input.Text
out, _ := json.Marshal(Output{Success: true, Result: result})
fmt.Println(string(out))
}
func writeError(msg string) {
out, _ := json.Marshal(Output{Success: false, Error: msg})
fmt.Println(string(out))
}
```
### 編譯
```bash
cd registry/components/my_component
tinygo build -o my_component.wasm -target wasi .
```
### 本機測試
```bash
echo '{"text":"hello world"}' | wasmtime run my_component.wasm
# 預期:{"success":true,"result":"[transformed] hello world"}
echo '{}' | wasmtime run my_component.wasm
# 預期:{"success":false,"error":"text is required"}
```
---
## AssemblyScript 零件開發
### 環境安裝
```bash
# Node.js >= 18
node --version
# 初始化 AS 專案
npm init -y
npm install --save-dev assemblyscript
npx asinit .
# 本機測試執行器
brew install wasmtime # macOS
```
### 給 AI 的提示範本
```
請幫我用 AssemblyScript(不是 TypeScript)寫一個 arcrun WASM 零件。
需求:[你的需求]
規則:
- AssemblyScript 是 TypeScript 的子集,編譯為 WASM,不能使用 DOM / Node.js API
- 從 stdin 讀取 JSON(使用 WASI fd_read),往 stdout 輸出 JSON(使用 Console.log
- 成功回傳 {"success":true,"result":...}
- 失敗回傳 {"success":false,"error":"..."}
- 不使用網路、不使用檔案系統
請生成 assembly/index.ts 和 component.contract.yaml。
注意:AssemblyScript 沒有 JSON.parse,需要手動解析或使用 as-json 套件。
```
### assembly/index.ts 範本
```typescript
// AssemblyScript — 注意:這不是 Node.js / TypeScript
// 沒有 DOM、沒有 fetch、沒有 require
import { Console } from "as-wasi/assembly";
import { JSON } from "assemblyscript-json/assembly";
export function _start(): void {
// 從 stdin 讀取輸入
const input = Console.readAll();
// 解析 JSON
const parsed = JSON.parse(input);
if (!parsed.isObj) {
Console.log('{"success":false,"error":"invalid input"}');
return;
}
const obj = parsed as JSON.Obj;
const textVal = obj.getString("text");
if (textVal == null) {
Console.log('{"success":false,"error":"text is required"}');
return;
}
const text = textVal.valueOf();
// 你的邏輯
const result = "[transformed] " + text;
Console.log('{"success":true,"result":"' + result + '"}');
}
```
**專案依賴(package.json):**
```json
{
"dependencies": {
"as-wasi": "^0.4.7",
"assemblyscript-json": "^1.1.0"
}
}
```
### 編譯
```bash
cd registry/components/my_component
npm install
npx asc assembly/index.ts \
--target release \
--outFile my_component.wasm \
--exportRuntime \
--use abort=~lib/wasi_abort
```
### 本機測試
```bash
echo '{"text":"hello world"}' | wasmtime run my_component.wasm
# 預期:{"success":true,"result":"[transformed] hello world"}
```
---
## Rust 零件開發
Rust 零件支援已就緒,但文件尚在完善中。如果你熟悉 Rust + WASM,歡迎參考 [wasm-wasi 官方文件](https://doc.rust-lang.org/stable/reference/linkage.html),核心要求與其他語言相同:WASI preview1stdin/stdout JSON I/O。
基本設定:
```bash
rustup target add wasm32-wasip1
cargo build --target wasm32-wasip1 --release
```
---
## 提交至公眾 Registry
```bash
# 確保 .wasm 已編譯
ls my_component.wasm
# 提交(需要 arcrun.dev API Key
acr parts publish ./registry/components/my_component/
```
提交後流程:
| 狀態 | 說明 |
|------|------|
| `sandbox_pending` | 沙盒驗收執行中 |
| `author_only` | 驗收通過,你自己可用 |
| `public` | 人工審核通過,所有人可用,開始累積統計 |
查詢審核進度:
```bash
acr parts publish --status <submission_id>
```
---
## 常見問題
### `no_network_syscall` 設定錯誤
- **功能類**category: logic / data / ai):`no_network_syscall: true`。這類零件應完全沙盒化。
- **整合類**category: api):`no_network_syscall: false`,因為要呼叫外部 API。
兩者都需要宣告在 `constraints` 下,設錯會在 syscall 掃描步驟被沙盒拒絕。
### `gherkin_tests` 必須包含 happy path 和 error path
至少兩個測試場景:一個輸入正確的 happy path、一個缺少必填欄位或輸入非法的 error path。
### 體積超過上限
- TinyGo:確認使用 `-target wasi`(而非 `-target wasm`),前者體積更小
- AssemblyScript:加上 `--optimize``--target release`
- Rust:使用 `--release` 並加入 `opt-level = "z"``Cargo.toml`
---
## 問題回報
開 Issue[github.com/richblack/arcrun/issues](https://github.com/richblack/arcrun/issues)