/** * 从最新 flock-logged-in-*.js 摘抄 selector 线索,打印 checklist * 用法: npx tsx scripts/finalize-flock-logged-in-recording.ts */ import fs from "node:fs"; import path from "node:path"; const ROOT = process.cwd(); const DIR = path.join(ROOT, ".rpa", "recordings"); const PREFIX = "flock-logged-in-"; function latestRecording(): string | null { if (!fs.existsSync(DIR)) { return null; } const files = fs .readdirSync(DIR) .filter((f) => f.startsWith(PREFIX) && f.endsWith(".js")) .map((f) => ({ f, m: fs.statSync(path.join(DIR, f)).mtimeMs, })) .sort((a, b) => b.m - a.m); return files[0] ? path.join(DIR, files[0].f) : null; } function extractHints(src: string): string[] { const hints: string[] = []; const patterns = [ /page\.goto\(['"]([^'"]+)['"]\)/g, /getByRole\(([^)]+)\)/g, /getByLabel\(([^)]+)\)/g, /getByPlaceholder\(([^)]+)\)/g, /getByText\(([^)]+)\)/g, /getByTestId\(([^)]+)\)/g, /locator\(['"]([^'"]+)['"]\)/g, ]; for (const re of patterns) { let m: RegExpExecArray | null; while ((m = re.exec(src)) !== null) { hints.push(m[0].slice(0, 200)); } } return [...new Set(hints)]; } function main(): void { const file = latestRecording(); const storage = path.join(ROOT, ".rpa", "flock-logged-in-storage.json"); console.log("=== Flock 登录后录制 finalize ==="); if (!file) { console.error("未找到 .rpa/recordings/flock-logged-in-*.js"); console.error("请先: npm run record:flock -- --logged-in"); process.exit(1); } const src = fs.readFileSync(file, "utf8"); const hints = extractHints(src); console.log(`录制文件: ${file}`); console.log( `storage: ${storage} (${fs.existsSync(storage) ? "存在" : "缺失"})`, ); console.log(`线索条数: ${hints.length}`); console.log(""); console.log("请将下列线索回填 docs/rpa-flock-logged-in-sop.md 附录 A:"); for (const h of hints.slice(0, 80)) { console.log(` - ${h}`); } if (hints.length > 80) { console.log(` ... 另有 ${hints.length - 80} 条`); } } main();