feat: 薄殼原則落地 + seed 下沉 API + MCP 進主庫 + 部署一致性

壓測四橫向問題修正(docs 壓測報告):

① 薄殼原則成鐵律:能力長在 API,CLI/MCP/lib 只暴露
   - seed 下沉成 API 行為:cypher-executor POST /init/seed(一次灌 API+auth recipe),
     種子資料移到 server src/lib/api-recipe-seeds.ts,CLI 改薄殼一次呼叫
   - 解除 deployFullyOk 連坐 + init 補 seed auth recipe + update 補 seed/全 KV
   - registry SUBMISSIONS_KV 補進 REQUIRED_KV_NAMESPACES(修 20/21)

② MCP 統一帳號來源(單一 remote MCP + .env 切 MCP URL)
   - MCP 從 sibling repo 搬進 arcrun/mcp/(remote Worker,route 改 mcp.arcrun.dev)
   - config 加 mcp_url 三層解析 + getMcpUrl + DEFAULT_MCP_URL
   - 新增 acr mcp-setup:依 config 寫專案 .mcp.json(接案切資料夾自動切 MCP)
   - acr --version 改動態讀 package.json(根治漂移)

③ Deploy 一致性
   - tests/release.feature + scripts/check-release.sh
   - local-deploy.sh:CLI npm publish + auto patch bump + CHANGELOG
   - local-deploy.sh bash 3.2 相容修正(mapfile / 空陣列 set -u)
   - builtins/pnpm-lock.yaml

④ README self-hosted 同步現況(移除 R2 殘留、加 flag/env、多帳號)

CLI bump → 1.3.0

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
uncle6me-web
2026-06-06 15:45:35 +08:00
parent 5f381a44a6
commit 3e65e22775
58 changed files with 8608 additions and 74 deletions
+101
View File
@@ -0,0 +1,101 @@
/**
* Cypher-executor service binding wrapper — LI SDD M2.2
*
* 對應 .agents/specs/llm-interface/ Milestone 2.2。
* 統一 arcrun-mcp 對 cypher-executor 的呼叫,預設 fetch 樣板 + auth header 注入。
*
* arcrun 平台「ak_」級 api_key 跟 MCP 「pk_live」級 token 是兩層 auth
* - pk_live (partner-auth middleware) → org_namespaceMCP 自己用)
* - ak_xxx (X-Arcrun-API-Key) → cypher-executor workflow 操作
*
* 此 client 統一處理 ak_xxx 注入 + error contract 化(給 AI 看的 next_actions)。
*/
import type { Env } from "../types.js";
export interface CypherCallOpts {
apiKey: string;
method?: string;
body?: unknown;
query?: Record<string, string | number>;
}
export async function cypherFetch(
env: Env,
path: string,
opts: CypherCallOpts,
): Promise<Response> {
if (!env.CYPHER_EXECUTOR) {
throw new Error("CYPHER_EXECUTOR service binding not configured");
}
const url = new URL(`http://cypher-executor${path}`);
if (opts.query) {
for (const [k, v] of Object.entries(opts.query)) {
url.searchParams.set(k, String(v));
}
}
return env.CYPHER_EXECUTOR.fetch(url.toString(), {
method: opts.method ?? "GET",
headers: {
"Content-Type": "application/json",
"X-Arcrun-API-Key": opts.apiKey,
},
body: opts.body ? JSON.stringify(opts.body) : undefined,
});
}
/**
* 統一 error response 格式化(LI SDD §1.3
*
* 用法:
* const res = await cypherFetch(...);
* if (!res.ok) return errorResponse('not_found', `...`, [...], await res.text());
*/
export function errorResponse(
error_code: string,
human_message: string,
next_actions: string[],
detail?: string,
): {
content: { type: "text"; text: string }[];
isError: true;
} {
return {
content: [
{
type: "text",
text: JSON.stringify(
{ ok: false, error_code, human_message, next_actions, detail },
null,
2,
),
},
],
isError: true,
};
}
/**
* 成功 response 格式化
*/
export function successResponse(
data: unknown,
hints?: string[],
): {
content: { type: "text"; text: string }[];
} {
return {
content: [
{
type: "text",
text: JSON.stringify(
{ ok: true, data, ...(hints ? { hints } : {}) },
null,
2,
),
},
],
};
}
+13
View File
@@ -0,0 +1,13 @@
import { Env } from "../types.js";
/**
* Wrapper around env.KBDB.fetch that automatically injects
* the KBDB_INTERNAL_TOKEN Authorization header.
*/
export function kbdbFetch(env: Env, path: string, init?: RequestInit): Promise<Response> {
const headers = new Headers((init?.headers as HeadersInit) || {});
if (env.KBDB_INTERNAL_TOKEN) {
headers.set("Authorization", `Bearer ${env.KBDB_INTERNAL_TOKEN}`);
}
return env.KBDB.fetch(`http://kbdb${path}`, { ...init, headers });
}