/** * seed-api-recipes.ts * * 將現役 API recipe 種子上傳至目標 cypher-executor(prod 或 self-host)。 * 種子資料的單一來源在 CLI 端(cli/src/lib/api-recipe-seeds.ts),此腳本 import 它, * 避免兩份種子定義漂移。 * * 執行: * npx tsx scripts/seed-api-recipes.ts * * 環境變數: * ARCRUN_API_URL - 目標 cypher-executor,預設 https://cypher.arcrun.dev * ARCRUN_API_KEY - X-Arcrun-API-Key(POST /recipes 需要) * * 注意:API recipe 帶 endpoint(資料去向)→ POST /recipes 會要 exposure_consent * (data-exfil-warning)。seed 是平台預建、非用戶 push,腳本帶種子層級的 consent。 * * 對應 SDD:.agents/specs/arcrun/sdk-and-website/self-hosted-init.md §5 */ import { API_RECIPE_SEEDS } from '../../cli/src/lib/api-recipe-seeds.js'; const BASE_URL = process.env.ARCRUN_API_URL ?? 'https://cypher.arcrun.dev'; const API_KEY = process.env.ARCRUN_API_KEY ?? ''; async function main() { console.log(`\n Seeding ${API_RECIPE_SEEDS.length} API recipes → ${BASE_URL}\n`); let ok = 0; let fail = 0; for (const recipe of API_RECIPE_SEEDS) { process.stdout.write(` ${recipe.canonical_id.padEnd(24)} `); try { const res = await fetch(`${BASE_URL}/recipes`, { method: 'POST', headers: { 'Content-Type': 'application/json', ...(API_KEY ? { 'X-Arcrun-API-Key': API_KEY } : {}), }, body: JSON.stringify({ canonical_id: recipe.canonical_id, display_name: recipe.display_name, description: recipe.description, endpoint: recipe.endpoint, method: recipe.method, auth_service: recipe.auth_service, // 種子層級的暴露同意:平台預建 recipe,非用戶互動 push。 // 格式須符合 cypher-executor ExposureConsent(confirmed_by_human + understood + confirmed_at)。 // 誠實標明來源是 seed,軌跡可審(mindset §7:機制價值是歸責+可審,非防偽)。 exposure_consent: { confirmed_by_human: true, understood: `platform seed recipe (api-recipe-seeds.ts): ${recipe.canonical_id} → ${recipe.endpoint}`, confirmed_at: new Date().toISOString(), }, }), }); if (res.ok) { console.log('✓'); ok++; } else { const err = await res.text().catch(() => ''); console.log(`✗ HTTP ${res.status}: ${err.slice(0, 120)}`); fail++; } } catch (e) { console.log(`✗ ${e instanceof Error ? e.message : String(e)}`); fail++; } } console.log(`\n 完成:${ok} 成功,${fail} 失敗\n`); if (fail > 0) process.exit(1); } main();