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
+147
View File
@@ -0,0 +1,147 @@
// POST /components — 零件提交端點(沙盒驗收流程)
// POST /components/index-only — metadata-only 索引(無 wasm、無沙盒,給 backfill 用)
// Requirements: 2.1, 2.2, 2.3
// SDD: matrix/arcrun/.agents/specs/component-registry-canon/design.md
import { Hono } from 'hono';
import type { Bindings } from '../types';
import { validateContract } from '../actions/validateContract';
import { submitComponent } from '../actions/submitComponent';
import type { SubmitOptions } from '../actions/submitComponent';
import { indexOnlyComponent } from '../actions/indexOnlyComponent';
const app = new Hono<{ Bindings: Bindings }>();
app.post('/', async c => {
// 接受 multipart/form-datacontractJSON 字串)+ wasmbinary
let contract: unknown;
let wasmBytes: Uint8Array;
// G0/G4:人類確認 + 舉證 + 本地 Gherkin evidencemultipart 或 JSON 皆可帶)
const submitOptions: SubmitOptions = {};
const contentType = c.req.header('content-type') ?? '';
if (contentType.includes('multipart/form-data')) {
const formData = await c.req.formData();
const contractStr = formData.get('contract');
const wasmFile = formData.get('wasm');
if (!contractStr || typeof contractStr !== 'string') {
return c.json({ success: false, error: '缺少 contract 欄位' }, 400);
}
if (!wasmFile || !(wasmFile instanceof File)) {
return c.json({ success: false, error: '缺少 wasm 欄位' }, 400);
}
try {
contract = JSON.parse(contractStr);
} catch {
return c.json({ success: false, error: 'contract 必須為合法 JSON' }, 400);
}
wasmBytes = new Uint8Array(await wasmFile.arrayBuffer());
const hc = formData.get('human_confirmation');
if (typeof hc === 'string') { try { submitOptions.human_confirmation = JSON.parse(hc); } catch { /* ignore */ } }
const ge = formData.get('gherkin_evidence');
if (typeof ge === 'string') { try { submitOptions.gherkin_evidence = JSON.parse(ge); } catch { /* ignore */ } }
if (formData.get('skip_acceptance') === 'true') submitOptions.skip_acceptance = true;
} else {
// 也支援純 JSON(用於測試,wasm 以 base64 傳入)
let body: Record<string, unknown>;
try {
body = await c.req.json();
} catch {
return c.json({ success: false, error: 'request body 必須為 multipart/form-data 或 JSON' }, 400);
}
contract = body.contract;
const wasmBase64 = body.wasm_base64;
if (!contract) {
return c.json({ success: false, error: '缺少 contract 欄位' }, 400);
}
if (!wasmBase64 || typeof wasmBase64 !== 'string') {
return c.json({ success: false, error: '缺少 wasm_base64 欄位' }, 400);
}
// base64 decode
const binaryStr = atob(wasmBase64);
wasmBytes = new Uint8Array(binaryStr.length);
for (let i = 0; i < binaryStr.length; i++) {
wasmBytes[i] = binaryStr.charCodeAt(i);
}
if (body.human_confirmation) submitOptions.human_confirmation = body.human_confirmation as SubmitOptions['human_confirmation'];
if (body.gherkin_evidence) submitOptions.gherkin_evidence = body.gherkin_evidence as SubmitOptions['gherkin_evidence'];
if (body.skip_acceptance === true) submitOptions.skip_acceptance = true;
}
// 驗證 contract 格式
const validation = validateContract(contract);
if (!validation.valid) {
return c.json({
success: false,
failed_step: 'contract_validation',
reason: `合約格式驗證失敗:${validation.errors.join(', ')}`,
missing_fields: validation.missing_fields,
guide_anchor: '#contract-example',
}, 422);
}
// 執行沙盒驗收(含 G0 人類閘門)+ 寫入 metadata
const result = await submitComponent(wasmBytes, validation.contract!, c.env, submitOptions);
if (!result.success) {
return c.json(result, 422);
}
return c.json(result, 201);
});
// POST /components/index-only — metadata-only 索引(給 backfill 用)
// 只接 contractJSON),不收 wasm bytes、不沙盒驗收
// 用途:cypher-executor 已不從 R2 動態載 wasm(零件用獨立 Worker URL),
// 故已部署但未索引的零件,只要把 metadata 寫進 KV 讓 search 找得到即可。
app.post('/index-only', async c => {
let body: Record<string, unknown>;
try {
body = await c.req.json();
} catch {
return c.json({ success: false, error: 'request body 必須為 JSON' }, 400);
}
const contract = body.contract;
if (!contract) {
return c.json({ success: false, error: '缺少 contract 欄位' }, 400);
}
// index-only 是 backfill 用,比 submit 寬鬆:
// 既有零件可能沒 gherkin_tests / 沒 description / aliases — 補預設讓索引能進
if (typeof contract === 'object' && contract !== null) {
const c2 = contract as Record<string, unknown>;
if (!c2.gherkin_tests || (Array.isArray(c2.gherkin_tests) && c2.gherkin_tests.length < 2)) {
c2.gherkin_tests = [
{ scenario: 'placeholder happy', given: '{}', then_contains: '{' },
{ scenario: 'placeholder fail', given: '{}', then_contains: '}' },
];
}
if (!c2.description) c2.description = '';
if (!c2.tags) c2.tags = [];
}
const validation = validateContract(contract);
if (!validation.valid) {
return c.json({
success: false,
failed_step: 'contract_validation',
reason: `合約格式驗證失敗:${validation.errors.join(', ')}`,
missing_fields: validation.missing_fields,
}, 422);
}
const result = await indexOnlyComponent(validation.contract!, c.env);
return c.json(result, result.already_indexed ? 200 : 201);
});
export default app;
+15
View File
@@ -0,0 +1,15 @@
// GET /components/guide
// Requirements: 11.1, 11.2, 11.3
import { Hono } from 'hono';
import type { Bindings } from '../types';
import { getGuide } from '../actions/getGuide';
const app = new Hono<{ Bindings: Bindings }>();
app.get('/', c => {
const markdown = getGuide();
return c.text(markdown, 200, { 'Content-Type': 'text/markdown; charset=utf-8' });
});
export default app;
+20
View File
@@ -0,0 +1,20 @@
// POST /init — 確保 tpl-component template 存在(冪等)
// Requirements: 12.1
import { Hono } from 'hono';
import type { Bindings } from '../types';
import { ensureTemplate } from '../actions/ensureTemplate';
const app = new Hono<{ Bindings: Bindings }>();
app.post('/', async c => {
try {
const result = await ensureTemplate(c.env);
return c.json({ success: true, ...result });
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
return c.json({ success: false, error: message }, 500);
}
});
export default app;
+43
View File
@@ -0,0 +1,43 @@
// GET /components/:id — 取得零件最優版本合約
// GET /components/:id/versions — 取得所有版本清單(含評分)
// GET /components/search?q=... — 語意搜尋零件
// Requirements: 12.2, 12.3
import { Hono } from 'hono';
import type { Bindings } from '../types';
import { getComponent, getComponentVersions, searchComponents } from '../actions/queryComponents';
const app = new Hono<{ Bindings: Bindings }>();
// 語意搜尋(必須在 /:id 之前,避免 "search" 被當作 id
app.get('/search', async c => {
const q = c.req.query('q');
if (!q || q.trim() === '') {
return c.json({ success: false, error: 'q 參數必填' }, 400);
}
const results = await searchComponents(q.trim(), c.env);
return c.json({ success: true, data: { results, count: results.length } });
});
// 取得所有版本
app.get('/:id/versions', async c => {
const id = c.req.param('id');
const versions = await getComponentVersions(id, c.env);
if (versions.length === 0) {
return c.json({ success: false, error: `零件 ${id} 不存在` }, 404);
}
return c.json({ success: true, data: { versions, count: versions.length } });
});
// 取得最優版本
app.get('/:id', async c => {
const id = c.req.param('id');
const component = await getComponent(id, c.env);
if (!component) {
return c.json({ success: false, error: `零件 ${id} 不存在` }, 404);
}
return c.json({ success: true, data: component });
});
export default app;
+31
View File
@@ -0,0 +1,31 @@
// POST /components/validate-contract
// Requirements: 1.1, 1.2, 11.5
import { Hono } from 'hono';
import type { Bindings } from '../types';
import { validateContract } from '../actions/validateContract';
const app = new Hono<{ Bindings: Bindings }>();
app.post('/', async c => {
let body: unknown;
try {
body = await c.req.json();
} catch {
return c.json({ valid: false, missing_fields: [], errors: ['request body 必須為合法 JSON'] }, 400);
}
const result = validateContract(body);
if (result.valid) {
return c.json({ valid: true, missing_fields: [], errors: [] }, 200);
}
return c.json({
valid: false,
missing_fields: result.missing_fields,
errors: result.errors,
}, 422);
});
export default app;