Files
Arcrun/registry/scripts/backfill-index.mjs
T
uncle6me-web 922a57fe34 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>
2026-06-03 15:52:38 +08:00

122 lines
3.7 KiB
JavaScript
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.
#!/usr/bin/env node
// Backfill component metadata 進 registry index
// SDD: matrix/arcrun/.agents/specs/component-registry-canon/design.md Phase 1
//
// 用法:
// node scripts/backfill-index.mjs --dry-run # 看會送什麼
// node scripts/backfill-index.mjs # 真的灌
//
// 流程:
// 1. 掃 ../components/*/component.contract.yaml
// 2. 解析 YAML(用 zero-dep 簡易 parsercontract 是 well-formed YAML
// 3. 對每個 contract POST registry.arcrun.dev/components/index-only
// 4. 印 success / already_indexed / fail 統計
import { readdirSync, readFileSync, statSync } from 'node:fs';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const COMPONENTS_DIR = join(__dirname, '..', 'components');
const REGISTRY_URL = process.env.REGISTRY_URL ?? 'https://registry.arcrun.dev';
const DRY_RUN = process.argv.includes('--dry-run');
// YAML 是 well-formed contract.yaml,用 js-yaml 解析最穩
async function parseYaml(text) {
const { load } = await import('js-yaml');
return load(text);
}
function listComponents() {
return readdirSync(COMPONENTS_DIR)
.filter((name) => {
const p = join(COMPONENTS_DIR, name);
return statSync(p).isDirectory();
})
.sort();
}
async function readContract(name) {
const path = join(COMPONENTS_DIR, name, 'component.contract.yaml');
const text = readFileSync(path, 'utf-8');
return parseYaml(text);
}
async function postIndexOnly(contract) {
const res = await fetch(`${REGISTRY_URL}/components/index-only`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ contract }),
});
const body = await res.text();
let parsed;
try {
parsed = JSON.parse(body);
} catch {
parsed = { raw: body };
}
return { status: res.status, body: parsed };
}
async function main() {
console.log('=== arcrun Component Registry Backfill ===');
console.log(`Registry: ${REGISTRY_URL}`);
console.log(`Mode: ${DRY_RUN ? 'DRY RUN' : 'LIVE'}`);
console.log();
const names = listComponents();
console.log(`Found ${names.length} components in ${COMPONENTS_DIR}`);
console.log();
const stats = { created: 0, already: 0, fail: 0 };
for (const name of names) {
let contract;
try {
contract = await readContract(name);
} catch (e) {
console.log(` ✗ ${name.padEnd(28)} READ FAIL: ${e.message}`);
stats.fail++;
continue;
}
const cid = contract.canonical_id ?? '(no canonical_id)';
const ver = contract.version ?? '(no version)';
if (DRY_RUN) {
console.log(` → ${name.padEnd(28)} ${cid} ${ver}`);
continue;
}
try {
const { status, body } = await postIndexOnly(contract);
if (status === 200 && body.already_indexed) {
console.log(` = ${name.padEnd(28)} ${cid} ${ver} [already]`);
stats.already++;
} else if (status === 201) {
console.log(` ✓ ${name.padEnd(28)} ${cid} ${ver} [${body.component_hash_id}]`);
stats.created++;
} else {
console.log(` ✗ ${name.padEnd(28)} ${cid} ${ver} HTTP ${status}: ${JSON.stringify(body).slice(0, 200)}`);
stats.fail++;
}
} catch (e) {
console.log(` ✗ ${name.padEnd(28)} POST FAIL: ${e.message}`);
stats.fail++;
}
}
console.log();
console.log('=== Summary ===');
console.log(`Created: ${stats.created}`);
console.log(`Already indexed: ${stats.already}`);
console.log(`Failed: ${stats.fail}`);
process.exit(stats.fail > 0 ? 1 : 0);
}
main().catch((e) => {
console.error('Fatal:', e);
process.exit(1);
});