UNPKG

@radcliffetech/symbolos-core

Version:

Core symbolic simulation and execution engine for Symbolos

152 lines (151 loc) โ€ข 6.12 kB
import { createWorldInstanceFromFrame, forkWorld, createWorld, runGen2WorldSimulation, runWorldPipeline, } from "../.."; import { SYMBOLOS_VERSION } from "../version"; import { conwayGame } from "../pipelines/conway-game-of-life"; import chalk from "chalk"; import { hideBin } from "yargs/helpers"; import { readJsonGz } from "../lib/file-utils"; import yargs from "yargs/yargs"; const getPipelineRegistry = () => ({ [conwayGame.id]: conwayGame, }); const defaultPipelineId = conwayGame.id; async function main() { console.log(chalk.gray(`๐Ÿชช Symbolos Core v${SYMBOLOS_VERSION}`)); const args = await yargs(hideBin(process.argv)) .option("fromFrame", { type: "string", describe: "Path to .world.json.gz frame to resume from", }) .option("fromArchive", { type: "string", describe: "Path to .world.json.gz archive to fork from", }) .option("pipelineId", { type: "string", default: defaultPipelineId, describe: "Pipeline ID", }) .option("verbose", { type: "boolean", default: false }) .option("params", { type: "array", describe: "Pipeline parameters as key=value pairs", }) .option("list", { type: "boolean", describe: "List available pipeline IDs and exit", }) .parse(); let pipelineId = args.pipelineId || defaultPipelineId; const pipelineRegistry = getPipelineRegistry(); if (args.list) { console.log("๐Ÿ“š Available pipelines:"); Object.entries(pipelineRegistry).forEach(([id, def]) => { console.log(`- ${id} โ€” ${def.label}`); }); process.exit(0); } const pipelineDefinition = pipelineRegistry[pipelineId]; if (!pipelineDefinition) { console.error(chalk.red(`โŒ Pipeline with ID "${pipelineId}" not found!`)); console.error(chalk.red(`Available pipelines: ${Object.keys(pipelineRegistry).join(", ")}`)); process.exit(1); } const framePath = args.fromFrame; const verbose = args.verbose; const cliParams = (args.params || []).reduce((acc, pair) => { const [key, value] = pair.split("="); acc[key] = isNaN(Number(value)) ? value : Number(value); return acc; }, {}); let world; const runId = crypto.randomUUID(); if (framePath) { console.log(chalk.cyan(`๐Ÿ“‚ Resuming world from: ${framePath}`)); const frame = await readJsonGz(framePath); world = createWorldInstanceFromFrame({ frame, pipelineId, runId }); pipelineId = world.pipelineId; console.log(chalk.green(`โœ… World restored at tick ${world.tick}, step ${world.step}`)); } else if (args.fromArchive) { console.log(chalk.cyan(`๐Ÿ“‚ Forking world from archive: ${args.fromArchive}`)); const archive = await readJsonGz(args.fromArchive); const baseWorld = createWorldInstanceFromFrame({ frame: archive, pipelineId: archive.pipelineId || defaultPipelineId, runId: archive.runId || crypto.randomUUID(), }); world = forkWorld(baseWorld, cliParams); pipelineId = world.pipelineId; console.log(chalk.green(`โœ… Forked world created with new runId: ${world.runId}`)); } else { console.log(chalk.yellow(`๐ŸŒฑ Starting new world for pipeline: ${pipelineId}`)); world = createWorld(pipelineId); console.log(chalk.green(`โœ… New world initialized with runId: ${world.runId}`)); } console.log(chalk.blue(`๐Ÿงช Using pipeline: ${pipelineId}`)); console.log(chalk.blueBright(`๐Ÿ”ง Pipeline Definition: ${pipelineDefinition.label}`)); const mergedParams = { ...(pipelineDefinition.args?.defaults || {}), ...cliParams, }; const pipelineArgs = { id: `user-args-${Date.now()}`, label: "User Arguments", type: "PipelineArgs", status: "valid", createdAt: new Date().toISOString(), params: mergedParams, }; const pipelineConfig = { verbose, }; if (Object.keys(mergedParams).length > 0) { console.log(chalk.gray("๐Ÿ“ฆ Final parameters:")); Object.entries(mergedParams).forEach(([key, value]) => { console.log(chalk.gray(` ${key}: ${value}`)); }); } console.log(chalk.blueBright(`๐Ÿš€ Running simulation...`)); console.log(chalk.gray(`๐Ÿง  Using simulator version: ${pipelineDefinition.version}`)); const result = pipelineDefinition.version === 3 ? await runWorldPipeline({ world, pipelineArgs, steps: pipelineDefinition.getSteps(pipelineArgs), }) : await runGen2WorldSimulation({ world, pipelineArgs, steps: pipelineDefinition.getSteps(pipelineArgs), simulatorConfig: pipelineConfig, }); if (!result || typeof result.tick !== "number") { console.error(chalk.red("โš ๏ธ Simulation failed or returned invalid result.")); process.exit(1); } console.log(chalk.green(`โœ… Simulation completed! Final tick: ${result.tick}`)); if (result.context && result.context._artifactsById) { const archive = Array.from(result.context._artifactsById.values()).find((o) => o.type === "WorldArchive"); const typedArchive = archive; if (typedArchive?.filePath) { console.log(chalk.gray(`๐Ÿ“„ Archive saved to: ${typedArchive.filePath}`)); } else { console.log(chalk.gray(`๐Ÿ“„ Archive complete, but file path not recorded.`)); } } // Summary output console.log(chalk.magenta("\n๐Ÿ“ Simulation Summary:")); console.log(`- Pipeline ID: ${pipelineId}`); console.log(`- Run ID: ${runId}`); console.log(`- Final Tick: ${result.tick}`); console.log(`- Parameters:`); Object.entries(mergedParams).forEach(([key, value]) => { console.log(` โ€ข ${key}: ${value}`); }); } main().catch((err) => { console.error(chalk.red("โŒ Error during simulation:"), err); process.exit(1); });