arcrun — AI workflow execution engine (clean history)

Self-hosted 開源:WASM 零件 + recipe + cypher-executor,跑在你自己的 Cloudflare。

此為重建的乾淨歷史起點(移除曾誤 commit 的 GCP SA 金鑰,舊歷史保留在
richblack/arcrun 與本地 backup 分支)。含:
- acr init --self-hosted installer(建 KV/R2 + codeload 拉預編譯 wasm + wrangler deploy + seed recipe)
- recipe push 把關(資料外流提醒 + 打通檢查)
- 19 個正當零件預編譯 wasm(claude_api/km_writer/kbdb_upsert_block 排除:違反 DECISIONS §1)
- CLI / cypher-executor / registry / 完整 SDD

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
uncle6me-web
2026-06-03 15:52:38 +08:00
commit 922a57fe34
485 changed files with 89356 additions and 0 deletions
+116
View File
@@ -0,0 +1,116 @@
// Component Registry Worker 型別定義
import { z } from 'zod';
// ── Cloudflare Bindings ──────────────────────────────────────────────────────
export type Bindings = {
AI: Ai;
// KV key 格式:
// comp:{hash_id}:{version} → 零件元數據(hash_id = cmp_ + sha256 前 8 碼)
// idx:{canonical_id} → canonical_id → hash_id 反查索引
SUBMISSIONS_KV: KVNamespace;
ANALYTICS_KV: KVNamespace; // 執行統計匯總(key = stats:{hash_id}:{version}
ENVIRONMENT: string;
};
// ── Component Contract SchemaZod)─────────────────────────────────────────
// max_cold_start_ms 上限放寬至 500(從 50):實測 auth/ai 類零件含 crypto/init 步驟通常 100-300ms
// no_network_syscall / no_filesystem_syscall 都改 optionalauth/api 類零件需要網路 syscall
export const ConstraintsSchema = z.object({
max_size_kb: z.number().positive().max(8192),
max_cold_start_ms: z.number().positive().max(500),
no_network_syscall: z.boolean().optional(),
no_filesystem_syscall: z.boolean().optional(),
io_model: z.literal('stdin_stdout_json'),
});
export const GherkinTestSchema = z.object({
scenario: z.string().min(1),
given: z.string().min(1),
then_contains: z.string().min(1),
});
export const ComponentContractSchema = z.object({
// canonical_id:提交者填寫的可讀名稱(小寫底線),用於搜尋與 workflow 引用
// component_hash_id:由 Registry 在提交時派發,格式 cmp_{8碼hex}workflow 引用此 id 才能保證永久不壞
// 兩者都可以在 workflow 中引用,Registry 會互相解析
canonical_id: z.string().min(1).regex(/^[a-z][a-z0-9_]*$/, 'canonical_id 必須為小寫底線格式'),
display_name: z.string().min(1),
// category 擴充:auth (auth primitive)、ai (Claude/AI 推論)、platform (平台底層 crypto/system)
category: z.enum(['logic', 'api', 'ui', 'style', 'anim', 'data', 'auth', 'ai', 'platform']),
version: z.string().min(1).regex(/^v\d+$/, 'version 格式必須為 vN'),
wasi_target: z.literal('preview1'),
stability: z.enum(['floating', 'stable', 'pinned']),
runtime_compat: z.array(z.enum(['cf-workers', 'workerd', 'wazero'])).min(1),
constraints: ConstraintsSchema,
input_schema: z.record(z.unknown()),
output_schema: z.record(z.unknown()),
gherkin_tests: z.array(GherkinTestSchema).min(2, '至少需要一個 happy path 和一個 error path'),
// 選填欄位
component_type: z.enum(['wasm', 'service_binding']).optional(),
max_size_kb: z.number().optional(),
max_cold_start_ms: z.number().optional(),
no_network_syscall: z.boolean().optional(),
service_binding_key: z.string().optional(),
description: z.string().optional(),
// aliases:搜尋同義詞,不作為識別符使用
// 從 registry/aliases.yaml 的 scope 同義詞表自動合併,也可在 contract 內手動補充
// 未來接入 KBDB 後,canonical_id 將獲得系統派發的唯一 hash id
aliases: z.array(z.string()).optional(),
tags: z.array(z.string()).optional(),
});
export type ComponentContract = z.infer<typeof ComponentContractSchema>;
// ── 沙盒驗收步驟 ─────────────────────────────────────────────────────────────
export type SandboxStep = 'fake_component_scan' | 'size_check' | 'cold_start' | 'syscall_scan' | 'gherkin_tests' | 'runtime_compat';
export interface SandboxResult {
success: boolean;
failed_step?: SandboxStep;
reason?: string;
guide_anchor?: string;
// 未真正驗證的步驟(mock,禁假綠 §3c/§7)。success 仍可能為 true,但這些步驟沒實際跑。
unimplemented_steps?: SandboxStep[];
// 驗收通過後回傳兩個 id
component_hash_id: string; // cmp_{8碼hex}workflow 引用用,永久不變
canonical_id: string; // 可讀名稱,搜尋用
version: string;
}
// ── KBDB Block 格式 ──────────────────────────────────────────────────────────
export interface KbdbBlock {
block_id: string;
template_id: string;
user_id?: string;
page_name?: string;
}
export interface KbdbSlots {
[key: string]: string;
}
// ── 禁止的 WASM syscall(網路 + 檔案系統)────────────────────────────────────
export const FORBIDDEN_SYSCALLS = [
'sock_connect',
'sock_accept',
'sock_recv',
'sock_send',
'sock_shutdown',
'fd_open',
'path_open',
'path_create_directory',
'path_remove_directory',
'path_rename',
'path_unlink_file',
'path_filestat_get',
'path_filestat_set_times',
'path_link',
'path_readlink',
'path_symlink',
] as const;