// Module shop system for managing dependencies and mods var io = use('io') var toml = use('toml') var json = use('json') var Shop = {} // Load shop.toml configuration Shop.load_config = function() { var shop_path = '.cell/shop.toml' if (!io.exists(shop_path)) { return null } var content = io.slurp(shop_path) return toml.parse(content) } // Save shop.toml configuration Shop.save_config = function(config) { // Simple TOML writer for our needs var lines = [] // Top-level strings if (config.module) lines.push('module = "' + config.module + '"') if (config.engine) lines.push('engine = "' + config.engine + '"') if (config.entrypoint) lines.push('entrypoint = "' + config.entrypoint + '"') // Dependencies section if (config.dependencies && Object.keys(config.dependencies).length > 0) { lines.push('') lines.push('[dependencies]') for (var key in config.dependencies) { lines.push(key + ' = "' + config.dependencies[key] + '"') } } // Aliases section if (config.aliases && Object.keys(config.aliases).length > 0) { lines.push('') lines.push('[aliases]') for (var key in config.aliases) { lines.push(key + ' = "' + config.aliases[key] + '"') } } // Replace section if (config.replace && Object.keys(config.replace).length > 0) { lines.push('') lines.push('[replace]') for (var key in config.replace) { lines.push('"' + key + '" = "' + config.replace[key] + '"') } } // Patches section if (config.patches && Object.keys(config.patches).length > 0) { lines.push('') lines.push('[patches]') for (var key in config.patches) { lines.push(key + ' = "' + config.patches[key] + '"') } } // Mods section if (config.mods && config.mods.enabled && config.mods.enabled.length > 0) { lines.push('') lines.push('[mods]') lines.push('enabled = [') for (var i = 0; i < config.mods.enabled.length; i++) { lines.push(' "' + config.mods.enabled[i] + '",') } lines.push(']') } io.slurpwrite('.cell/shop.toml', lines.join('\n')) } // Initialize .cell directory structure Shop.init = function() { if (!io.exists('.cell')) { io.mkdir('.cell') } if (!io.exists('.cell/modules')) { io.mkdir('.cell/modules') } if (!io.exists('.cell/build')) { io.mkdir('.cell/build') } if (!io.exists('.cell/patches')) { io.mkdir('.cell/patches') } if (!io.exists('.cell/shop.toml')) { var default_config = { module: "my-game", engine: "mist/prosperon@v0.9.3", entrypoint: "main.js", dependencies: {}, aliases: {}, replace: {}, patches: {}, mods: { enabled: [] } } Shop.save_config(default_config) } if (!io.exists('.cell/lock.toml')) { io.slurpwrite('.cell/lock.toml', '# Lock file for module integrity\n') } return true } // Mount modules according to the specification Shop.mount = function() { var config = Shop.load_config() if (!config) { log.error("No shop.toml found") return false } // 1. Mount mods first (highest priority, prepend=1) if (config.mods && config.mods.enabled) { for (var i = 0; i < config.mods.enabled.length; i++) { var mod_path = config.mods.enabled[i] if (io.exists(mod_path)) { io.mount(mod_path, "/", true) // prepend=true log.console("Mounted mod: " + mod_path) } } } // 2. Self is already mounted (project root) // This happens in prosperon.c // 3. Mount aliases (dependencies) if (config.dependencies) { for (var alias in config.dependencies) { var version = config.dependencies[alias] var parsed = Shop.parse_locator(version) var module_name = alias if (parsed && parsed.version) { module_name = alias + '@' + parsed.version } // Check if replaced with local path var mount_path = '.cell/modules/' + module_name if (config.replace && config.replace[version]) { mount_path = config.replace[version] } // Try compiled version first var compiled_path = '.cell/build/' + module_name if (io.exists(compiled_path)) { io.mount(compiled_path, alias, false) // Mount at alias name log.console("Mounted compiled: " + alias + " at /" + alias + " from " + compiled_path) } else if (io.exists(mount_path)) { io.mount(mount_path, alias, false) // Mount at alias name log.console("Mounted source: " + alias + " at /" + alias + " from " + mount_path) } // Also handle short aliases if (config.aliases) { for (var short_alias in config.aliases) { if (config.aliases[short_alias] === alias) { if (io.exists(compiled_path)) { io.mount(compiled_path, short_alias, false) log.console("Mounted alias: " + short_alias + " -> " + alias) } else if (io.exists(mount_path)) { io.mount(mount_path, short_alias, false) log.console("Mounted alias: " + short_alias + " -> " + alias) } } } } } } // 4. Mount compiled modules directory if (io.exists('.cell/build')) { io.mount('.cell/build', "modules", false) log.console("Mounted compiled modules at /modules") } // 5. Mount source modules directory if (io.exists('.cell/modules')) { io.mount('.cell/modules', "modules-src", false) log.console("Mounted source modules at /modules-src") } // 6. Mount core if available if (io.exists('.cell/modules/core')) { io.mount('.cell/modules/core', "core", false) log.console("Mounted core at /core") } // 6. Core is already mounted in prosperon.c return true } // Parse module locator (e.g., "git.world/jj/mod@v0.6.3") Shop.parse_locator = function(locator) { var parts = locator.split('@') if (parts.length !== 2) { return null } return { path: parts[0], version: parts[1], name: parts[0].split('/').pop() } } // Add a dependency Shop.add_dependency = function(alias, locator) { var config = Shop.load_config() if (!config) { log.error("No shop.toml found") return false } if (!config.dependencies) { config.dependencies = {} } config.dependencies[alias] = locator Shop.save_config(config) return true } // Get the module directory for a given alias Shop.get_module_dir = function(alias) { var config = Shop.load_config() if (!config || !config.dependencies || !config.dependencies[alias]) { return null } var version = config.dependencies[alias] var module_name = alias + '@' + version.split('@')[1] // Check if replaced if (config.replace && config.replace[version]) { return config.replace[version] } return '.cell/modules/' + module_name } // Compile a module Shop.compile_module = function(alias) { var module_dir = Shop.get_module_dir(alias) if (!module_dir) { log.error("Module not found: " + alias) return false } // TODO: Implement actual compilation // For now, just copy .js files to .cell/build with .o extension log.console("Would compile module: " + alias + " from " + module_dir) return true } // Build all modules Shop.build = function() { var config = Shop.load_config() if (!config || !config.dependencies) { return true } for (var alias in config.dependencies) { Shop.compile_module(alias) } return true } return Shop