import crypto from "node:crypto"; import fs from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); const planPath = path.join(root, "docs/BLENDER_WEB_PARITY_TASK_PLAN_V2.json"); const outputDir = path.join(root, "tests/golden/WBV2"); const catalogPath = path.join(outputDir, "task-catalog.jsonl"); const indexPath = path.join(outputDir, "task-index.json"); const planBytes = fs.readFileSync(planPath); const plan = JSON.parse(planBytes); const sha256 = (bytes) => crypto.createHash("sha256").update(bytes).digest("hex"); const relative = (file) => path.relative(root, file).replaceAll(path.sep, "/"); const active = plan.tasks.filter((task) => task.ready === true && task.status === "in_progress"); if (active.length !== 1) throw new Error(`V2 plan must have exactly one ready in_progress task; found ${active.length}`); const lines = []; const entries = {}; let offset = 0; for (let index = 0; index < plan.tasks.length; index += 1) { const task = plan.tasks[index]; const compact = { id: task.id, gapId: task.parityId ?? `workflow:${task.title}`, ownerFamily: task.owner, sourceTask: task.phase, state: task.status === "done" ? "completed" : task.ready === true ? "active" : "pending", targetImplementationClass: task.implementationClass, exitCriteria: task.acceptance, }; const line = `${JSON.stringify(compact)}\n`; const length = Buffer.byteLength(line); lines.push(line); entries[task.id] = { line: index, offset, length, previous: task.dependsOn.at(-1) ?? null, next: plan.tasks[index + 1]?.id ?? null, }; offset += length; } fs.mkdirSync(outputDir, { recursive: true }); const catalogBytes = Buffer.from(lines.join("")); fs.writeFileSync(catalogPath, catalogBytes); const index = { schemaVersion: 1, operation: "BLENDER_WEB_CAPABILITY_TASK_INDEX", source: { path: relative(planPath), sha256: sha256(planBytes) }, catalog: { path: relative(catalogPath), sha256: sha256(catalogBytes) }, taskCount: plan.tasks.length, activeTask: active[0].id, entries, }; fs.writeFileSync(indexPath, `${JSON.stringify(index)}\n`); process.stdout.write(`v2-task-index-generated tasks=${plan.tasks.length} active=${index.activeTask} output=${relative(indexPath)}\n`);