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:
@@ -12,9 +12,11 @@
|
||||
|
||||
import chalk from 'chalk';
|
||||
import { loadConfig } from '../lib/config.js';
|
||||
import { CfAccountClient } from '../lib/cf-api.js';
|
||||
import {
|
||||
wranglerAvailable,
|
||||
downloadAndDeploy,
|
||||
REQUIRED_KV_NAMESPACES,
|
||||
type DeployContext,
|
||||
} from '../lib/deploy.js';
|
||||
|
||||
@@ -40,20 +42,50 @@ export async function cmdUpdate(): Promise<void> {
|
||||
|
||||
console.log(chalk.bold('\n acr update — 拉新 release 並重新部署\n'));
|
||||
|
||||
// 重新解析「全部」KV namespace id(冪等:已存在則重用),不只 config 存的兩個。
|
||||
// 壓測 §4.1.3:舊版 update 只注入 WEBHOOKS+CREDENTIALS_KV,其餘 6 個注入成空字串 →
|
||||
// 重部署反而可能弄壞需要 RECIPES/EXEC_CONTEXT/... 的 worker。改為與 init 同樣全建妥。
|
||||
const cf = new CfAccountClient(config.cloudflare_account_id, config.cf_api_token);
|
||||
const kvNamespaceIds: Record<string, string> = {};
|
||||
try {
|
||||
const existing = await cf.listKvNamespaces();
|
||||
for (const title of REQUIRED_KV_NAMESPACES) {
|
||||
kvNamespaceIds[title] = await cf.ensureKvNamespace(title, existing);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(chalk.yellow(`\n ✗ 解析 KV namespace 失敗:${e instanceof Error ? e.message : e}\n`));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const ctx: DeployContext = {
|
||||
accountId: config.cloudflare_account_id,
|
||||
apiToken: config.cf_api_token,
|
||||
workerSubdomain: extractSubdomain(config.cypher_executor_url),
|
||||
kvNamespaceIds: {
|
||||
WEBHOOKS: config.webhooks_kv_namespace_id ?? '',
|
||||
CREDENTIALS_KV: config.credentials_kv_namespace_id ?? '',
|
||||
},
|
||||
kvNamespaceIds,
|
||||
};
|
||||
|
||||
const result = await downloadAndDeploy(ctx);
|
||||
|
||||
if (result.implemented) {
|
||||
console.log(chalk.green('\n ✓ 更新完成\n'));
|
||||
console.log(chalk.green('\n ✓ 部署完成'));
|
||||
// 重跑 seed(薄殼:呼叫 API /init/seed;冪等,覆寫既有)。
|
||||
// 修壓測 §4.1.3「update 不做 seed,但 init 提示說 update 會重試 seed」的矛盾。
|
||||
const cypherUrl = config.cypher_executor_url
|
||||
?? result.cypherExecutorUrl
|
||||
?? (ctx.workerSubdomain ? `https://arcrun-cypher-executor.${ctx.workerSubdomain}.workers.dev` : '');
|
||||
if (cypherUrl) {
|
||||
process.stdout.write(chalk.gray(' → 重新 seed recipe(API + auth,由 API 灌入)...'));
|
||||
try {
|
||||
const res = await fetch(`${cypherUrl}/init/seed`, { method: 'POST' });
|
||||
const body = await res.json().catch(() => null) as { success?: boolean; message?: string } | null;
|
||||
console.log(res.ok && body?.success
|
||||
? chalk.green(` ✓ ${body.message ?? ''}`)
|
||||
: chalk.yellow(` ⚠ ${body?.message ?? `HTTP ${res.status}`}`));
|
||||
} catch (e) {
|
||||
console.log(chalk.yellow(` ⚠ seed 失敗(${e instanceof Error ? e.message : e})`));
|
||||
}
|
||||
}
|
||||
console.log('');
|
||||
} else {
|
||||
console.log(chalk.yellow(' ⚠ 更新尚未自動化:'));
|
||||
console.log(chalk.gray(' ' + result.message.split('\n').join('\n ')) + '\n');
|
||||
|
||||
Reference in New Issue
Block a user