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

9.2 KiB
Raw Blame History

Contributing to arcrun

感謝你考慮貢獻 arcrun!本文件說明如何新增零件(WASM component)並提交至公眾零件庫。

arcrun 的零件主要由 AI 撰寫。你不需要是 TinyGo 或 AssemblyScript 專家,只需要把這份文件和你的 API 文件或需求貼給 AI,讓它生成源碼,你負責編譯、測試、提交。


選擇開發語言

零件只需要輸出符合 WASI preview1.wasm 檔案,與使用哪個語言無關。

語言 輸出大小 AI 撰寫品質 說明
TinyGo 極小(1080KB 優秀 官方零件使用;語法簡單,AI 出錯率低
AssemblyScript 小(20150KB 良好 TypeScript 語法,前端開發者最快上手
Rust 小–中(30300KB 良好 效能最強;適合複雜演算法,工具鏈稍複雜

AI 開發建議:

  • TinyGoGo 語法與 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

所有語言共用相同的合約格式:

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: "我的零件功能說明。"

整合類零件額外加入:

credentials_required:
  - key: my_api_token
    type: api_key
    description: "My Service API token"
    inject_as: api_token

TinyGo 零件開發

環境安裝

# 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 範本

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))
}

編譯

cd registry/components/my_component
tinygo build -o my_component.wasm -target wasi .

本機測試

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 零件開發

環境安裝

# 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 範本

// 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):

{
  "dependencies": {
    "as-wasi": "^0.4.7",
    "assemblyscript-json": "^1.1.0"
  }
}

編譯

cd registry/components/my_component
npm install
npx asc assembly/index.ts \
  --target release \
  --outFile my_component.wasm \
  --exportRuntime \
  --use abort=~lib/wasi_abort

本機測試

echo '{"text":"hello world"}' | wasmtime run my_component.wasm
# 預期:{"success":true,"result":"[transformed] hello world"}

Rust 零件開發

Rust 零件支援已就緒,但文件尚在完善中。如果你熟悉 Rust + WASM,歡迎參考 wasm-wasi 官方文件,核心要求與其他語言相同:WASI preview1stdin/stdout JSON I/O。

基本設定:

rustup target add wasm32-wasip1
cargo build --target wasm32-wasip1 --release

提交至公眾 Registry

# 確保 .wasm 已編譯
ls my_component.wasm

# 提交(需要 arcrun.dev API Key
acr parts publish ./registry/components/my_component/

提交後流程:

狀態 說明
sandbox_pending 沙盒驗收執行中
author_only 驗收通過,你自己可用
public 人工審核通過,所有人可用,開始累積統計

查詢審核進度:

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

問題回報

開 Issuegithub.com/richblack/arcrun/issues