/** * 用最新金样本规则重算已有 manual-selection-*.json * 用法:npx tsx scripts/reprocess-manual-interactions-gold.ts .rpa/address-event-compare/99-ff22eee0 */ import { readFileSync, writeFileSync, existsSync } from "node:fs"; import { join } from "node:path"; import { pickSelectionGoldInteractions } from "@/workers/rpa/selection-trace"; const runDir = process.argv[2]; if (!runDir) { console.error("用法: npx tsx scripts/reprocess-manual-interactions-gold.ts "); process.exit(1); } function loadJson(path: string): T | null { if (!existsSync(path)) { return null; } return JSON.parse(readFileSync(path, "utf8")) as T; } type BundleFile = { interactions: { clicks: unknown[]; keys: unknown[] }; gold?: unknown; }; for (const side of ["pickup", "delivery"] as const) { const path = join(runDir, `manual-selection-${side}.json`); const data = loadJson(path); if (!data?.interactions) { console.warn(`跳过 ${path}`); continue; } const gold = pickSelectionGoldInteractions( data.interactions as Parameters[0], ); writeFileSync( path, JSON.stringify({ ...data, gold }, null, 2), "utf8", ); console.log( `[reprocess] ${side} selectionClicks=${gold.selectionClicks.length} selectionKeys=${gold.selectionKeys.length}`, ); if (gold.selectionClicks.length > 0) { const last = gold.selectionClicks[gold.selectionClicks.length - 1]!; console.log(`[reprocess] ${side} last-click`, last.target); } } const pickup = loadJson(join(runDir, "manual-selection-pickup.json")); const delivery = loadJson(join(runDir, "manual-selection-delivery.json")); if (pickup?.interactions && delivery?.interactions) { writeFileSync( join(runDir, "manual-interactions-gold.json"), JSON.stringify( { pairId: "99", reprocessedAt: new Date().toISOString(), pickup: pickSelectionGoldInteractions( pickup.interactions as Parameters[0], ), delivery: pickSelectionGoldInteractions( delivery.interactions as Parameters[0], ), }, null, 2, ), "utf8", ); console.log(`[reprocess] wrote ${join(runDir, "manual-interactions-gold.json")}`); }