// cell config - Manage system and actor configurations var toml = use('toml') var pkg = use('package') function print_help() { log.console("Usage: cell config [options]") log.console("") log.console("Commands:") log.console(" get Get a configuration value") log.console(" set Set a configuration value") log.console(" list List all configurations") log.console(" actor get Get actor-specific config") log.console(" actor set Set actor-specific config") log.console(" actor list List actor configurations") log.console("") log.console("Examples:") log.console(" cell config get system.ar_timer") log.console(" cell config set system.net_service 0.2") log.console(" cell config actor prosperon/_sdl_video set resolution 1920x1080") log.console(" cell config actor extramath/spline set precision high") log.console("") log.console("System keys:") log.console(" system.ar_timer - Seconds before idle actor reclamation") log.console(" system.actor_memory - MB of memory an actor can use (0=unbounded)") log.console(" system.net_service - Seconds per network service pull") log.console(" system.reply_timeout - Seconds to hold callback for replies (0=unbounded)") log.console(" system.actor_max - Max number of simultaneous actors") log.console(" system.stack_max - MB of memory each actor's stack can grow to") } // Parse a dot-notation key into path segments function parse_key(key) { return array(key, '.') } // Get a value from nested object using path function get_nested(obj, path) { var current = obj arrfor(path, function(segment) { if (is_null(current) || !is_object(current)) return null current = current[segment] }) return current } // Set a value in nested object using path function set_nested(obj, path, value) { var current = obj for (var i = 0; i < length(path) - 1; i++) { var segment = path[i] if (is_null(current[segment]) || !is_object(current[segment])) { current[segment] = {} } current = current[segment] } current[path[length(path) - 1]] = value } // Parse value string into appropriate type function parse_value(str) { // Boolean if (str == 'true') return true if (str == 'false') return false // Number (including underscores) var num_str = replace(str, /_/g, '') if (/^-?\d+$/.test(num_str)) return parseInt(num_str) if (/^-?\d*\.\d+$/.test(num_str)) return parseFloat(num_str) // String return str } // Format value for display function format_value(val) { if (is_text(val)) return '"' + val + '"' if (is_number(val) && val >= 1000) { // Add underscores to large numbers return replace(val.toString(), /\B(?=(\d{3})+(?!\d))/g, '_') } return text(val) } // Print configuration tree recursively function print_config(obj, prefix = '') { arrfor(array(obj), function(key) { var val = obj[key] var full_key = prefix ? prefix + '.' + key : key if (is_object(val)) print_config(val, full_key) else log.console(full_key + ' = ' + format_value(val)) }) } // Main command handling if (length(args) == 0) { print_help() $stop() return } var config = pkg.load_config() if (!config) { log.error("Failed to load cell.toml") $stop() return } var command = args[0] switch (command) { case 'help': case '-h': case '--help': print_help() break case 'list': log.console("# Cell Configuration") log.console("") print_config(config) break case 'get': if (length(args) < 2) { log.error("Usage: cell config get ") $stop() return } var key = args[1] var path = parse_key(key) var value = get_nested(config, path) if (value == null) { log.error("Key not found: " + key) } else if (isa(value, object)) { // Print all nested values print_config(value, key) } else { log.console(key + ' = ' + format_value(value)) } break case 'set': if (length(args) < 3) { log.error("Usage: cell config set ") $stop() return } var key = args[1] var value_str = args[2] var path = parse_key(key) var value = parse_value(value_str) // Validate system keys if (path[0] == 'system') { var valid_system_keys = [ 'ar_timer', 'actor_memory', 'net_service', 'reply_timeout', 'actor_max', 'stack_max' ] if (find(valid_system_keys, path[1]) == null) { log.error("Invalid system key. Valid keys: " + text(valid_system_keys, ', ')) $stop() return } } set_nested(config, path, value) pkg.save_config(config) log.console("Set " + key + " = " + format_value(value)) break case 'actor': // Handle actor-specific configuration if (length(args) < 3) { log.error("Usage: cell config actor [options]") $stop() return } var actor_name = args[1] var actor_cmd = args[2] // Initialize actors section if needed config.actors = config.actors || {} config.actors[actor_name] = config.actors[actor_name] || {} switch (actor_cmd) { case 'list': if (length(array(config.actors[actor_name])) == 0) { log.console("No configuration for actor: " + actor_name) } else { log.console("# Configuration for actor: " + actor_name) log.console("") print_config(config.actors[actor_name], 'actors.' + actor_name) } break case 'get': if (length(args) < 4) { log.error("Usage: cell config actor get ") $stop() return } var key = args[3] var path = parse_key(key) var value = get_nested(config.actors[actor_name], path) if (value == null) { log.error("Key not found for actor " + actor_name + ": " + key) } else { log.console('actors.' + actor_name + '.' + key + ' = ' + format_value(value)) } break case 'set': if (length(args) < 5) { log.error("Usage: cell config actor set ") $stop() return } var key = args[3] var value_str = args[4] var path = parse_key(key) var value = parse_value(value_str) set_nested(config.actors[actor_name], path, value) pkg.save_config(config) log.console("Set actors." + actor_name + "." + key + " = " + format_value(value)) break default: log.error("Unknown actor command: " + actor_cmd) log.console("Valid commands: list, get, set") } break default: log.error("Unknown command: " + command) print_help() } $stop()