import { cp, mkdir, rm, writeFile } from 'node:fs/promises'; import path from 'node:path'; import { spawnSync } from 'node:child_process'; import process from 'node:process'; const variant = process.argv[2]; if (variant !== 'engine' && variant !== 'ops' && variant !== 'player') { throw new Error('Usage: node scripts/build-learning-artifact.mjs [output-directory]'); } const explicitOutput = process.argv[3]; if (explicitOutput && variant !== 'player') { throw new Error('An explicit output directory is only supported for the player artifact'); } const root = process.cwd(); const role = variant === 'engine' ? 'server' : variant === 'ops' ? 'ops' : 'learner'; const basePath = variant === 'ops' ? '/learning-ops' : ''; const inheritedNodeOptions = process.env.NODE_OPTIONS?.trim() || ''; const env = { ...process.env, // The webpack graph for the complete Stage, editor, runtime and Ops surface // exceeds Node's default ~4 GiB heap. Keep CI, local artifacts and Docker // builds on the same explicit budget instead of relying on host defaults. NODE_OPTIONS: `${inheritedNodeOptions} --max-old-space-size=8192`.trim(), OPENMAIC_DEPLOYMENT_ROLE: role, NEXT_PUBLIC_OPENMAIC_DEPLOYMENT_ROLE: role, OPENMAIC_BASE_PATH: basePath, }; function run(script, args = []) { const result = spawnSync(process.execPath, [script, ...args], { cwd: root, env, stdio: 'inherit', }); if (result.status !== 0) process.exit(result.status ?? 1); } run(path.join(root, 'scripts/assert-vendor-maic-importer.mjs')); // Next 16's default Turbopack build can stall indefinitely on this large // workspace after allocating its graph. The production Docker build and these // reproducible artifacts use the mature webpack path explicitly. run(path.join(root, 'node_modules/next/dist/bin/next'), ['build', '--webpack']); if (variant === 'player') { run( path.join(root, 'scripts/build-makelore-player-artifact.mjs'), explicitOutput ? [path.resolve(explicitOutput)] : [], ); console.log('Learning player build completed from a fresh learner-role Next output.'); process.exit(0); } const target = path.join(root, 'dist', `learning-${variant}`); await rm(target, { recursive: true, force: true }); await mkdir(path.join(target, '.next'), { recursive: true }); await cp(path.join(root, '.next', 'standalone'), target, { recursive: true }); await cp(path.join(root, '.next', 'static'), path.join(target, '.next', 'static'), { recursive: true, }); await cp(path.join(root, 'public'), path.join(target, 'public'), { recursive: true }); await writeFile( path.join(target, 'learning-artifact.json'), `${JSON.stringify( { schemaVersion: 1, variant, role, basePath, start: 'node server.js', port: 3000, dataDirectory: '/app/data', }, null, 2, )}\n`, ); console.log(`Learning ${variant} standalone artifact: ${target}`);