#!/usr/bin/env node import { spawn } from "node:child_process"; import { access, readFile } from "node:fs/promises"; import path from "node:path"; import { fileURLToPath } from "node:url"; const projectRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); const source = JSON.parse(await readFile( path.join(projectRoot, "dungeon-pipeline", "epoch-five-player-instances.json"), "utf8", )); const force = process.argv.includes("--force"); const requested = new Set(process.argv.slice(2).filter((argument) => argument !== "--force")); const dungeons = source.dungeons.filter((dungeon) => ( !requested.size || requested.has(dungeon.slug) )); const exists = async (file) => { try { await access(file); return true; } catch { return false; } }; function run(script, argumentsList) { return new Promise((resolve, reject) => { const child = spawn(process.execPath, [script, ...argumentsList], { cwd: projectRoot, env: process.env, stdio: "inherit", windowsHide: true, }); child.once("error", reject); child.once("exit", (code) => ( code === 0 ? resolve() : reject(new Error(`${path.basename(script)} ${argumentsList.join(" ")} exited ${code}.`)) )); }); } if (!dungeons.length) throw new Error("No requested Epoch dungeon slugs were found."); if (!process.env[source.source.rootEnvironmentVariable] && !process.env.EPOCH_CLIENT_ROOT) { throw new Error(`${source.source.rootEnvironmentVariable} must point to the installed Epoch client.`); } if (!process.env.WOW_SERVER_DATA) { process.env.WOW_SERVER_DATA = path.join(projectRoot, "..", "HealerMan-Storage", "pipeline-work", "dungeons", "server-data"); } const discoverCli = path.join(projectRoot, "scripts", "dungeon-pipeline", "discover-all.mjs"); const dungeonCli = path.join(projectRoot, "scripts", "dungeon-pipeline", "cli.mjs"); const packageCli = path.join( projectRoot, "scripts", "dungeon-pipeline", "package-epoch-creatures.mjs", ); const reports = []; for (const dungeon of dungeons) { const resultFile = path.join( projectRoot, "dungeon-pipeline", "work", dungeon.slug, "creature-source", "automation-result.json", ); if (!force && await exists(resultFile)) { reports.push({ slug: dungeon.slug, status: "already-exported" }); continue; } try { await run(discoverCli, [dungeon.slug]); await run(dungeonCli, ["creatures", dungeon.slug]); reports.push({ slug: dungeon.slug, status: "green" }); } catch (error) { reports.push({ slug: dungeon.slug, status: "error", error: error instanceof Error ? error.message : String(error), }); } } await run(packageCli, []); const failed = reports.filter((report) => report.status === "error"); console.log(JSON.stringify({ status: failed.length ? "error" : "green", dungeons: reports.length, exported: reports.filter((report) => report.status === "green").length, skipped: reports.filter((report) => report.status === "already-exported").length, failed, reports, }, null, 2)); if (failed.length) process.exitCode = 1;