Files
Arcrun/mcp/src/lib/cypher-client.ts
T
uncle6me-web 3e65e22775 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>
2026-06-06 15:45:35 +08:00

102 lines
2.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 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,
),
},
],
};
}