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
+79
View File
@@ -0,0 +1,79 @@
/**
* Credentials API — 多租戶 credential 管理
*
* POST /credentials
* Body: { name: string, encrypted: string, iv: string }
* Header: X-Arcrun-API-Key
* → 以 {api_key}:cred:{name} 為 KV key 存入 CREDENTIALS_KV
*
* DELETE /credentials/:name
* Header: X-Arcrun-API-Key
* → 刪除 {api_key}:cred:{name}
*
* GET /credentials
* Header: X-Arcrun-API-Key
* → 列出當前 api_key 下所有 credential 名稱(不含加密值)
*/
import { Hono } from 'hono';
import type { Bindings } from '../types';
export const credentialsRouter = new Hono<{ Bindings: Bindings }>();
// POST /credentials — 上傳加密 credential
credentialsRouter.post('/credentials', async (c) => {
const apiKey = c.req.header('X-Arcrun-API-Key');
if (!apiKey) {
return c.json({ error: '缺少 X-Arcrun-API-Key header' }, 401);
}
const body = await c.req.json().catch(() => null) as {
name?: string;
encrypted?: string;
iv?: string;
} | null;
if (!body?.name || !body.encrypted || !body.iv) {
return c.json({ error: '缺少必要欄位:name, encrypted, iv' }, 400);
}
const name = body.name.trim();
if (!/^\w+$/.test(name)) {
return c.json({ error: 'credential name 只能包含英文字母、數字和底線' }, 400);
}
const kvKey = `${apiKey}:cred:${name}`;
const record = JSON.stringify({ encrypted: body.encrypted, iv: body.iv });
await c.env.CREDENTIALS_KV.put(kvKey, record);
return c.json({ success: true, name });
});
// DELETE /credentials/:name — 刪除 credential
credentialsRouter.delete('/credentials/:name', async (c) => {
const apiKey = c.req.header('X-Arcrun-API-Key');
if (!apiKey) {
return c.json({ error: '缺少 X-Arcrun-API-Key header' }, 401);
}
const name = c.req.param('name');
const kvKey = `${apiKey}:cred:${name}`;
await c.env.CREDENTIALS_KV.delete(kvKey);
return c.json({ success: true, name });
});
// GET /credentials — 列出 credential 名稱(不含值)
credentialsRouter.get('/credentials', async (c) => {
const apiKey = c.req.header('X-Arcrun-API-Key');
if (!apiKey) {
return c.json({ error: '缺少 X-Arcrun-API-Key header' }, 401);
}
const prefix = `${apiKey}:cred:`;
const list = await c.env.CREDENTIALS_KV.list({ prefix });
const names = list.keys.map(k => k.name.slice(prefix.length));
return c.json({ credentials: names });
});